From af49ed346f51d01fac7b746e71b4bf138125dc7e Mon Sep 17 00:00:00 2001 From: Mert E Date: Wed, 20 Mar 2024 17:59:28 +0300 Subject: [PATCH] feat: errors v2 (#7916) * feat: NcBaseErrorv2 * feat: move existing errors to v2 (WIP) * feat: use functions instead of replace for templates * feat: use v2 for database errors * feat: experimental extraction for non-matched db errors * feat: improved error message formats * test: NcBaseErrorv2 * fix: move string casting to handler --- .../composables/useSharedFormViewStore.ts | 5 +- packages/nocodb-sdk/src/lib/globals.ts | 26 +- .../old-datas/old-datas.service.ts | 2 +- .../public-datas-export.controller.ts | 10 +- packages/nocodb/src/db/BaseModelSqlv2.ts | 94 ++---- packages/nocodb/src/db/conditionV2.ts | 2 +- .../src/db/generateLookupSelectQuery.ts | 4 +- packages/nocodb/src/db/sortV2.ts | 2 +- .../global-exception.filter.ts | 20 +- packages/nocodb/src/helpers/NcPluginMgrv2.ts | 6 +- packages/nocodb/src/helpers/PagedResponse.ts | 2 +- packages/nocodb/src/helpers/catchError.ts | 298 ++++++++++++++++-- packages/nocodb/src/helpers/getAst.ts | 2 +- .../extract-ids/extract-ids.middleware.ts | 2 +- packages/nocodb/src/models/Filter.ts | 2 +- packages/nocodb/src/models/Model.ts | 2 +- packages/nocodb/src/models/Source.ts | 2 +- packages/nocodb/src/models/User.ts | 6 +- packages/nocodb/src/modules/datas/helpers.ts | 7 +- .../jobs/jobs/export-import/export.service.ts | 6 +- .../jobs/jobs/export-import/import.service.ts | 11 +- .../src/services/api-docs/api-docs.service.ts | 4 +- .../services/base-users/base-users.service.ts | 8 +- packages/nocodb/src/services/bases.service.ts | 2 +- .../src/services/calendar-datas.service.ts | 18 +- .../nocodb/src/services/calendars.service.ts | 2 +- .../nocodb/src/services/columns.service.ts | 26 +- .../src/services/data-alias-nested.service.ts | 14 +- .../nocodb/src/services/data-table.service.ts | 39 +-- packages/nocodb/src/services/datas.service.ts | 31 +- packages/nocodb/src/services/forms.service.ts | 2 +- .../nocodb/src/services/galleries.service.ts | 2 +- packages/nocodb/src/services/grids.service.ts | 2 +- .../nocodb/src/services/kanbans.service.ts | 2 +- packages/nocodb/src/services/maps.service.ts | 2 +- .../services/model-visibilities.service.ts | 2 +- .../nocodb/src/services/org-users.service.ts | 4 +- .../src/services/public-datas.service.ts | 35 +- .../src/services/public-metas.service.ts | 7 +- .../src/services/shared-bases.service.ts | 8 +- .../nocodb/src/services/tables.service.ts | 2 +- packages/nocodb/src/services/views.service.ts | 10 +- .../tests/unit/rest/tests/newDataApis.test.ts | 58 ++-- .../tests/unit/rest/tests/tableRow.test.ts | 26 +- 44 files changed, 510 insertions(+), 307 deletions(-) diff --git a/packages/nc-gui/composables/useSharedFormViewStore.ts b/packages/nc-gui/composables/useSharedFormViewStore.ts index 0c37b4c726..9eb7a004c2 100644 --- a/packages/nc-gui/composables/useSharedFormViewStore.ts +++ b/packages/nc-gui/composables/useSharedFormViewStore.ts @@ -12,7 +12,7 @@ import type { StringOrNullType, TableType, } from 'nocodb-sdk' -import { ErrorMessages, RelationTypes, UITypes, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk' +import { RelationTypes, UITypes, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk' import { isString } from '@vue/shared' import { filterNullOrUndefinedObjectProperties } from '~/helpers/parsers/parserHelpers' import { @@ -178,7 +178,8 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share } catch (e: any) { if (e.response && e.response.status === 404) { notFound.value = true - } else if ((await extractSdkResponseErrorMsg(e)) === ErrorMessages.INVALID_SHARED_VIEW_PASSWORD) { + // TODO - handle invalidSharedViewPassword + } else if (await extractSdkResponseErrorMsg(e)) { passwordDlg.value = true if (password.value && password.value !== '') passwordError.value = 'Something went wrong. Please check your credentials.' diff --git a/packages/nocodb-sdk/src/lib/globals.ts b/packages/nocodb-sdk/src/lib/globals.ts index d08e7dead0..fd3ad311f3 100644 --- a/packages/nocodb-sdk/src/lib/globals.ts +++ b/packages/nocodb-sdk/src/lib/globals.ts @@ -28,11 +28,6 @@ export enum ExportTypes { CSV = 'csv', } -export enum ErrorMessages { - INVALID_SHARED_VIEW_PASSWORD = 'INVALID_SHARED_VIEW_PASSWORD', - NOT_IMPLEMENTED = 'NOT_IMPLEMENTED', -} - export enum AuditOperationTypes { COMMENT = 'COMMENT', DATA = 'DATA', @@ -129,6 +124,27 @@ export enum NcDataErrorCodes { NC_ERR_MM_MODEL_NOT_FOUND = 'NC_ERR_MM_MODEL_NOT_FOUND', } +export enum NcErrorType { + AUTHENTICATION_REQUIRED = 'AUTHENTICATION_REQUIRED', + API_TOKEN_NOT_ALLOWED = 'API_TOKEN_NOT_ALLOWED', + WORKSPACE_NOT_FOUND = 'WORKSPACE_NOT_FOUND', + BASE_NOT_FOUND = 'BASE_NOT_FOUND', + SOURCE_NOT_FOUND = 'SOURCE_NOT_FOUND', + TABLE_NOT_FOUND = 'TABLE_NOT_FOUND', + VIEW_NOT_FOUND = 'VIEW_NOT_FOUND', + FIELD_NOT_FOUND = 'FIELD_NOT_FOUND', + RECORD_NOT_FOUND = 'RECORD_NOT_FOUND', + ERROR_DUPLICATE_RECORD = 'ERROR_DUPLICATE_RECORD', + USER_NOT_FOUND = 'USER_NOT_FOUND', + INVALID_OFFSET_VALUE = 'INVALID_OFFSET_VALUE', + INVALID_LIMIT_VALUE = 'INVALID_LIMIT_VALUE', + INVALID_FILTER = 'INVALID_FILTER', + INVALID_SHARED_VIEW_PASSWORD = 'INVALID_SHARED_VIEW_PASSWORD', + NOT_IMPLEMENTED = 'NOT_IMPLEMENTED', + INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR', + DATABASE_ERROR = 'DATABASE_ERROR', +} + type Roles = OrgUserRoles | ProjectRoles | WorkspaceUserRoles; type RolesObj = Partial>; diff --git a/packages/nocodb/src/controllers/old-datas/old-datas.service.ts b/packages/nocodb/src/controllers/old-datas/old-datas.service.ts index c210179289..7cf7710aba 100644 --- a/packages/nocodb/src/controllers/old-datas/old-datas.service.ts +++ b/packages/nocodb/src/controllers/old-datas/old-datas.service.ts @@ -136,7 +136,7 @@ export class OldDatasService { titleOrId: req.params.viewName, fk_model_id: model.id, })); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(req.params.tableName); return { model, view }; } } diff --git a/packages/nocodb/src/controllers/public-datas-export.controller.ts b/packages/nocodb/src/controllers/public-datas-export.controller.ts index 75fe13444a..9f7b8ebe9e 100644 --- a/packages/nocodb/src/controllers/public-datas-export.controller.ts +++ b/packages/nocodb/src/controllers/public-datas-export.controller.ts @@ -6,7 +6,7 @@ import { Response, UseGuards, } from '@nestjs/common'; -import { ErrorMessages, isSystemColumn, ViewTypes } from 'nocodb-sdk'; +import { isSystemColumn, ViewTypes } from 'nocodb-sdk'; import * as XLSX from 'xlsx'; import { nocoExecute } from 'nc-help'; import papaparse from 'papaparse'; @@ -35,7 +35,7 @@ export class PublicDatasExportController { @Param('publicDataUuid') publicDataUuid: string, ) { const view = await View.getByUUID(publicDataUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(publicDataUuid); if ( view.type !== ViewTypes.GRID && view.type !== ViewTypes.KANBAN && @@ -45,7 +45,7 @@ export class PublicDatasExportController { NcError.notFound('Not found'); if (view.password && view.password !== req.headers?.['xc-password']) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + NcError.invalidSharedViewPassword(); } const model = await view.getModelWithInfo(); @@ -88,7 +88,7 @@ export class PublicDatasExportController { const view = await View.getByUUID(req.params.publicDataUuid); const fields = req.query.fields; - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(req.params.publicDataUuid); if ( view.type !== ViewTypes.GRID && view.type !== ViewTypes.KANBAN && @@ -98,7 +98,7 @@ export class PublicDatasExportController { NcError.notFound('Not found'); if (view.password && view.password !== req.headers?.['xc-password']) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + NcError.invalidSharedViewPassword(); } const model = await view.getModelWithInfo(); diff --git a/packages/nocodb/src/db/BaseModelSqlv2.ts b/packages/nocodb/src/db/BaseModelSqlv2.ts index 79767d67fd..ed998012e5 100644 --- a/packages/nocodb/src/db/BaseModelSqlv2.ts +++ b/packages/nocodb/src/db/BaseModelSqlv2.ts @@ -632,7 +632,7 @@ class BaseModelSqlv2 { args.column_name.split(',').map(async (col) => { let column = cols.find((c) => c.column_name === col || c.title === col); if (!column) { - throw NcError.notFound('Column not found'); + throw NcError.fieldNotFound(col); } // if qrCode or Barcode replace it with value column nd keep the alias @@ -851,7 +851,7 @@ class BaseModelSqlv2 { (c) => c.column_name === col || c.title === col, ); if (!column) { - throw NcError.notFound('Column not found'); + throw NcError.fieldNotFound(col); } // if qrCode or Barcode replace it with value column nd keep the alias @@ -3683,9 +3683,7 @@ class BaseModelSqlv2 { if (!pkValues) { // throw or skip if no pk provided if (throwExceptionIfNotExist) { - NcError.unprocessableEntity( - `Record with pk ${JSON.stringify(pkValues)} not found`, - ); + NcError.recordNotFound(JSON.stringify(pkValues)); } continue; } @@ -3696,9 +3694,7 @@ class BaseModelSqlv2 { if (!oldRecord) { // throw or skip if no record found if (throwExceptionIfNotExist) { - NcError.unprocessableEntity( - `Record with pk ${JSON.stringify(pkValues)} not found`, - ); + NcError.recordNotFound(JSON.stringify(pkValues)); } continue; } @@ -3853,9 +3849,7 @@ class BaseModelSqlv2 { if (!pkValues) { // throw or skip if no pk provided if (throwExceptionIfNotExist) { - NcError.unprocessableEntity( - `Record with pk ${JSON.stringify(pkValues)} not found`, - ); + NcError.recordNotFound(JSON.stringify(pkValues)); } continue; } @@ -3864,9 +3858,7 @@ class BaseModelSqlv2 { if (!deletedRecord) { // throw or skip if no record found if (throwExceptionIfNotExist) { - NcError.unprocessableEntity( - `Record with pk ${JSON.stringify(pkValues)} not found`, - ); + NcError.recordNotFound(JSON.stringify(pkValues)); } continue; } @@ -4430,7 +4422,7 @@ class BaseModelSqlv2 { !column || ![UITypes.LinkToAnotherRecord, UITypes.Links].includes(column.uidt) ) - NcError.notFound('Column not found'); + NcError.fieldNotFound(colId); const colOptions = await column.getColOptions(); @@ -4650,7 +4642,7 @@ class BaseModelSqlv2 { !column || ![UITypes.LinkToAnotherRecord, UITypes.Links].includes(column.uidt) ) - NcError.notFound('Column not found'); + NcError.fieldNotFound(colId); const colOptions = await column.getColOptions(); @@ -4818,9 +4810,9 @@ class BaseModelSqlv2 { .getColumns() .then((cols) => cols?.find((col) => col.id === args.groupColumnId)); - if (!column) NcError.notFound('Column not found'); + if (!column) NcError.fieldNotFound(args.groupColumnId); if (isVirtualCol(column)) - NcError.notImplemented('Grouping for virtual columns not implemented'); + NcError.notImplemented('Grouping for virtual columns'); // extract distinct group column values let groupingValues: Set; @@ -4980,9 +4972,9 @@ class BaseModelSqlv2 { .getColumns() .then((cols) => cols?.find((col) => col.id === args.groupColumnId)); - if (!column) NcError.notFound('Column not found'); + if (!column) NcError.fieldNotFound(args.groupColumnId); if (isVirtualCol(column)) - NcError.notImplemented('Grouping for virtual columns not implemented'); + NcError.notImplemented('Grouping for virtual columns'); const qb = this.dbDriver(this.tnPath) .count('*', { as: 'count' }) @@ -5594,8 +5586,7 @@ class BaseModelSqlv2 { const columns = await this.model.getColumns(); const column = columns.find((c) => c.id === colId); - if (!column || !isLinksOrLTAR(column)) - NcError.notFound(`Link column ${colId} not found`); + if (!column || !isLinksOrLTAR(column)) NcError.fieldNotFound(colId); const row = await this.readByPk( rowId, @@ -5606,7 +5597,7 @@ class BaseModelSqlv2 { // validate rowId if (!row) { - NcError.notFound(`Record with id '${rowId}' not found`); + NcError.recordNotFound(rowId); } if (!_childIds.length) return; @@ -5717,11 +5708,7 @@ class BaseModelSqlv2 { !childRows.find((r) => r[parentColumn.column_name] === id), ); - NcError.unprocessableEntity( - `Child record with id [${extractIdsString( - missingIds, - )}] not found`, - ); + NcError.recordNotFound(extractIds(missingIds)); } insertData = childRows @@ -5794,11 +5781,7 @@ class BaseModelSqlv2 { !childRows.find((r) => r[parentColumn.column_name] === id), ); - NcError.unprocessableEntity( - `Child record with id [${extractIdsString( - missingIds, - )}] not found`, - ); + NcError.recordNotFound(extractIds(missingIds)); } } const updateQb = this.dbDriver(childTn).update({ @@ -5852,12 +5835,7 @@ class BaseModelSqlv2 { }); if (!childRow) { - NcError.unprocessableEntity( - `Child record with id [${extractIdsString( - childIds, - true, - )}] not found`, - ); + NcError.recordNotFound(extractIds(childIds, true)); } } @@ -5913,8 +5891,7 @@ class BaseModelSqlv2 { const columns = await this.model.getColumns(); const column = columns.find((c) => c.id === colId); - if (!column || !isLinksOrLTAR(column)) - NcError.notFound(`Link column ${colId} not found`); + if (!column || !isLinksOrLTAR(column)) NcError.fieldNotFound(colId); const row = await this.readByPk( rowId, @@ -5925,7 +5902,7 @@ class BaseModelSqlv2 { // validate rowId if (!row) { - NcError.notFound(`Record with id '${rowId}' not found`); + NcError.recordNotFound(rowId); } if (!childIds.length) return; @@ -5999,11 +5976,7 @@ class BaseModelSqlv2 { ), ); - NcError.unprocessableEntity( - `Child record with id [${extractIdsString( - missingIds, - )}] not found`, - ); + NcError.recordNotFound(extractIds(missingIds)); } } @@ -6086,11 +6059,7 @@ class BaseModelSqlv2 { ), ); - NcError.unprocessableEntity( - `Child record with id [${extractIdsString( - missingIds, - )}] not found`, - ); + NcError.recordNotFound(extractIds(missingIds)); } } @@ -6148,12 +6117,7 @@ class BaseModelSqlv2 { }); if (!childRow) { - NcError.unprocessableEntity( - `Child record with id [${extractIdsString( - childIds, - true, - )}] not found`, - ); + NcError.recordNotFound(extractIds(childIds, true)); } } @@ -6213,7 +6177,7 @@ class BaseModelSqlv2 { // validate rowId if (!row) { - NcError.notFound(`Record with id ${id} not found`); + NcError.recordNotFound(id); } const parentCol = await ( @@ -6501,7 +6465,7 @@ export function extractSortsObject( else sort.fk_column_id = aliasColObjMap[s.replace(/^\+/, '')]?.id; if (throwErrorIfInvalid && !sort.fk_column_id) - NcError.unprocessableEntity(`Invalid field: ${s.replace(/^[+-]/, '')}`); + NcError.fieldNotFound(s.replace(/^[+-]/, '')); return new Sort(sort); }); @@ -6672,7 +6636,7 @@ export function extractCondition( validateFilterComparison(aliasColObjMap[alias].uidt, op, sub_op); } else if (throwErrorIfInvalid) { - NcError.unprocessableEntity(`Invalid field: ${alias}`); + NcError.invalidFilter(str); } return new Filter({ @@ -6828,13 +6792,13 @@ export function getListArgs( return obj; } -function extractIdsString( +function extractIds( childIds: (string | number | Record)[], isBt = false, ) { - return (isBt ? childIds.slice(0, 1) : childIds) - .map((r) => (typeof r === 'object' ? JSON.stringify(r) : r)) - .join(', '); + return (isBt ? childIds.slice(0, 1) : childIds).map((r) => + typeof r === 'object' ? JSON.stringify(r) : `${r}`, + ); } export { BaseModelSqlv2 }; diff --git a/packages/nocodb/src/db/conditionV2.ts b/packages/nocodb/src/db/conditionV2.ts index 703139a386..9a9764a1cc 100644 --- a/packages/nocodb/src/db/conditionV2.ts +++ b/packages/nocodb/src/db/conditionV2.ts @@ -167,7 +167,7 @@ const parseConditionV2 = async ( const column = await getRefColumnIfAlias(await filter.getColumn()); if (!column) { if (throwErrorIfInvalid) { - NcError.unprocessableEntity(`Invalid field: ${filter.fk_column_id}`); + NcError.fieldNotFound(filter.fk_column_id); } return; } diff --git a/packages/nocodb/src/db/generateLookupSelectQuery.ts b/packages/nocodb/src/db/generateLookupSelectQuery.ts index 0a618d8d02..92efea7a68 100644 --- a/packages/nocodb/src/db/generateLookupSelectQuery.ts +++ b/packages/nocodb/src/db/generateLookupSelectQuery.ts @@ -434,8 +434,6 @@ export default async function generateLookupSelectQuery({ }; } - NcError.notImplemented( - 'Database not supported this operation on Lookup/LTAR', - ); + NcError.notImplemented('This operation on Lookup/LTAR for this database'); } } diff --git a/packages/nocodb/src/db/sortV2.ts b/packages/nocodb/src/db/sortV2.ts index e3706d1d23..8b5bac7863 100644 --- a/packages/nocodb/src/db/sortV2.ts +++ b/packages/nocodb/src/db/sortV2.ts @@ -33,7 +33,7 @@ export default async function sortV2( const column = await getRefColumnIfAlias(await sort.getColumn()); if (!column) { if (throwErrorIfInvalid) { - NcError.unprocessableEntity(`Invalid field: ${sort.fk_column_id}`); + NcError.fieldNotFound(sort.fk_column_id); } continue; } diff --git a/packages/nocodb/src/filters/global-exception/global-exception.filter.ts b/packages/nocodb/src/filters/global-exception/global-exception.filter.ts index 9a5806f9d7..5f036eb1e7 100644 --- a/packages/nocodb/src/filters/global-exception/global-exception.filter.ts +++ b/packages/nocodb/src/filters/global-exception/global-exception.filter.ts @@ -8,9 +8,8 @@ import { BadRequest, extractDBError, Forbidden, - InternalServerError, + NcBaseErrorv2, NotFound, - NotImplemented, Unauthorized, UnprocessableEntity, } from '~/helpers/catchError'; @@ -37,7 +36,6 @@ export class GlobalExceptionFilter implements ExceptionFilter { exception instanceof Unauthorized || exception instanceof Forbidden || exception instanceof NotFound || - exception instanceof NotImplemented || exception instanceof UnprocessableEntity || exception instanceof NotFoundException || exception instanceof ThrottlerException @@ -83,22 +81,18 @@ export class GlobalExceptionFilter implements ExceptionFilter { exception.getStatus?.() === 404 ) { return response.status(404).json({ msg: exception.message }); - } else if ( - exception instanceof InternalServerError || - exception.getStatus?.() === 500 - ) { - return response.status(500).json({ msg: exception.message }); - } else if ( - exception instanceof NotImplemented || - exception.getStatus?.() === 501 - ) { - return response.status(501).json({ msg: exception.message }); } else if (exception instanceof AjvError) { return response .status(400) .json({ msg: exception.message, errors: exception.errors }); } else if (exception instanceof UnprocessableEntity) { return response.status(422).json({ msg: exception.message }); + } else if (exception instanceof NcBaseErrorv2) { + return response.status(exception.code).json({ + error: exception.error, + message: exception.message, + details: exception.details, + }); } // handle different types of exceptions diff --git a/packages/nocodb/src/helpers/NcPluginMgrv2.ts b/packages/nocodb/src/helpers/NcPluginMgrv2.ts index d9873c580c..717ee663c4 100644 --- a/packages/nocodb/src/helpers/NcPluginMgrv2.ts +++ b/packages/nocodb/src/helpers/NcPluginMgrv2.ts @@ -249,7 +249,7 @@ class NcPluginMgrv2 { await tempPlugin.init(args?.input); if (!tempPlugin?.getAdapter()?.test) - NcError.notImplemented('Plugin test is not implemented'); + NcError.notImplemented('Plugin Test'); return tempPlugin?.getAdapter()?.test?.(); } @@ -263,7 +263,7 @@ class NcPluginMgrv2 { await tempPlugin.init(args?.input); if (!tempPlugin?.getAdapter()?.test) - NcError.notImplemented('Plugin test is not implemented'); + NcError.notImplemented('Plugin Test'); return tempPlugin?.getAdapter()?.test?.(); } @@ -276,7 +276,7 @@ class NcPluginMgrv2 { await tempPlugin.init(args?.input); if (!tempPlugin?.getAdapter()?.test) - NcError.notImplemented('Plugin test is not implemented'); + NcError.notImplemented('Plugin Test'); return tempPlugin?.getAdapter()?.test?.(); } diff --git a/packages/nocodb/src/helpers/PagedResponse.ts b/packages/nocodb/src/helpers/PagedResponse.ts index 09696b11a6..ef2c6cbb87 100644 --- a/packages/nocodb/src/helpers/PagedResponse.ts +++ b/packages/nocodb/src/helpers/PagedResponse.ts @@ -42,7 +42,7 @@ export class PagedResponseImpl { if (additionalProps) Object.assign(this, additionalProps); if (offset && offset >= +count) { - NcError.badRequest('Offset is beyond the total number of records'); + NcError.invalidOffsetValue(offset); } } diff --git a/packages/nocodb/src/helpers/catchError.ts b/packages/nocodb/src/helpers/catchError.ts index 0ec0af1e77..29bad0e38e 100644 --- a/packages/nocodb/src/helpers/catchError.ts +++ b/packages/nocodb/src/helpers/catchError.ts @@ -1,5 +1,7 @@ +import { NcErrorType } from 'nocodb-sdk'; import type { NextFunction, Request, Response } from 'express'; import type { ErrorObject } from 'ajv'; +import { defaultLimitConfig } from '~/helpers/extractLimitAndOffset'; export enum DBError { TABLE_EXIST = 'TABLE_EXIST', @@ -372,6 +374,12 @@ export function extractDBError(error): { case 'EHOSTDOWN': message = 'The host is down.'; break; + default: + // if error message contains -- then extract message after -- + if (error.message && error.message.includes('--')) { + message = error.message.split('--')[1]; + } + break; } if (message) { @@ -400,7 +408,6 @@ export default function ( e instanceof Unauthorized || e instanceof Forbidden || e instanceof NotFound || - e instanceof NotImplemented || e instanceof UnprocessableEntity ) ) @@ -409,7 +416,15 @@ export default function ( const dbError = extractDBError(e); if (dbError) { - return res.status(400).json(dbError); + const error = new NcBaseErrorv2(NcErrorType.DATABASE_ERROR, { + params: dbError.message, + details: dbError, + }); + return res.status(error.code).json({ + error: error.error, + message: error.message, + details: error.details, + }); } if (e instanceof BadRequest) { @@ -420,16 +435,16 @@ export default function ( return res.status(403).json({ msg: e.message }); } else if (e instanceof NotFound) { return res.status(404).json({ msg: e.message }); - } else if (e instanceof InternalServerError) { - return res.status(500).json({ msg: e.message }); - } else if (e instanceof NotImplemented) { - return res.status(501).json({ msg: e.message }); } else if (e instanceof AjvError) { return res.status(400).json({ msg: e.message, errors: e.errors }); } else if (e instanceof UnprocessableEntity) { return res.status(422).json({ msg: e.message }); } else if (e instanceof NotAllowed) { return res.status(405).json({ msg: e.message }); + } else if (e instanceof NcBaseErrorv2) { + return res + .status(e.code) + .json({ error: e.error, message: e.message, details: e.details }); } // if some other error occurs then send 500 and a generic message res.status(500).json({ msg: 'Internal server error' }); @@ -453,10 +468,6 @@ export class Forbidden extends NcBaseError {} export class NotFound extends NcBaseError {} -export class InternalServerError extends NcBaseError {} - -export class NotImplemented extends NcBaseError {} - export class UnprocessableEntity extends NcBaseError {} export class AjvError extends NcBaseError { @@ -468,7 +479,266 @@ export class AjvError extends NcBaseError { errors: ErrorObject[]; } +const errorHelpers: { + [key in NcErrorType]: { + message: string | ((...params: string[]) => string); + code: number; + }; +} = { + [NcErrorType.INTERNAL_SERVER_ERROR]: { + message: (message: string) => message || `Internal server error`, + code: 500, + }, + [NcErrorType.DATABASE_ERROR]: { + message: (message: string) => + message || `There was an error while running the query`, + code: 500, + }, + [NcErrorType.AUTHENTICATION_REQUIRED]: { + message: 'Authentication required to access this resource', + code: 401, + }, + [NcErrorType.API_TOKEN_NOT_ALLOWED]: { + message: 'This request is not allowed with API token', + code: 401, + }, + [NcErrorType.WORKSPACE_NOT_FOUND]: { + message: (id: string) => `Workspace '${id}' not found`, + code: 404, + }, + [NcErrorType.BASE_NOT_FOUND]: { + message: (id: string) => `Base '${id}' not found`, + code: 404, + }, + [NcErrorType.SOURCE_NOT_FOUND]: { + message: (id: string) => `Source '${id}' not found`, + code: 404, + }, + [NcErrorType.TABLE_NOT_FOUND]: { + message: (id: string) => `Table '${id}' not found`, + code: 404, + }, + [NcErrorType.VIEW_NOT_FOUND]: { + message: (id: string) => `View '${id}' not found`, + code: 404, + }, + [NcErrorType.FIELD_NOT_FOUND]: { + message: (id: string) => `Field '${id}' not found`, + code: 404, + }, + [NcErrorType.RECORD_NOT_FOUND]: { + message: (...ids: string[]) => { + const isMultiple = Array.isArray(ids) && ids.length > 1; + return `Record${isMultiple ? 's' : ''} '${ids.join(', ')}' not found`; + }, + code: 404, + }, + [NcErrorType.ERROR_DUPLICATE_RECORD]: { + message: (...ids: string[]) => { + const isMultiple = Array.isArray(ids) && ids.length > 1; + return `Record${isMultiple ? 's' : ''} '${ids.join( + ', ', + )}' already exists`; + }, + code: 422, + }, + [NcErrorType.USER_NOT_FOUND]: { + message: (idOrEmail: string) => { + const isEmail = idOrEmail.includes('@'); + return `User ${ + isEmail ? 'with email' : 'with id' + } '${idOrEmail}' not found`; + }, + code: 404, + }, + [NcErrorType.INVALID_OFFSET_VALUE]: { + message: (offset: string) => `Offset value '${offset}' is invalid`, + code: 422, + }, + [NcErrorType.INVALID_LIMIT_VALUE]: { + message: `Limit value should be between ${defaultLimitConfig.limitMin} and ${defaultLimitConfig.limitMax}`, + code: 422, + }, + [NcErrorType.INVALID_FILTER]: { + message: (filter: string) => `Filter '${filter}' is invalid`, + code: 422, + }, + [NcErrorType.INVALID_SHARED_VIEW_PASSWORD]: { + message: 'Invalid shared view password', + code: 403, + }, + [NcErrorType.NOT_IMPLEMENTED]: { + message: (feature: string) => `${feature} is not implemented`, + code: 501, + }, +}; + +function generateError( + type: NcErrorType, + args?: NcErrorArgs, +): { + message: string; + code: number; + details?: any; +} { + const errorHelper = errorHelpers[type]; + const { params, customMessage, details } = args || {}; + + if (!errorHelper) { + return { + message: 'An error occurred', + code: 500, + details: details, + }; + } + + let message: string; + const messageHelper = customMessage || errorHelper.message; + + if (typeof messageHelper === 'function') { + message = messageHelper(...(Array.isArray(params) ? params : [params])); + } else { + message = messageHelper; + } + + return { + message, + code: errorHelper.code, + details: details, + }; +} + +type NcErrorArgs = { + params?: string | string[]; + customMessage?: string | ((...args: string[]) => string); + details?: any; +}; + +export class NcBaseErrorv2 extends NcBaseError { + error: NcErrorType; + code: number; + details?: any; + constructor(error: NcErrorType, args?: NcErrorArgs) { + const errorHelper = generateError(error, args); + super(errorHelper.message); + this.error = error; + this.code = errorHelper.code; + this.details = args?.details; + } +} + export class NcError { + static authenticationRequired(args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.AUTHENTICATION_REQUIRED, args); + } + + static apiTokenNotAllowed(args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.API_TOKEN_NOT_ALLOWED, args); + } + + static workspaceNotFound(id: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.WORKSPACE_NOT_FOUND, { + params: id, + ...args, + }); + } + + static baseNotFound(id: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.BASE_NOT_FOUND, { + params: id, + ...args, + }); + } + + static sourceNotFound(id: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.SOURCE_NOT_FOUND, { + params: id, + ...args, + }); + } + + static tableNotFound(id: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.TABLE_NOT_FOUND, { + params: id, + ...args, + }); + } + + static userNotFound(id: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.USER_NOT_FOUND, { + params: id, + ...args, + }); + } + + static viewNotFound(id: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.VIEW_NOT_FOUND, { + params: id, + ...args, + }); + } + + static recordNotFound(id: string | string[], args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.RECORD_NOT_FOUND, { + params: id, + ...args, + }); + } + + static duplicateRecord(id: string | string[], args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.ERROR_DUPLICATE_RECORD, { + params: id, + ...args, + }); + } + + static fieldNotFound(id: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.FIELD_NOT_FOUND, { + params: id, + ...args, + }); + } + + static invalidOffsetValue(offset: string | number, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.INVALID_OFFSET_VALUE, { + params: `${offset}`, + ...args, + }); + } + + static invalidLimitValue(args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.INVALID_LIMIT_VALUE, { + ...args, + }); + } + + static invalidFilter(filter: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.INVALID_FILTER, { + params: filter, + ...args, + }); + } + + static invalidSharedViewPassword(args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.INVALID_SHARED_VIEW_PASSWORD, { + ...args, + }); + } + + static notImplemented(feature: string = 'Feature', args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.NOT_IMPLEMENTED, { + params: feature, + ...args, + }); + } + + static internalServerError(message: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.INTERNAL_SERVER_ERROR, { + params: message, + ...args, + }); + } + static notFound(message = 'Not found') { throw new NotFound(message); } @@ -485,14 +755,6 @@ export class NcError { throw new Forbidden(message); } - static internalServerError(message = 'Internal server error') { - throw new InternalServerError(message); - } - - static notImplemented(message = 'Not implemented') { - throw new NotImplemented(message); - } - static ajvValidationError(param: { message: string; errors: ErrorObject[] }) { throw new AjvError(param); } diff --git a/packages/nocodb/src/helpers/getAst.ts b/packages/nocodb/src/helpers/getAst.ts index a2625958e1..9657bbc0d7 100644 --- a/packages/nocodb/src/helpers/getAst.ts +++ b/packages/nocodb/src/helpers/getAst.ts @@ -115,7 +115,7 @@ const getAst = async ({ (f) => !colAliasMap[f] && !aliasColMap[f], ); if (invalidFields.length) { - NcError.unprocessableEntity(`Invalid field: ${invalidFields[0]}`); + NcError.fieldNotFound(invalidFields.join(', ')); } } } else { diff --git a/packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts b/packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts index f8f5bce37a..bbcc8a4368 100644 --- a/packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts +++ b/packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts @@ -253,7 +253,7 @@ export class AclMiddleware implements NestInterceptor { const roles: Record = extractRolesObj(userScopeRole); if (req?.user?.is_api_token && blockApiTokenAccess) { - NcError.forbidden('Not allowed with API token'); + NcError.apiTokenNotAllowed(); } if ( (!allowedRoles || allowedRoles.some((role) => roles?.[role])) && diff --git a/packages/nocodb/src/models/Filter.ts b/packages/nocodb/src/models/Filter.ts index db089524f7..c0b0ee763b 100644 --- a/packages/nocodb/src/models/Filter.ts +++ b/packages/nocodb/src/models/Filter.ts @@ -96,7 +96,7 @@ export default class Filter implements FilterType { } else if (filter.fk_column_id) { model = await Column.get({ colId: filter.fk_column_id }, ncMeta); } else { - NcError.badRequest('Invalid filter'); + NcError.invalidFilter(JSON.stringify(filter)); } if (model != null) { diff --git a/packages/nocodb/src/models/Model.ts b/packages/nocodb/src/models/Model.ts index 93fcc15b46..f53d71876e 100644 --- a/packages/nocodb/src/models/Model.ts +++ b/packages/nocodb/src/models/Model.ts @@ -765,7 +765,7 @@ export default class Model implements TableType { const model = await this.getWithInfo({ id: tableId }); const newPvCol = model.columns.find((c) => c.id === columnId); - if (!newPvCol) NcError.badRequest('Column not found'); + if (!newPvCol) NcError.fieldNotFound(columnId); // drop existing primary column/s for (const col of model.columns?.filter((c) => c.pv) || []) { diff --git a/packages/nocodb/src/models/Source.ts b/packages/nocodb/src/models/Source.ts index 7dd5cf7b85..d63e5c968c 100644 --- a/packages/nocodb/src/models/Source.ts +++ b/packages/nocodb/src/models/Source.ts @@ -112,7 +112,7 @@ export default class Source implements SourceType { ) { const oldBase = await Source.get(sourceId, false, ncMeta); - if (!oldBase) NcError.badRequest('Wrong source id!'); + if (!oldBase) NcError.sourceNotFound(sourceId); const updateObj = extractProps(source, [ 'alias', diff --git a/packages/nocodb/src/models/User.ts b/packages/nocodb/src/models/User.ts index ff2da983df..6eba62d5eb 100644 --- a/packages/nocodb/src/models/User.ts +++ b/packages/nocodb/src/models/User.ts @@ -249,7 +249,7 @@ export default class User implements UserType { const user = await this.get(userId, ncMeta); - if (!user) NcError.badRequest('User not found'); + if (!user) NcError.userNotFound(userId); // clear all user related cache await this.clearCache(userId, ncMeta); @@ -267,7 +267,7 @@ export default class User implements UserType { ) { const user = args.user ?? (await this.get(userId, ncMeta)); - if (!user) NcError.badRequest('User not found'); + if (!user) NcError.userNotFound(userId); const baseRoles = await new Promise((resolve) => { if (args.baseId) { @@ -295,7 +295,7 @@ export default class User implements UserType { protected static async clearCache(userId: string, ncMeta = Noco.ncMeta) { const user = await this.get(userId, ncMeta); - if (!user) NcError.badRequest('User not found'); + if (!user) NcError.userNotFound(userId); // todo: skip base user cache delete based on flag const bases = await BaseUser.getProjectsList(userId, {}, ncMeta); diff --git a/packages/nocodb/src/modules/datas/helpers.ts b/packages/nocodb/src/modules/datas/helpers.ts index b7dd7cf623..72a068e745 100644 --- a/packages/nocodb/src/modules/datas/helpers.ts +++ b/packages/nocodb/src/modules/datas/helpers.ts @@ -37,7 +37,7 @@ export async function getViewAndModelByAliasOrId(param: { aliasOrId: param.tableName, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.tableName); const view = param.viewName && @@ -45,7 +45,7 @@ export async function getViewAndModelByAliasOrId(param: { titleOrId: param.viewName, fk_model_id: model.id, })); - if (param.viewName && !view) NcError.notFound('View not found'); + if (param.viewName && !view) NcError.viewNotFound(param.viewName); return { model, view }; } @@ -234,8 +234,7 @@ export async function getColumnByIdOrName( c.column_name === columnNameOrId, ); - if (!column) - NcError.notFound(`Column with id/name '${columnNameOrId}' is not found`); + if (!column) NcError.fieldNotFound(columnNameOrId); return column; } diff --git a/packages/nocodb/src/modules/jobs/jobs/export-import/export.service.ts b/packages/nocodb/src/modules/jobs/jobs/export-import/export.service.ts index a480dcedd2..7a33d109ac 100644 --- a/packages/nocodb/src/modules/jobs/jobs/export-import/export.service.ts +++ b/packages/nocodb/src/modules/jobs/jobs/export-import/export.service.ts @@ -47,8 +47,7 @@ export class ExportService { let pgSerialLastVal; - if (!model) - return NcError.badRequest(`Model not found for id '${modelId}'`); + if (!model) return NcError.tableNotFound(modelId); const fndProject = bases.find((p) => p.id === model.base_id); const base = fndProject || (await Base.get(model.base_id)); @@ -703,8 +702,7 @@ export class ExportService { const source = await Source.get(param.sourceId); - if (!source) - throw NcError.badRequest(`Source not found for id '${param.sourceId}'`); + if (!source) NcError.sourceNotFound(param.sourceId); const base = await Base.get(source.base_id); diff --git a/packages/nocodb/src/modules/jobs/jobs/export-import/import.service.ts b/packages/nocodb/src/modules/jobs/jobs/export-import/import.service.ts index 4988ff53dc..bd49185cc1 100644 --- a/packages/nocodb/src/modules/jobs/jobs/export-import/import.service.ts +++ b/packages/nocodb/src/modules/jobs/jobs/export-import/import.service.ts @@ -94,13 +94,11 @@ export class ImportService { const base = await Base.get(param.baseId); - if (!base) - return NcError.badRequest(`Base not found for id '${param.baseId}'`); + if (!base) return NcError.baseNotFound(param.baseId); const source = await Source.get(param.sourceId); - if (!source) - return NcError.badRequest(`Source not found for id '${param.sourceId}'`); + if (!source) return NcError.sourceNotFound(param.sourceId); const tableReferences = new Map(); const linkMap = new Map(); @@ -1357,9 +1355,8 @@ export class ImportService { const destProject = await Base.get(baseId); const destBase = await Source.get(sourceId); - if (!destProject || !destBase) { - throw NcError.badRequest('Base or Source not found'); - } + if (!destProject) return NcError.baseNotFound(baseId); + if (!destBase) return NcError.sourceNotFound(sourceId); switch (src.type) { case 'local': { diff --git a/packages/nocodb/src/services/api-docs/api-docs.service.ts b/packages/nocodb/src/services/api-docs/api-docs.service.ts index 2e51b6466a..f2e2a0ebf8 100644 --- a/packages/nocodb/src/services/api-docs/api-docs.service.ts +++ b/packages/nocodb/src/services/api-docs/api-docs.service.ts @@ -9,7 +9,7 @@ export class ApiDocsService { async swaggerJson(param: { baseId: string; siteUrl: string }) { const base = await Base.get(param.baseId); - if (!base) NcError.notFound(); + if (!base) NcError.baseNotFound(param.baseId); const models = await Model.list({ base_id: param.baseId, @@ -38,7 +38,7 @@ export class ApiDocsService { async swaggerJsonV2(param: { baseId: string; siteUrl: string }) { const base = await Base.get(param.baseId); - if (!base) NcError.notFound(); + if (!base) NcError.baseNotFound(param.baseId); const models = await Model.list({ base_id: param.baseId, diff --git a/packages/nocodb/src/services/base-users/base-users.service.ts b/packages/nocodb/src/services/base-users/base-users.service.ts index f7025be205..79fc8e93b6 100644 --- a/packages/nocodb/src/services/base-users/base-users.service.ts +++ b/packages/nocodb/src/services/base-users/base-users.service.ts @@ -92,7 +92,7 @@ export class BaseUsersService { const base = await Base.get(param.baseId); if (!base) { - return NcError.badRequest('Invalid base id'); + return NcError.baseNotFound(param.baseId); } if (user) { @@ -102,7 +102,7 @@ export class BaseUsersService { const base = await Base.get(param.baseId); if (!base) { - return NcError.badRequest('Invalid base id'); + return NcError.baseNotFound(param.baseId); } if (baseUser && baseUser.roles) { @@ -200,7 +200,7 @@ export class BaseUsersService { const base = await Base.get(param.baseId); if (!base) { - return NcError.badRequest('Invalid base id'); + return NcError.baseNotFound(param.baseId); } if (param.baseUser.roles.includes(ProjectRoles.OWNER)) { @@ -306,7 +306,7 @@ export class BaseUsersService { const base = await Base.get(param.baseId); if (!base) { - return NcError.badRequest('Invalid base id'); + return NcError.baseNotFound(param.baseId); } const invite_token = uuidv4(); diff --git a/packages/nocodb/src/services/bases.service.ts b/packages/nocodb/src/services/bases.service.ts index 58ab4d6db5..635f6cdba0 100644 --- a/packages/nocodb/src/services/bases.service.ts +++ b/packages/nocodb/src/services/bases.service.ts @@ -111,7 +111,7 @@ export class BasesService { const base = await Base.getWithInfo(param.baseId); if (!base) { - NcError.notFound('Base not found'); + NcError.baseNotFound(param.baseId); } await Base.softDelete(param.baseId); diff --git a/packages/nocodb/src/services/calendar-datas.service.ts b/packages/nocodb/src/services/calendar-datas.service.ts index 48480f7efa..6c772c59c8 100644 --- a/packages/nocodb/src/services/calendar-datas.service.ts +++ b/packages/nocodb/src/services/calendar-datas.service.ts @@ -1,5 +1,5 @@ import { Injectable, Logger } from '@nestjs/common'; -import { ErrorMessages, ViewTypes } from 'nocodb-sdk'; +import { ViewTypes } from 'nocodb-sdk'; import dayjs from 'dayjs'; import type { CalendarRangeType, FilterType } from 'nocodb-sdk'; import { CalendarRange, Model, View } from '~/models'; @@ -29,7 +29,7 @@ export class CalendarDatasService { const view = await View.get(viewId); - if (!view) NcError.notFound('View not found'); + if (!view) NcError.viewNotFound(viewId); if (view.type !== ViewTypes.CALENDAR) NcError.badRequest('View is not a calendar view'); @@ -70,13 +70,13 @@ export class CalendarDatasService { const { sharedViewUuid, password, query = {} } = param; const view = await View.getByUUID(sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(sharedViewUuid); if (view.type !== ViewTypes.CALENDAR) { - NcError.notFound('Not found'); + NcError.notFound('View is not a calendar view'); } if (view.password && view.password !== password) { - return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + return NcError.invalidSharedViewPassword(); } return this.getCalendarRecordCount({ @@ -97,13 +97,13 @@ export class CalendarDatasService { const { sharedViewUuid, password, query = {} } = param; const view = await View.getByUUID(sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(sharedViewUuid); if (view.type !== ViewTypes.CALENDAR) { - NcError.notFound('Not found'); + NcError.notFound('View is not a calendar view'); } if (view.password && view.password !== password) { - return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + return NcError.invalidSharedViewPassword(); } return this.getCalendarDataList({ @@ -131,7 +131,7 @@ export class CalendarDatasService { const view = await View.get(viewId); - if (!view) NcError.notFound('View not found'); + if (!view) NcError.viewNotFound(viewId); if (view.type !== ViewTypes.CALENDAR) NcError.badRequest('View is not a calendar view'); diff --git a/packages/nocodb/src/services/calendars.service.ts b/packages/nocodb/src/services/calendars.service.ts index dee83076fc..7bdccbc139 100644 --- a/packages/nocodb/src/services/calendars.service.ts +++ b/packages/nocodb/src/services/calendars.service.ts @@ -77,7 +77,7 @@ export class CalendarsService { const view = await View.get(param.calendarViewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.calendarViewId); } const res = await CalendarView.update(param.calendarViewId, param.calendar); diff --git a/packages/nocodb/src/services/columns.service.ts b/packages/nocodb/src/services/columns.service.ts index 4d976dfa0a..cbc693354e 100644 --- a/packages/nocodb/src/services/columns.service.ts +++ b/packages/nocodb/src/services/columns.service.ts @@ -306,9 +306,7 @@ export class ColumnsService { await this.updateRollupOrLookup(colBody, column); } else { - NcError.notImplemented( - `Updating ${colBody.uidt} => ${colBody.uidt} is not implemented`, - ); + NcError.notImplemented(`Updating ${colBody.uidt} => ${colBody.uidt}`); } } else if ( [ @@ -321,9 +319,7 @@ export class ColumnsService { UITypes.ForeignKey, ].includes(colBody.uidt) ) { - NcError.notImplemented( - `Updating ${colBody.uidt} => ${colBody.uidt} is not implemented`, - ); + NcError.notImplemented(`Updating ${colBody.uidt} => ${colBody.uidt}`); } else if ( [ UITypes.CreatedTime, @@ -1317,9 +1313,7 @@ export class ColumnsService { ...colBody, }); } else { - NcError.notImplemented( - `Updating ${column.uidt} => ${colBody.uidt} is not supported at the moment`, - ); + NcError.notImplemented(`Updating ${column.uidt} => ${colBody.uidt}`); } } else if (column.uidt === UITypes.User) { if ([UITypes.SingleLineText, UITypes.Email].includes(colBody.uidt)) { @@ -1412,9 +1406,7 @@ export class ColumnsService { ...colBody, }); } else { - NcError.notImplemented( - `Updating ${column.uidt} => ${colBody.uidt} is not supported at the moment`, - ); + NcError.notImplemented(`Updating ${column.uidt} => ${colBody.uidt}`); } } else { colBody = await getColumnPropsFromUIDT(colBody, source); @@ -2286,7 +2278,7 @@ export class ColumnsService { }); break; case UITypes.ForeignKey: { - NcError.notImplemented(); + NcError.notImplemented(`Support for ${column.uidt}`); break; } case UITypes.SingleSelect: { @@ -3135,7 +3127,7 @@ export class ColumnsService { }); if (!table) { - NcError.badRequest('Table not found'); + NcError.tableNotFound(tableId); } const columns = await table.getColumns(); @@ -3163,7 +3155,7 @@ export class ColumnsService { }); if (!table) { - NcError.badRequest('Table not found'); + NcError.tableNotFound(tableId); } const columns = await table.getColumns(); @@ -3177,13 +3169,13 @@ export class ColumnsService { const source = await Source.get(table.source_id); if (!source) { - NcError.badRequest('Source not found'); + NcError.sourceNotFound(table.source_id); } const base = await source.getProject(); if (!base) { - NcError.badRequest('Base not found'); + NcError.baseNotFound(source.base_id); } const dbDriver = await NcConnectionMgrv2.get(source); diff --git a/packages/nocodb/src/services/data-alias-nested.service.ts b/packages/nocodb/src/services/data-alias-nested.service.ts index d550544e46..7f87ecf876 100644 --- a/packages/nocodb/src/services/data-alias-nested.service.ts +++ b/packages/nocodb/src/services/data-alias-nested.service.ts @@ -22,7 +22,7 @@ export class DataAliasNestedService { ) { const { model, view } = await getViewAndModelByAliasOrId(param); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.tableName); const source = await Source.get(model.source_id); @@ -69,7 +69,7 @@ export class DataAliasNestedService { }, ) { const { model, view } = await getViewAndModelByAliasOrId(param); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.tableName); const source = await Source.get(model.source_id); @@ -111,7 +111,7 @@ export class DataAliasNestedService { ) { const { model, view } = await getViewAndModelByAliasOrId(param); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.tableName); const source = await Source.get(model.source_id); @@ -153,7 +153,7 @@ export class DataAliasNestedService { }, ) { const { model, view } = await getViewAndModelByAliasOrId(param); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.tableName); const source = await Source.get(model.source_id); @@ -238,7 +238,7 @@ export class DataAliasNestedService { ) { const { model, view } = await getViewAndModelByAliasOrId(param); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.tableName); const source = await Source.get(model.source_id); @@ -284,7 +284,7 @@ export class DataAliasNestedService { }, ) { const { model, view } = await getViewAndModelByAliasOrId(param); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.tableName); const source = await Source.get(model.source_id); @@ -316,7 +316,7 @@ export class DataAliasNestedService { }, ) { const { model, view } = await getViewAndModelByAliasOrId(param); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.tableName); const source = await Source.get(model.source_id); diff --git a/packages/nocodb/src/services/data-table.service.ts b/packages/nocodb/src/services/data-table.service.ts index 3077cb9f8f..f136c5891c 100644 --- a/packages/nocodb/src/services/data-table.service.ts +++ b/packages/nocodb/src/services/data-table.service.ts @@ -52,7 +52,7 @@ export class DataTableService { }); if (!row) { - NcError.notFound('Row not found'); + NcError.recordNotFound(param.rowId); } return row; @@ -184,7 +184,7 @@ export class DataTableService { const model = await Model.get(param.modelId); if (!model) { - NcError.notFound(`Table with id '${param.modelId}' not found`); + NcError.tableNotFound(param.modelId); } if (param.baseId && model.base_id !== param.baseId) { @@ -196,7 +196,7 @@ export class DataTableService { if (param.viewId) { view = await View.get(param.viewId); if (!view || (view.fk_model_id && view.fk_model_id !== param.modelId)) { - NcError.unprocessableEntity(`View with id '${param.viewId}' not found`); + NcError.viewNotFound(param.viewId); } } @@ -278,7 +278,7 @@ export class DataTableService { }); if (!(await baseModel.exist(param.rowId))) { - NcError.notFound(`Record with id '${param.rowId}' not found`); + NcError.recordNotFound(`${param.rowId}`); } const column = await this.getColumn(param); @@ -356,8 +356,7 @@ export class DataTableService { private async getColumn(param: { modelId: string; columnId: string }) { const column = await Column.get({ colId: param.columnId }); - if (!column) - NcError.notFound(`Column with id '${param.columnId}' not found`); + if (!column) NcError.fieldNotFound(param.columnId); if (column.fk_model_id !== param.modelId) NcError.badRequest('Column not belong to model'); @@ -419,8 +418,7 @@ export class DataTableService { this.validateIds(param.refRowIds); const { model, view } = await this.getModelAndView(param); - if (!model) - NcError.notFound('Table with id ' + param.modelId + ' not found'); + if (!model) NcError.tableNotFound(param.modelId); const source = await Source.get(model.source_id); @@ -503,9 +501,7 @@ export class DataTableService { operationMap.deleteAll && !(await baseModel.exist(operationMap.deleteAll.rowId)) ) { - NcError.notFound( - `Record with id '${operationMap.deleteAll.rowId}' not found`, - ); + NcError.recordNotFound(operationMap.deleteAll.rowId); } else if (operationMap.copy && operationMap.paste) { const [existsCopyRow, existsPasteRow] = await Promise.all([ baseModel.exist(operationMap.copy.rowId), @@ -513,17 +509,13 @@ export class DataTableService { ]); if (!existsCopyRow && !existsPasteRow) { - NcError.notFound( - `Record with id '${operationMap.copy.rowId}' and '${operationMap.paste.rowId}' not found`, + NcError.recordNotFound( + `'${operationMap.copy.rowId}' and '${operationMap.paste.rowId}'`, ); } else if (!existsCopyRow) { - NcError.notFound( - `Record with id '${operationMap.copy.rowId}' not found`, - ); + NcError.recordNotFound(operationMap.copy.rowId); } else if (!existsPasteRow) { - NcError.notFound( - `Record with id '${operationMap.paste.rowId}' not found`, - ); + NcError.recordNotFound(operationMap.paste.rowId); } } @@ -640,7 +632,7 @@ export class DataTableService { const set = new Set(); for (const rowId of rowIds) { if (rowId === undefined || rowId === null) - NcError.unprocessableEntity('Invalid row id ' + rowId); + NcError.recordNotFound(rowId); if (map.has(rowId)) { set.add(rowId); } else { @@ -648,12 +640,9 @@ export class DataTableService { } } - if (set.size > 0) - NcError.unprocessableEntity( - 'Child record with id [' + [...set].join(', ') + '] are duplicated', - ); + if (set.size > 0) NcError.duplicateRecord([...set]); } else if (rowIds === undefined || rowIds === null) { - NcError.unprocessableEntity('Invalid row id ' + rowIds); + NcError.recordNotFound(rowIds); } } diff --git a/packages/nocodb/src/services/datas.service.ts b/packages/nocodb/src/services/datas.service.ts index dac753df80..9d97ee8d55 100644 --- a/packages/nocodb/src/services/datas.service.ts +++ b/packages/nocodb/src/services/datas.service.ts @@ -295,7 +295,7 @@ export class DatasService { }); if (!row) { - NcError.notFound('Row not found'); + NcError.recordNotFound(param.rowId); } return row; @@ -390,7 +390,7 @@ export class DatasService { id: view?.fk_model_id || param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); return await this.getDataList({ model, view, query: param.query }); } @@ -407,7 +407,7 @@ export class DatasService { id: view?.fk_model_id || param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); const source = await Source.get(model.source_id); @@ -468,7 +468,7 @@ export class DatasService { id: view?.fk_model_id || param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); const source = await Source.get(model.source_id); @@ -529,7 +529,7 @@ export class DatasService { id: view?.fk_model_id || param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); const source = await Source.get(model.source_id); @@ -590,7 +590,7 @@ export class DatasService { id: view?.fk_model_id || param.viewId, }); - if (!model) return NcError.notFound('Table not found'); + if (!model) return NcError.tableNotFound(view?.fk_model_id || param.viewId); const source = await Source.get(model.source_id); @@ -651,7 +651,7 @@ export class DatasService { id: view?.fk_model_id || param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); const source = await Source.get(model.source_id); @@ -703,7 +703,7 @@ export class DatasService { const model = await Model.getByIdOrName({ id: param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.viewId); const source = await Source.get(model.source_id); @@ -733,7 +733,7 @@ export class DatasService { const model = await Model.getByIdOrName({ id: param.viewId, }); - if (!model) return NcError.notFound('Table not found'); + if (!model) return NcError.tableNotFound(param.viewId); const source = await Source.get(model.source_id); @@ -754,7 +754,7 @@ export class DatasService { const model = await Model.getByIdOrName({ id: param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.viewId); const source = await Source.get(model.source_id); @@ -779,7 +779,7 @@ export class DatasService { const model = await Model.getByIdOrName({ id: param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(param.viewId); const source = await Source.get(model.source_id); @@ -804,7 +804,7 @@ export class DatasService { id: view?.fk_model_id || param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); const source = await Source.get(model.source_id); @@ -837,7 +837,7 @@ export class DatasService { id: view?.fk_model_id || param.viewId, }); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); const source = await Source.get(model.source_id); @@ -875,7 +875,7 @@ export class DatasService { titleOrId: req.params.viewName, fk_model_id: model.id, })); - if (!model) NcError.notFound('Table not found'); + if (!model) NcError.tableNotFound(req.params.tableName); return { model, view }; } @@ -982,8 +982,7 @@ export class DatasService { c.column_name === columnNameOrId, ); - if (!column) - NcError.notFound(`Column with id/name '${columnNameOrId}' is not found`); + if (!column) NcError.fieldNotFound(columnNameOrId); return column; } diff --git a/packages/nocodb/src/services/forms.service.ts b/packages/nocodb/src/services/forms.service.ts index 08db6056b3..23b0beb641 100644 --- a/packages/nocodb/src/services/forms.service.ts +++ b/packages/nocodb/src/services/forms.service.ts @@ -77,7 +77,7 @@ export class FormsService { const view = await View.get(param.formViewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.formViewId); } const res = await FormView.update(param.formViewId, param.form); diff --git a/packages/nocodb/src/services/galleries.service.ts b/packages/nocodb/src/services/galleries.service.ts index 6afb4eb361..70d52a9025 100644 --- a/packages/nocodb/src/services/galleries.service.ts +++ b/packages/nocodb/src/services/galleries.service.ts @@ -76,7 +76,7 @@ export class GalleriesService { const view = await View.get(param.galleryViewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.galleryViewId); } const res = await GalleryView.update(param.galleryViewId, param.gallery); diff --git a/packages/nocodb/src/services/grids.service.ts b/packages/nocodb/src/services/grids.service.ts index 1e027f1849..4496223f47 100644 --- a/packages/nocodb/src/services/grids.service.ts +++ b/packages/nocodb/src/services/grids.service.ts @@ -67,7 +67,7 @@ export class GridsService { const view = await View.get(param.viewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.viewId); } const res = await GridView.update(param.viewId, param.grid); diff --git a/packages/nocodb/src/services/kanbans.service.ts b/packages/nocodb/src/services/kanbans.service.ts index 900ca2464a..bfa73ff566 100644 --- a/packages/nocodb/src/services/kanbans.service.ts +++ b/packages/nocodb/src/services/kanbans.service.ts @@ -78,7 +78,7 @@ export class KanbansService { const view = await View.get(param.kanbanViewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.kanbanViewId); } const res = await KanbanView.update(param.kanbanViewId, param.kanban); diff --git a/packages/nocodb/src/services/maps.service.ts b/packages/nocodb/src/services/maps.service.ts index 0069268385..cdf9112b40 100644 --- a/packages/nocodb/src/services/maps.service.ts +++ b/packages/nocodb/src/services/maps.service.ts @@ -70,7 +70,7 @@ export class MapsService { const view = await View.get(param.mapViewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.mapViewId); } const res = await MapView.update(param.mapViewId, param.map); diff --git a/packages/nocodb/src/services/model-visibilities.service.ts b/packages/nocodb/src/services/model-visibilities.service.ts index 71db96f994..465a257dae 100644 --- a/packages/nocodb/src/services/model-visibilities.service.ts +++ b/packages/nocodb/src/services/model-visibilities.service.ts @@ -24,7 +24,7 @@ export class ModelVisibilitiesService { const base = await Base.getWithInfo(param.baseId); if (!base) { - NcError.badRequest('Base not found'); + NcError.baseNotFound(param.baseId); } for (const d of param.visibilityRule) { diff --git a/packages/nocodb/src/services/org-users.service.ts b/packages/nocodb/src/services/org-users.service.ts index bfa8f694fe..4b49ca734d 100644 --- a/packages/nocodb/src/services/org-users.service.ts +++ b/packages/nocodb/src/services/org-users.service.ts @@ -201,7 +201,7 @@ export class OrgUsersService { const user = await User.get(param.userId); if (!user) { - NcError.badRequest(`User with id '${param.userId}' not found`); + NcError.userNotFound(param.userId); } const invite_token = uuidv4(); @@ -247,7 +247,7 @@ export class OrgUsersService { const user = await User.get(param.userId); if (!user) { - NcError.badRequest(`User with id '${param.userId}' not found`); + NcError.userNotFound(param.userId); } const token = uuidv4(); await User.update(user.id, { diff --git a/packages/nocodb/src/services/public-datas.service.ts b/packages/nocodb/src/services/public-datas.service.ts index abee2bcb0d..d1af9579d9 100644 --- a/packages/nocodb/src/services/public-datas.service.ts +++ b/packages/nocodb/src/services/public-datas.service.ts @@ -1,12 +1,7 @@ import path from 'path'; import { Injectable } from '@nestjs/common'; import { nanoid } from 'nanoid'; -import { - ErrorMessages, - populateUniqueFileName, - UITypes, - ViewTypes, -} from 'nocodb-sdk'; +import { populateUniqueFileName, UITypes, ViewTypes } from 'nocodb-sdk'; import slash from 'slash'; import { nocoExecute } from 'nc-help'; @@ -36,7 +31,7 @@ export class PublicDatasService { const { sharedViewUuid, password, query = {} } = param; const view = await View.getByUUID(sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(sharedViewUuid); if ( view.type !== ViewTypes.GRID && view.type !== ViewTypes.KANBAN && @@ -48,7 +43,7 @@ export class PublicDatasService { } if (view.password && view.password !== password) { - return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + return NcError.invalidSharedViewPassword(); } const model = await Model.getByIdOrName({ @@ -104,7 +99,7 @@ export class PublicDatasService { }) { const view = await View.getByUUID(param.sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(param.sharedViewUuid); if ( view.type !== ViewTypes.GRID && @@ -115,7 +110,7 @@ export class PublicDatasService { } if (view.password && view.password !== param.password) { - return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + return NcError.invalidSharedViewPassword(); } const model = await Model.getByIdOrName({ @@ -201,14 +196,14 @@ export class PublicDatasService { }) { const view = await View.getByUUID(param.sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(param.sharedViewUuid); if (view.type !== ViewTypes.GRID) { NcError.notFound('Not found'); } if (view.password && view.password !== param.password) { - return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + return NcError.invalidSharedViewPassword(); } const model = await Model.getByIdOrName({ @@ -261,11 +256,11 @@ export class PublicDatasService { }) { const view = await View.getByUUID(param.sharedViewUuid); - if (!view) NcError.notFound(); + if (!view) NcError.viewNotFound(param.sharedViewUuid); if (view.type !== ViewTypes.FORM) NcError.notFound(); if (view.password && view.password !== param.password) { - return NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + return NcError.invalidSharedViewPassword(); } const model = await Model.getByIdOrName({ @@ -434,14 +429,14 @@ export class PublicDatasService { }) { const view = await View.getByUUID(param.sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(param.sharedViewUuid); if (view.type !== ViewTypes.FORM && view.type !== ViewTypes.GALLERY) { NcError.notFound('Not found'); } if (view.password && view.password !== param.password) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + NcError.invalidSharedViewPassword(); } const column = await Column.get({ colId: param.columnId }); @@ -492,7 +487,7 @@ export class PublicDatasService { }) { const view = await View.getByUUID(param.sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(param.sharedViewUuid); if ( view.type !== ViewTypes.GRID && view.type !== ViewTypes.KANBAN && @@ -503,7 +498,7 @@ export class PublicDatasService { } if (view.password && view.password !== param.password) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + NcError.invalidSharedViewPassword(); } const column = await getColumnByIdOrName( @@ -567,7 +562,7 @@ export class PublicDatasService { }) { const view = await View.getByUUID(param.sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(param.sharedViewUuid); if ( view.type !== ViewTypes.GRID && view.type !== ViewTypes.KANBAN && @@ -578,7 +573,7 @@ export class PublicDatasService { } if (view.password && view.password !== param.password) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + NcError.invalidSharedViewPassword(); } const column = await getColumnByIdOrName( diff --git a/packages/nocodb/src/services/public-metas.service.ts b/packages/nocodb/src/services/public-metas.service.ts index 04150639cf..30b80bdc3f 100644 --- a/packages/nocodb/src/services/public-metas.service.ts +++ b/packages/nocodb/src/services/public-metas.service.ts @@ -1,6 +1,5 @@ import { Injectable } from '@nestjs/common'; import { - ErrorMessages, isCreatedOrLastModifiedByCol, RelationTypes, UITypes, @@ -19,10 +18,10 @@ export class PublicMetasService { client?: string; } = await View.getByUUID(param.sharedViewUuid); - if (!view) NcError.notFound('Not found'); + if (!view) NcError.viewNotFound(param.sharedViewUuid); if (view.password && view.password !== param.password) { - NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + NcError.invalidSharedViewPassword(); } await view.getFilters(); @@ -171,7 +170,7 @@ export class PublicMetasService { const base = await Base.getByUuid(param.sharedBaseUuid); if (!base) { - NcError.notFound(); + NcError.baseNotFound(param.sharedBaseUuid); } return { base_id: base.id }; diff --git a/packages/nocodb/src/services/shared-bases.service.ts b/packages/nocodb/src/services/shared-bases.service.ts index 057f1992dd..a6bfe878fc 100644 --- a/packages/nocodb/src/services/shared-bases.service.ts +++ b/packages/nocodb/src/services/shared-bases.service.ts @@ -42,7 +42,7 @@ export class SharedBasesService { } if (!base) { - NcError.badRequest('Invalid base id'); + NcError.baseNotFound(param.baseId); } const data: any = { @@ -86,7 +86,7 @@ export class SharedBasesService { } if (!base) { - NcError.badRequest('Invalid base id'); + NcError.baseNotFound(param.baseId); } if (roles === 'editor' && process.env.NC_CLOUD === 'true') { @@ -137,7 +137,7 @@ export class SharedBasesService { const base = await Base.get(param.baseId); if (!base) { - NcError.badRequest('Invalid base id'); + NcError.baseNotFound(param.baseId); } const data: any = { uuid: null, @@ -159,7 +159,7 @@ export class SharedBasesService { const base = await Base.get(param.baseId); if (!base) { - NcError.badRequest('Invalid base id'); + NcError.baseNotFound(param.baseId); } const data: any = { uuid: base.uuid, diff --git a/packages/nocodb/src/services/tables.service.ts b/packages/nocodb/src/services/tables.service.ts index 012371941b..73ab346e15 100644 --- a/packages/nocodb/src/services/tables.service.ts +++ b/packages/nocodb/src/services/tables.service.ts @@ -296,7 +296,7 @@ export class TablesService { }); if (!table) { - NcError.notFound('Table not found'); + NcError.tableNotFound(param.tableId); } // todo: optimise diff --git a/packages/nocodb/src/services/views.service.ts b/packages/nocodb/src/services/views.service.ts index 7cb0ab0a21..5aeaa8d62e 100644 --- a/packages/nocodb/src/services/views.service.ts +++ b/packages/nocodb/src/services/views.service.ts @@ -98,7 +98,7 @@ export class ViewsService { const view = await View.get(param.viewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.viewId); } this.appHooksService.emit(AppEvents.SHARED_VIEW_CREATE, { @@ -124,7 +124,7 @@ export class ViewsService { const view = await View.get(param.viewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.viewId); } const result = await View.update(param.viewId, param.view); @@ -145,7 +145,7 @@ export class ViewsService { const view = await View.get(param.viewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.viewId); } await View.delete(param.viewId); @@ -173,7 +173,7 @@ export class ViewsService { const view = await View.get(param.viewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.viewId); } const result = await View.update(param.viewId, param.sharedView); @@ -195,7 +195,7 @@ export class ViewsService { const view = await View.get(param.viewId); if (!view) { - NcError.badRequest('View not found'); + NcError.viewNotFound(param.viewId); } await View.sharedViewDelete(param.viewId); diff --git a/packages/nocodb/tests/unit/rest/tests/newDataApis.test.ts b/packages/nocodb/tests/unit/rest/tests/newDataApis.test.ts index 0d574cdda6..451188e321 100644 --- a/packages/nocodb/tests/unit/rest/tests/newDataApis.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/newDataApis.test.ts @@ -222,9 +222,9 @@ async function ncAxiosLinkGet({ // print error codes if (debugMode && status !== 200) { - console.log('#### ', response.body.msg); + console.log('#### ', response.body.message || response.body.msg); } - if (!debugMode && msg) expect(response.body.msg).to.equal(msg); + if (!debugMode && msg) expect(response.body.message || response.body.msg).to.equal(msg); return response; } @@ -248,10 +248,10 @@ async function ncAxiosLinkAdd({ // print error codes if (debugMode && status !== 201) { - console.log('#### ', response.body.msg); + console.log('#### ', response.body.message || response.body.msg); } - if (!debugMode && msg) expect(response.body.msg).to.equal(msg); + if (!debugMode && msg) expect(response.body.message || response.body.msg).to.equal(msg); return response; } @@ -274,9 +274,9 @@ async function ncAxiosLinkRemove({ // print error codes if (debugMode && status !== 200) { - console.log('#### ', response.body.msg); + console.log('#### ', response.body.message || response.body.msg); } - if (!debugMode && msg) expect(response.body.msg).to.equal(msg); + if (!debugMode && msg) expect(response.body.message || response.body.msg).to.equal(msg); return response; } @@ -831,7 +831,7 @@ function textBased() { query: { viewId: '123456789', }, - status: 422, + status: 404, }); }); @@ -883,10 +883,10 @@ function textBased() { query: { offset: 10000, }, - status: 400, + status: 422, }); - expect(rsp.body.msg).to.equal( - 'Offset is beyond the total number of records', + expect(rsp.body.message).to.equal( + "Offset value '10000' is invalid", ); }); @@ -897,7 +897,7 @@ function textBased() { query: { sort: 'abc', }, - status: 422, + status: 404, }); await ncAxiosGet({ query: { @@ -909,7 +909,7 @@ function textBased() { query: { fields: 'abc', }, - status: 422, + status: 404, }); }); @@ -1079,7 +1079,7 @@ function textBased() { // Invalid row ID await ncAxiosPatch({ body: { Id: 123456789, SingleLineText: 'some text' }, - status: 422, + status: 404, }); }); @@ -1126,7 +1126,7 @@ function textBased() { status: unauthorizedResponse, }); // Invalid row ID - await ncAxiosDelete({ body: { Id: '123456789' }, status: 422 }); + await ncAxiosDelete({ body: { Id: '123456789' }, status: 404 }); }); } @@ -2380,7 +2380,7 @@ function linkBased() { ...validParams, urlParams: { ...validParams.urlParams, linkId: 9999 }, status: 404, - msg: "Column with id '9999' not found", + msg: "Field '9999' not found", }); // Link Add: Invalid Source row ID @@ -2389,7 +2389,7 @@ function linkBased() { ...validParams, urlParams: { ...validParams.urlParams, rowId: 9999 }, status: 404, - msg: "Record with id '9999' not found", + msg: "Record '9999' not found", }); // Body parameter error @@ -2411,8 +2411,8 @@ function linkBased() { await ncAxiosLinkAdd({ ...validParams, body: [999, 998], - status: 422, - msg: 'Child record with id [999] not found', + status: 404, + msg: 'Record \'999\' not found', }); } else { // Link Add: Invalid body parameter - row id invalid @@ -2421,8 +2421,8 @@ function linkBased() { await ncAxiosLinkAdd({ ...validParams, body: [999, 998, 997], - status: 422, - msg: 'Child record with id [999, 998, 997] not found', + status: 404, + msg: 'Records \'999, 998, 997\' not found', }); // Link Add: Invalid body parameter - repeated row id @@ -2432,7 +2432,7 @@ function linkBased() { ...validParams, body: [1, 2, 1, 2], status: 422, - msg: 'Child record with id [1, 2] are duplicated', + msg: "Records '1, 2' already exists", }); } } @@ -2452,7 +2452,7 @@ function linkBased() { ...validParams, urlParams: { ...validParams.urlParams, linkId: 9999 }, status: 404, - msg: "Column with id '9999' not found", + msg: "Field '9999' not found", }); // Link Remove: Invalid Source row ID @@ -2461,7 +2461,7 @@ function linkBased() { ...validParams, urlParams: { ...validParams.urlParams, rowId: 9999 }, status: 404, - msg: "Record with id '9999' not found", + msg: "Record '9999' not found", }); // Body parameter error @@ -2493,8 +2493,8 @@ function linkBased() { await ncAxiosLinkRemove({ ...validParams, body: [999, 998], - status: 422, - msg: 'Child record with id [999, 998] not found', + status: 404, + msg: 'Records \'999, 998\' not found', }); // Link Remove: Invalid body parameter - repeated row id @@ -2504,7 +2504,7 @@ function linkBased() { ...validParams, body: [1, 2, 1, 2], status: 422, - msg: 'Child record with id [1, 2] are duplicated', + msg: "Records '1, 2' already exists", }); } } @@ -2524,7 +2524,7 @@ function linkBased() { ...validParams, urlParams: { ...validParams.urlParams, linkId: 9999 }, status: 404, - msg: "Column with id '9999' not found", + msg: "Field '9999' not found", }); // Link List: Invalid Source row ID @@ -2533,7 +2533,7 @@ function linkBased() { ...validParams, urlParams: { ...validParams.urlParams, rowId: 9999 }, status: 404, - msg: "Record with id '9999' not found", + msg: "Record '9999' not found", }); // Query parameter error @@ -2566,7 +2566,7 @@ function linkBased() { ...validParams, query: { ...validParams.query, offset: 9999 }, // for BT relation we use btRead so we don't apply offset & limit, also we don't return page info where this check is done - status: relationType === 'bt' ? 200 : 400, + status: relationType === 'bt' ? 200 : 422, }); // Link List: Invalid query parameter - negative limit diff --git a/packages/nocodb/tests/unit/rest/tests/tableRow.test.ts b/packages/nocodb/tests/unit/rest/tests/tableRow.test.ts index 09fb83cc27..c1465d757c 100644 --- a/packages/nocodb/tests/unit/rest/tests/tableRow.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/tableRow.test.ts @@ -211,7 +211,7 @@ function tableStaticTest() { }) .expect(404); - if (response.body.msg !== 'Table not found') + if (response.body.message !== "Table 'wrong-table-id' not found") throw new Error('Wrong error message'); }); it('Find one sorted table data list with required columns', async function () { @@ -426,7 +426,7 @@ function tableStaticTest() { .set('xc-auth', context.token) .expect(404); - if (response.body['msg'] !== 'Table not found') { + if (response.body.message !== "Table 'wrong-id' not found") { throw new Error('Wrong error message'); } }); @@ -500,7 +500,7 @@ function tableStaticTest() { .set('xc-auth', context.token) .expect(404); - if (response.body['msg'] !== 'Table not found') { + if (response.body.message !== "Table 'invalid-table-id' not found") { console.log(response.body); throw new Error('Wrong error message'); } @@ -518,7 +518,7 @@ function tableStaticTest() { .set('xc-auth', context.token) .expect(404); - if (response.body['msg'] !== 'Table not found') { + if (response.body.message !== "Table 'invalid-table-id' not found") { throw new Error('Wrong error message'); } }); @@ -535,7 +535,7 @@ function tableStaticTest() { .set('xc-auth', context.token) .expect(404); - if (response.body['msg'] !== 'Column not found') { + if (response.body.message !== `Field '${firstNameColumn.id}' not found`) { console.log(response.body); throw new Error('Wrong error message'); } @@ -552,10 +552,10 @@ function tableStaticTest() { .expect(404); if ( - response.body.msg !== "Column with id/name 'invalid-column' is not found" + response.body.message !== "Field 'invalid-column' not found" ) { console.log(response.body); - throw new Error('Should error out'); + throw new Error('Wrong error message'); } }); it('List hm with non ltar column', async () => { @@ -2065,7 +2065,7 @@ function tableTest() { .expect(404); if ( - response.body.msg !== "Column with id/name 'invalid-column' is not found" + response.body.message !== "Field 'invalid-column' not found" ) { console.log(response.body); throw new Error('Should error out'); @@ -2089,7 +2089,7 @@ function tableTest() { .set('xc-auth', context.token) .expect(404); - if (response.body['msg'] !== 'Column not found') { + if (response.body.message !== `Field '${firstNameColumn.id}' not found`) { console.log(response.body); throw new Error('Wrong error message'); } @@ -2291,8 +2291,8 @@ function tableTest() { .set('xc-auth', context.token) .expect(404); - if (response.body['msg'] !== 'Table not found') { - console.log(response.body['msg']); + if (response.body.message !== "Table 'invalid-table-id' not found") { + console.log(response.body['message']); throw new Error('Wrong error message'); } }); @@ -2313,8 +2313,8 @@ function tableTest() { .set('xc-auth', context.token) .expect(404); - if (response.body['msg'] !== 'Table not found') { - console.log(response.body['msg']); + if (response.body.message !== "Table 'invalid-table-id' not found") { + console.log(response.body['message']); throw new Error('Wrong error message'); } });