introduced new exception classes for structured error reporting

This commit is contained in:
zadam
2022-12-09 16:04:13 +01:00
parent eaf195e0c8
commit 342ae6e5e2
27 changed files with 123 additions and 64 deletions

View File

@@ -5,6 +5,8 @@ const log = require('../../services/log');
const attributeService = require('../../services/attributes');
const Attribute = require('../../becca/entities/attribute');
const becca = require("../../becca/becca");
const ValidationError = require("../../public/app/services/validation_error.js");
const NotFoundError = require("../../errors/not_found_error.js");
function getEffectiveNoteAttributes(req) {
const note = becca.getNote(req.params.noteId);
@@ -21,11 +23,11 @@ function updateNoteAttribute(req) {
attribute = becca.getAttribute(body.attributeId);
if (!attribute) {
return [404, `Attribute '${body.attributeId}' does not exist.`];
throw new NotFoundError(`Attribute '${body.attributeId}' does not exist.`);
}
if (attribute.noteId !== noteId) {
return [400, `Attribute '${body.attributeId}' is not owned by ${noteId}`];
throw new ValidationError(`Attribute '${body.attributeId}' is not owned by ${noteId}`);
}
if (body.type !== attribute.type
@@ -106,7 +108,7 @@ function deleteNoteAttribute(req) {
if (attribute) {
if (attribute.noteId !== noteId) {
return [400, `Attribute ${attributeId} is not owned by ${noteId}`];
throw new ValidationError(`Attribute ${attributeId} is not owned by ${noteId}`);
}
attribute.markAsDeleted();

View File

@@ -9,6 +9,8 @@ const becca = require('../../becca/becca');
const TaskContext = require('../../services/task_context');
const branchService = require("../../services/branches");
const log = require("../../services/log.js");
const ValidationError = require("../../public/app/services/validation_error.js");
const NotFoundError = require("../../errors/not_found_error.js");
/**
* Code in this file deals with moving and cloning branches. Relationship between note and parent note is unique
@@ -22,7 +24,7 @@ function moveBranchToParent(req) {
const branchToMove = becca.getBranch(branchId);
if (!parentBranch || !branchToMove) {
return [400, `One or both branches ${branchId}, ${parentBranchId} have not been found`];
throw new ValidationError(`One or both branches ${branchId}, ${parentBranchId} have not been found`);
}
return branchService.moveBranchToBranch(branchToMove, parentBranch, branchId);
@@ -35,11 +37,11 @@ function moveBranchBeforeNote(req) {
const beforeBranch = becca.getBranch(beforeBranchId);
if (!branchToMove) {
return [404, `Can't find branch ${branchId}`];
throw new NotFoundError(`Can't find branch '${branchId}'`);
}
if (!beforeBranch) {
return [404, `Can't find branch ${beforeBranchId}`];
throw new NotFoundError(`Can't find branch '${beforeBranchId}'`);
}
const validationResult = treeService.validateParentChild(beforeBranch.parentNoteId, branchToMove.noteId, branchId);
@@ -193,7 +195,7 @@ function deleteBranch(req) {
const branch = becca.getBranch(req.params.branchId);
if (!branch) {
return [404, `Branch ${req.params.branchId} not found`];
throw new NotFoundError(`Branch '${req.params.branchId}' not found`);
}
const taskContext = TaskContext.getInstance(req.query.taskId, 'delete-notes');

View File

@@ -6,6 +6,7 @@ const opmlExportService = require('../../services/export/opml');
const becca = require('../../becca/becca');
const TaskContext = require("../../services/task_context");
const log = require("../../services/log");
const NotFoundError = require("../../errors/not_found_error.js");
function exportBranch(req, res) {
const {branchId, type, format, version, taskId} = req.params;
@@ -34,11 +35,11 @@ function exportBranch(req, res) {
opmlExportService.exportToOpml(taskContext, branch, version, res);
}
else {
return [404, "Unrecognized export format " + format];
throw new NotFoundError(`Unrecognized export format '${format}'`);
}
}
catch (e) {
const message = "Export failed with following error: '" + e.message + "'. More details might be in the logs.";
const message = `Export failed with following error: '${e.message}'. More details might be in the logs.`;
taskContext.reportError(message);
log.error(message + e.stack);

View File

@@ -10,6 +10,7 @@ const { Readable } = require('stream');
const chokidar = require('chokidar');
const ws = require('../../services/ws');
const becca = require("../../becca/becca");
const NotFoundError = require("../../errors/not_found_error.js");
function updateFile(req) {
const {noteId} = req.params;
@@ -18,7 +19,7 @@ function updateFile(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} doesn't exist.`];
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
}
note.saveNoteRevision();
@@ -116,7 +117,7 @@ function saveToTmpDir(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404,`Note ${noteId} doesn't exist.`];
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
}
const tmpObj = tmp.fileSync({postfix: getFilename(note)});

View File

@@ -4,6 +4,8 @@ const imageService = require('../../services/image');
const becca = require('../../becca/becca');
const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR;
const fs = require('fs');
const ValidationError = require("../../public/app/services/validation_error.js");
const NotFoundError = require("../../errors/not_found_error.js");
function returnImage(req, res) {
const image = becca.getNote(req.params.noteId);
@@ -51,11 +53,11 @@ function uploadImage(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} doesn't exist.`];
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
}
if (!["image/png", "image/jpg", "image/jpeg", "image/gif", "image/webp", "image/svg+xml"].includes(file.mimetype)) {
return [400, "Unknown image type: " + file.mimetype];
throw new ValidationError(`Unknown image type: ${file.mimetype}`);
}
const {url} = imageService.saveImage(noteId, file.buffer, file.originalname, true, true);
@@ -73,7 +75,7 @@ function updateImage(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} doesn't exist.`];
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
}
if (!["image/png", "image/jpeg", "image/gif", "image/webp", "image/svg+xml"].includes(file.mimetype)) {

View File

@@ -10,6 +10,8 @@ const becca = require('../../becca/becca');
const beccaLoader = require('../../becca/becca_loader');
const log = require('../../services/log');
const TaskContext = require('../../services/task_context');
const ValidationError = require("../../public/app/services/validation_error.js");
const NotFoundError = require("../../errors/not_found_error.js");
async function importToBranch(req) {
const {parentNoteId} = req.params;
@@ -27,13 +29,13 @@ async function importToBranch(req) {
const file = req.file;
if (!file) {
return [400, "No file has been uploaded"];
throw new ValidationError("No file has been uploaded");
}
const parentNote = becca.getNote(parentNoteId);
if (!parentNote) {
return [404, `Note ${parentNoteId} doesn't exist.`];
throw new NotFoundError(`Note '${parentNoteId}' doesn't exist.`);
}
const extension = path.extname(file.originalname).toLowerCase();

View File

@@ -2,6 +2,7 @@
const becca = require("../../becca/becca");
const { JSDOM } = require("jsdom");
const NotFoundError = require("../../errors/not_found_error.js");
function buildDescendantCountMap() {
const noteIdToCountMap = {};
@@ -326,7 +327,7 @@ function getBacklinkCount(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, "Not found"];
throw new NotFoundError(`Note '${noteId}' not found`);
}
else {
return {
@@ -340,7 +341,7 @@ function getBacklinks(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} was not found`];
throw new NotFoundError(`Note '${noteId}' was not found`);
}
let backlinksWithExcerptCount = 0;

View File

@@ -9,13 +9,15 @@ const TaskContext = require('../../services/task_context');
const protectedSessionService = require('../../services/protected_session');
const fs = require('fs');
const becca = require("../../becca/becca");
const ValidationError = require("../../public/app/services/validation_error.js");
const NotFoundError = require("../../errors/not_found_error.js");
function getNote(req) {
const noteId = req.params.noteId;
const note = becca.getNote(noteId);
if (!note) {
return [404, "Note " + noteId + " has not been found."];
throw new NotFoundError(`Note '${noteId}' has not been found.`);
}
const pojo = note.getPojo();
@@ -197,11 +199,11 @@ function changeTitle(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note '${noteId}' has not been found`];
throw new NotFoundError(`Note '${noteId}' has not been found`);
}
if (!note.isContentAvailable()) {
return [400, `Note '${noteId}' is not available for change`];
throw new ValidationError(`Note '${noteId}' is not available for change`);
}
const noteTitleChanged = note.title !== title;
@@ -290,7 +292,7 @@ function uploadModifiedFile(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note '${noteId}' has not been found`];
throw new NotFoundError(`Note '${noteId}' has not been found`);
}
log.info(`Updating note '${noteId}' with content from ${filePath}`);
@@ -300,7 +302,7 @@ function uploadModifiedFile(req) {
const fileContent = fs.readFileSync(filePath);
if (!fileContent) {
return [400, `File ${fileContent} is empty`];
throw new ValidationError(`File '${fileContent}' is empty`);
}
note.setContent(fileContent);
@@ -311,11 +313,11 @@ function forceSaveNoteRevision(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} not found.`];
throw new NotFoundError(`Note '${noteId}' not found.`);
}
if (!note.isContentAvailable()) {
return [400, `Note revision of a protected note cannot be created outside of a protected session.`];
throw new ValidationError(`Note revision of a protected note cannot be created outside of a protected session.`);
}
note.saveNoteRevision();

View File

@@ -3,6 +3,7 @@
const optionService = require('../../services/options');
const log = require('../../services/log');
const searchService = require('../../services/search/services/search');
const ValidationError = require("../../public/app/services/validation_error.js");
// options allowed to be updated directly in options dialog
const ALLOWED_OPTIONS = new Set([
@@ -82,7 +83,7 @@ function updateOption(req) {
const {name, value} = req.params;
if (!update(name, value)) {
return [400, "not allowed option to change"];
throw new ValidationError("not allowed option to change");
}
}

View File

@@ -1,6 +1,7 @@
"use strict";
const passwordService = require('../../services/password');
const ValidationError = require("../../public/app/services/validation_error.js");
function changePassword(req) {
if (passwordService.isPasswordSet()) {
@@ -14,7 +15,7 @@ function changePassword(req) {
function resetPassword(req) {
// protection against accidental call (not a security measure)
if (req.query.really !== "yesIReallyWantToResetPasswordAndLoseAccessToMyProtectedNotes") {
return [400, "Incorrect password reset confirmation"];
throw new ValidationError("Incorrect password reset confirmation");
}
return passwordService.resetPassword();

View File

@@ -6,12 +6,14 @@ const searchService = require('../../services/search/services/search');
const bulkActionService = require("../../services/bulk_actions");
const cls = require("../../services/cls");
const {formatAttrForSearch} = require("../../services/attribute_formatter");
const ValidationError = require("../../public/app/services/validation_error.js");
const NotFoundError = require("../../errors/not_found_error.js");
function searchFromNote(req) {
const note = becca.getNote(req.params.noteId);
if (!note) {
return [404, `Note ${req.params.noteId} has not been found.`];
throw new NotFoundError(`Note '${req.params.noteId}' has not been found.`);
}
if (note.isDeleted) {
@@ -20,7 +22,7 @@ function searchFromNote(req) {
}
if (note.type !== 'search') {
return [400, `Note ${req.params.noteId} is not a search note.`]
throw new ValidationError(`Note '${req.params.noteId}' is not a search note.`);
}
return searchService.searchFromNote(note);
@@ -30,16 +32,16 @@ function searchAndExecute(req) {
const note = becca.getNote(req.params.noteId);
if (!note) {
return [404, `Note ${req.params.noteId} has not been found.`];
throw new NotFoundError(`Note '${req.params.noteId}' has not been found.`);
}
if (note.isDeleted) {
// this can be triggered from recent changes and it's harmless to return empty list rather than fail
// this can be triggered from recent changes, and it's harmless to return empty list rather than fail
return [];
}
if (note.type !== 'search') {
return [400, `Note ${req.params.noteId} is not a search note.`]
throw new ValidationError(`Note '${req.params.noteId}' is not a search note.`);
}
const {searchResultNoteIds} = searchService.searchFromNote(note);

View File

@@ -2,6 +2,7 @@
const similarityService = require('../../becca/similarity');
const becca = require("../../becca/becca");
const NotFoundError = require("../../errors/not_found_error.js");
async function getSimilarNotes(req) {
const noteId = req.params.noteId;
@@ -9,7 +10,7 @@ async function getSimilarNotes(req) {
const note = becca.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} not found.`];
throw new NotFoundError(`Note '${noteId}' not found.`);
}
return await similarityService.findSimilarNotes(noteId);

View File

@@ -2,6 +2,7 @@
const sql = require('../../services/sql');
const becca = require("../../becca/becca");
const NotFoundError = require("../../errors/not_found_error.js");
function getSchema() {
const tableNames = sql.getColumn(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
@@ -21,7 +22,7 @@ function execute(req) {
const note = becca.getNote(req.params.noteId);
if (!note) {
return [404, `Note ${req.params.noteId} was not found.`];
throw new NotFoundError(`Note '${req.params.noteId}' was not found.`);
}
const queries = note.getContent().split("\n---");

View File

@@ -1,5 +1,6 @@
const sql = require('../../services/sql');
const becca = require('../../becca/becca');
const NotFoundError = require("../../errors/not_found_error.js");
function getNoteSize(req) {
const {noteId} = req.params;
@@ -26,7 +27,7 @@ function getSubtreeSize(req) {
const note = becca.notes[noteId];
if (!note) {
return [404, `Note ${noteId} was not found.`];
throw new NotFoundError(`Note '${noteId}' was not found.`);
}
const subTreeNoteIds = note.getSubtreeNoteIds();

View File

@@ -2,6 +2,7 @@
const becca = require('../../becca/becca');
const log = require('../../services/log');
const NotFoundError = require("../../errors/not_found_error.js");
function getNotesAndBranchesAndAttributes(noteIds) {
noteIds = new Set(noteIds);
@@ -141,7 +142,7 @@ function getTree(req) {
}
if (!(subTreeNoteId in becca.notes)) {
return [404, `Note ${subTreeNoteId} not found in the cache`];
throw new NotFoundError(`Note '${subTreeNoteId}' not found in the cache`);
}
collect(becca.notes[subTreeNoteId]);