From 3270a0338e864f563148076ab107e50387a5087b Mon Sep 17 00:00:00 2001 From: Christoph Enne Date: Sat, 10 Dec 2022 18:03:08 +0100 Subject: [PATCH] #27 better error handling and restructuring --- server/api/controllers/boards/import.js | 37 +++++++++++-------- server/api/helpers/boards/import-trello.js | 32 +++------------- server/api/helpers/boards/load-trello-file.js | 36 ++++++++++++++++++ 3 files changed, 62 insertions(+), 43 deletions(-) create mode 100644 server/api/helpers/boards/load-trello-file.js diff --git a/server/api/controllers/boards/import.js b/server/api/controllers/boards/import.js index 8740f263..60b63ef9 100755 --- a/server/api/controllers/boards/import.js +++ b/server/api/controllers/boards/import.js @@ -5,6 +5,9 @@ const Errors = { PROJECT_NOT_FOUND: { projectNotFound: 'Project not found', }, + TRELLO_FILE_INVALID: { + trelloFileInvalid: 'Trello File invalid', + }, }; module.exports = { @@ -28,42 +31,44 @@ module.exports = { projectNotFound: { responseType: 'notFound', }, + trelloFileInvalid: { + responseType: 'badRequest', + }, }, async fn(inputs) { const { currentUser } = this.req; + const project = await Project.findOne(inputs.projectId); + if (!project) { + throw Errors.PROJECT_NOT_FOUND; + } + + const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id); + if (!isProjectManager) { + throw Errors.PROJECT_NOT_FOUND; + } + const upload = util.promisify((options, callback) => this.req.file('file').upload(options, (error, files) => callback(error, files)), ); let files; + let trelloBoard; try { files = await upload({ saveAs: uuid(), maxBytes: null, }); + trelloBoard = await sails.helpers.boards.loadTrelloFile(files[0]); } catch (error) { - return exits.uploadError(error.message); // TODO: add error - } - - const project = await Project.findOne(inputs.projectId); - - if (!project) { - throw Errors.PROJECT_NOT_FOUND; - } - - const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id); - - if (!isProjectManager) { - throw Errors.PROJECT_NOT_FOUND; // Forbidden + throw Errors.TRELLO_FILE_INVALID; } const values = { ..._.pick(inputs, ['position', 'name']), type: 'kanban', }; - const { board, boardMembership } = await sails.helpers.boards.createOne( values, currentUser, @@ -71,10 +76,10 @@ module.exports = { this.req, ); - await sails.helpers.boards.importTrello(currentUser, board, files[0], this.req); + await sails.helpers.boards.importTrello(currentUser, board, trelloBoard, this.req); if (this.req.isSocket) { - sails.sockets.join(this.req, `board:${board.id}`); // TODO: only when subscription needed + sails.sockets.join(this.req, `board:${board.id}`); } return { diff --git a/server/api/helpers/boards/import-trello.js b/server/api/helpers/boards/import-trello.js index 2f25d431..5e8e3d57 100644 --- a/server/api/helpers/boards/import-trello.js +++ b/server/api/helpers/boards/import-trello.js @@ -1,18 +1,14 @@ -const fs = require('fs'); - async function importFromTrello(inputs) { - let trelloBoard; - - const getTrelloLists = () => trelloBoard.lists.filter((list) => !list.closed); + const getTrelloLists = () => inputs.trelloBoard.lists.filter((list) => !list.closed); const getTrelloCardsOfList = (listId) => - trelloBoard.cards.filter((l) => l.idList === listId && !l.closed); + inputs.trelloBoard.cards.filter((l) => l.idList === listId && !l.closed); const getAllTrelloCheckItemsOfCard = (cardId) => - trelloBoard.checklists + inputs.trelloBoard.checklists .filter((c) => c.idCard === cardId) .map((checklist) => checklist.checkItems) .flat(); const getTrelloCommentsOfCard = (cardId) => - trelloBoard.actions.filter( + inputs.trelloBoard.actions.filter( (action) => action.type === 'commentCard' && action.data && @@ -20,19 +16,6 @@ async function importFromTrello(inputs) { action.data.card.id === cardId, ); - const loadTrelloFile = async () => - new Promise((resolve, reject) => { - fs.readFile(inputs.file.fd, (err, data) => { - const exp = data && JSON.parse(data); - if (err) { - reject(err); - return; - } - trelloBoard = exp; - resolve(exp); - }); - }); - const importComments = async (trelloCard, plankaCard) => { const trelloComments = getTrelloCommentsOfCard(trelloCard.id); trelloComments.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); @@ -112,7 +95,6 @@ async function importFromTrello(inputs) { ); }; - await loadTrelloFile(); await importLists(); } @@ -126,7 +108,7 @@ module.exports = { type: 'ref', required: true, }, - file: { + trelloBoard: { type: 'json', required: true, }, @@ -136,12 +118,8 @@ module.exports = { }, async fn(inputs) { - // TODO some validations or something? check if the input file is ok? - await importFromTrello(inputs); - // TODO handle errors properly - return { board: inputs.board, }; diff --git a/server/api/helpers/boards/load-trello-file.js b/server/api/helpers/boards/load-trello-file.js new file mode 100644 index 00000000..039944ad --- /dev/null +++ b/server/api/helpers/boards/load-trello-file.js @@ -0,0 +1,36 @@ +const fs = require('fs'); + +module.exports = { + inputs: { + file: { + type: 'json', + required: true, + }, + }, + + async fn(inputs) { + const isValidTrelloFile = (content) => + content && + Array.isArray(content.lists) && + Array.isArray(content.cards) && + Array.isArray(content.checklists) && + Array.isArray(content.actions); + + return new Promise((resolve, reject) => { + fs.readFile(inputs.file.fd, (err, data) => { + try { + const exp = data && JSON.parse(data); + if (err) { + reject(err); + } else if (isValidTrelloFile(exp)) { + resolve(exp); + } else { + reject(new Error('Invalid Trello File')); + } + } catch (e) { + reject(new Error(e)); + } + }); + }); + }, +};