|
|
@ -20,6 +20,7 @@ import Validator from 'validator'; |
|
|
|
import { customAlphabet } from 'nanoid'; |
|
|
|
import { customAlphabet } from 'nanoid'; |
|
|
|
import DOMPurify from 'isomorphic-dompurify'; |
|
|
|
import DOMPurify from 'isomorphic-dompurify'; |
|
|
|
import { v4 as uuidv4 } from 'uuid'; |
|
|
|
import { v4 as uuidv4 } from 'uuid'; |
|
|
|
|
|
|
|
import { Logger } from '@nestjs/common'; |
|
|
|
import type { SortType } from 'nocodb-sdk'; |
|
|
|
import type { SortType } from 'nocodb-sdk'; |
|
|
|
import type { Knex } from 'knex'; |
|
|
|
import type { Knex } from 'knex'; |
|
|
|
import type LookupColumn from '~/models/LookupColumn'; |
|
|
|
import type LookupColumn from '~/models/LookupColumn'; |
|
|
@ -75,6 +76,8 @@ dayjs.extend(utc); |
|
|
|
|
|
|
|
|
|
|
|
dayjs.extend(timezone); |
|
|
|
dayjs.extend(timezone); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const logger = new Logger('BaseModelSqlv2'); |
|
|
|
|
|
|
|
|
|
|
|
const GROUP_COL = '__nc_group_id'; |
|
|
|
const GROUP_COL = '__nc_group_id'; |
|
|
|
|
|
|
|
|
|
|
|
const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14); |
|
|
|
const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14); |
|
|
@ -220,7 +223,7 @@ class BaseModelSqlv2 { |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) |
|
|
|
if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) |
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
console.log(e); |
|
|
|
logger.log(e); |
|
|
|
return this.readByPk(id, true); |
|
|
|
return this.readByPk(id, true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -295,7 +298,7 @@ class BaseModelSqlv2 { |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) |
|
|
|
if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) |
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
console.log(e); |
|
|
|
logger.log(e); |
|
|
|
return this.findOne(args, true); |
|
|
|
return this.findOne(args, true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -430,7 +433,7 @@ class BaseModelSqlv2 { |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) |
|
|
|
if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) |
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
console.log(e); |
|
|
|
logger.log(e); |
|
|
|
return this.list(args, { |
|
|
|
return this.list(args, { |
|
|
|
ignoreViewFilterAndSort, |
|
|
|
ignoreViewFilterAndSort, |
|
|
|
ignorePagination, |
|
|
|
ignorePagination, |
|
|
@ -654,7 +657,7 @@ class BaseModelSqlv2 { |
|
|
|
sanitize(column.id), |
|
|
|
sanitize(column.id), |
|
|
|
]); |
|
|
|
]); |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
logger.log(e); |
|
|
|
// return dummy select
|
|
|
|
// return dummy select
|
|
|
|
selectQb = this.dbDriver.raw(`'ERR' as ??`, [ |
|
|
|
selectQb = this.dbDriver.raw(`'ERR' as ??`, [ |
|
|
|
sanitize(column.id), |
|
|
|
sanitize(column.id), |
|
|
@ -874,7 +877,7 @@ class BaseModelSqlv2 { |
|
|
|
sanitize(column.id), |
|
|
|
sanitize(column.id), |
|
|
|
]); |
|
|
|
]); |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
logger.log(e); |
|
|
|
// return dummy select
|
|
|
|
// return dummy select
|
|
|
|
selectQb = this.dbDriver.raw(`'ERR' as ??`, [ |
|
|
|
selectQb = this.dbDriver.raw(`'ERR' as ??`, [ |
|
|
|
sanitize(column.id), |
|
|
|
sanitize(column.id), |
|
|
@ -1046,8 +1049,7 @@ class BaseModelSqlv2 { |
|
|
|
GROUP_COL, |
|
|
|
GROUP_COL, |
|
|
|
); |
|
|
|
); |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
logger.error(e); |
|
|
|
throw e; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1114,7 +1116,6 @@ class BaseModelSqlv2 { |
|
|
|
|
|
|
|
|
|
|
|
return children.map(({ count }) => count); |
|
|
|
return children.map(({ count }) => count); |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -1178,7 +1179,6 @@ class BaseModelSqlv2 { |
|
|
|
return c; |
|
|
|
return c; |
|
|
|
}); |
|
|
|
}); |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -1219,7 +1219,6 @@ class BaseModelSqlv2 { |
|
|
|
return (await this.execAndParse(query, null, { raw: true, first: true })) |
|
|
|
return (await this.execAndParse(query, null, { raw: true, first: true })) |
|
|
|
?.count; |
|
|
|
?.count; |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -2319,7 +2318,7 @@ class BaseModelSqlv2 { |
|
|
|
]), |
|
|
|
]), |
|
|
|
); |
|
|
|
); |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
logger.log(e); |
|
|
|
// return dummy select
|
|
|
|
// return dummy select
|
|
|
|
qb.select( |
|
|
|
qb.select( |
|
|
|
this.dbDriver.raw(`'ERR' as ??`, [sanitize(column.id)]), |
|
|
|
this.dbDriver.raw(`'ERR' as ??`, [sanitize(column.id)]), |
|
|
@ -2496,7 +2495,6 @@ class BaseModelSqlv2 { |
|
|
|
await this.afterInsert(response, trx, cookie); |
|
|
|
await this.afterInsert(response, trx, cookie); |
|
|
|
return Array.isArray(response) ? response[0] : response; |
|
|
|
return Array.isArray(response) ? response[0] : response; |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
await this.errorInsert(e, data, trx, cookie); |
|
|
|
await this.errorInsert(e, data, trx, cookie); |
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
@ -2579,7 +2577,6 @@ class BaseModelSqlv2 { |
|
|
|
await this.afterDelete(data, trx, cookie); |
|
|
|
await this.afterDelete(data, trx, cookie); |
|
|
|
return response; |
|
|
|
return response; |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
if (!_trx) await trx.rollback(); |
|
|
|
if (!_trx) await trx.rollback(); |
|
|
|
await this.errorDelete(e, id, trx, cookie); |
|
|
|
await this.errorDelete(e, id, trx, cookie); |
|
|
|
throw e; |
|
|
|
throw e; |
|
|
@ -2681,7 +2678,6 @@ class BaseModelSqlv2 { |
|
|
|
await this.afterUpdate(prevData, newData, trx, cookie, updateObj); |
|
|
|
await this.afterUpdate(prevData, newData, trx, cookie, updateObj); |
|
|
|
return newData; |
|
|
|
return newData; |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
await this.errorUpdate(e, data, trx, cookie); |
|
|
|
await this.errorUpdate(e, data, trx, cookie); |
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
@ -2869,7 +2865,6 @@ class BaseModelSqlv2 { |
|
|
|
|
|
|
|
|
|
|
|
return response; |
|
|
|
return response; |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -3540,7 +3535,6 @@ class BaseModelSqlv2 { |
|
|
|
return res; |
|
|
|
return res; |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
if (transaction) await transaction.rollback(); |
|
|
|
if (transaction) await transaction.rollback(); |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -4474,7 +4468,6 @@ class BaseModelSqlv2 { |
|
|
|
|
|
|
|
|
|
|
|
return r; |
|
|
|
return r; |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -5719,7 +5712,6 @@ class BaseModelSqlv2 { |
|
|
|
} |
|
|
|
} |
|
|
|
return parent; |
|
|
|
return parent; |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.log(e); |
|
|
|
|
|
|
|
throw e; |
|
|
|
throw e; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -5767,19 +5759,19 @@ class BaseModelSqlv2 { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async prepareNocoData(data, isInsertData = false, cookie?: { user?: any }) { |
|
|
|
async prepareNocoData(data, isInsertData = false, cookie?: { user?: any }) { |
|
|
|
|
|
|
|
for (const column of this.model.columns) { |
|
|
|
if ( |
|
|
|
if ( |
|
|
|
this.model.columns.some((c) => |
|
|
|
![ |
|
|
|
[ |
|
|
|
|
|
|
|
UITypes.Attachment, |
|
|
|
UITypes.Attachment, |
|
|
|
UITypes.User, |
|
|
|
UITypes.User, |
|
|
|
UITypes.CreatedTime, |
|
|
|
UITypes.CreatedTime, |
|
|
|
UITypes.LastModifiedTime, |
|
|
|
UITypes.LastModifiedTime, |
|
|
|
UITypes.CreatedBy, |
|
|
|
UITypes.CreatedBy, |
|
|
|
UITypes.LastModifiedBy, |
|
|
|
UITypes.LastModifiedBy, |
|
|
|
].includes(c.uidt), |
|
|
|
].includes(column.uidt) |
|
|
|
) |
|
|
|
) |
|
|
|
) { |
|
|
|
continue; |
|
|
|
for (const column of this.model.columns) { |
|
|
|
|
|
|
|
if (column.system) { |
|
|
|
if (column.system) { |
|
|
|
if (isInsertData) { |
|
|
|
if (isInsertData) { |
|
|
|
if (column.uidt === UITypes.CreatedTime) { |
|
|
|
if (column.uidt === UITypes.CreatedTime) { |
|
|
@ -5817,7 +5809,10 @@ class BaseModelSqlv2 { |
|
|
|
if (data[column.column_name]) { |
|
|
|
if (data[column.column_name]) { |
|
|
|
const userIds = []; |
|
|
|
const userIds = []; |
|
|
|
|
|
|
|
|
|
|
|
if (typeof data[column.column_name] === 'string') { |
|
|
|
if ( |
|
|
|
|
|
|
|
typeof data[column.column_name] === 'string' && |
|
|
|
|
|
|
|
/^\s*[{[]$/.test(data[column.column_name]) |
|
|
|
|
|
|
|
) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
data[column.column_name] = JSON.parse(data[column.column_name]); |
|
|
|
data[column.column_name] = JSON.parse(data[column.column_name]); |
|
|
|
} catch (e) {} |
|
|
|
} catch (e) {} |
|
|
@ -5828,35 +5823,7 @@ class BaseModelSqlv2 { |
|
|
|
include_ws_deleted: false, |
|
|
|
include_ws_deleted: false, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (typeof data[column.column_name] === 'string') { |
|
|
|
if (typeof data[column.column_name] === 'object') { |
|
|
|
const users = data[column.column_name] |
|
|
|
|
|
|
|
.split(',') |
|
|
|
|
|
|
|
.map((u) => u.trim()); |
|
|
|
|
|
|
|
for (const user of users) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (user.length === 0) continue; |
|
|
|
|
|
|
|
if (user.includes('@')) { |
|
|
|
|
|
|
|
const u = baseUsers.find((u) => u.email === user); |
|
|
|
|
|
|
|
if (!u) { |
|
|
|
|
|
|
|
NcError.unprocessableEntity( |
|
|
|
|
|
|
|
`User with email '${user}' is not part of this workspace`, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
userIds.push(u.id); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
const u = baseUsers.find((u) => u.id === user); |
|
|
|
|
|
|
|
if (!u) { |
|
|
|
|
|
|
|
NcError.unprocessableEntity( |
|
|
|
|
|
|
|
`User with id '${user}' is not part of this workspace`, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
userIds.push(u.id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
NcError.unprocessableEntity(e.message); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
const users: { id?: string; email?: string }[] = Array.isArray( |
|
|
|
const users: { id?: string; email?: string }[] = Array.isArray( |
|
|
|
data[column.column_name], |
|
|
|
data[column.column_name], |
|
|
|
) |
|
|
|
) |
|
|
@ -5894,6 +5861,39 @@ class BaseModelSqlv2 { |
|
|
|
NcError.unprocessableEntity(e.message); |
|
|
|
NcError.unprocessableEntity(e.message); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else if (typeof data[column.column_name] === 'string') { |
|
|
|
|
|
|
|
const users = data[column.column_name] |
|
|
|
|
|
|
|
.split(',') |
|
|
|
|
|
|
|
.map((u) => u.trim()); |
|
|
|
|
|
|
|
for (const user of users) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (user.length === 0) continue; |
|
|
|
|
|
|
|
if (user.includes('@')) { |
|
|
|
|
|
|
|
const u = baseUsers.find((u) => u.email === user); |
|
|
|
|
|
|
|
if (!u) { |
|
|
|
|
|
|
|
NcError.unprocessableEntity( |
|
|
|
|
|
|
|
`User with email '${user}' is not part of this workspace`, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
userIds.push(u.id); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
const u = baseUsers.find((u) => u.id === user); |
|
|
|
|
|
|
|
if (!u) { |
|
|
|
|
|
|
|
NcError.unprocessableEntity( |
|
|
|
|
|
|
|
`User with id '${user}' is not part of this workspace`, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
userIds.push(u.id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
NcError.unprocessableEntity(e.message); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
logger.error( |
|
|
|
|
|
|
|
`${data[column.column_name]} is not a valid user input`, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
NcError.unprocessableEntity('Invalid user object'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (userIds.length === 0) { |
|
|
|
if (userIds.length === 0) { |
|
|
@ -5923,7 +5923,6 @@ class BaseModelSqlv2 { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function extractSortsObject( |
|
|
|
export function extractSortsObject( |
|
|
|