Browse Source

Merge pull request #2377 from nocodb/develop

pull/2378/head 0.91.10
github-actions[bot] 2 years ago committed by GitHub
parent
commit
9bc11ff4be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 38
      packages/nc-gui/components/import/templateParsers/ExcelTemplateAdapter.js
  2. 296
      packages/nocodb/src/lib/meta/api/sync/helpers/job.ts
  3. 5
      packages/nocodb/src/lib/models/Project.ts
  4. 12
      packages/nocodb/src/lib/models/User.ts

38
packages/nc-gui/components/import/templateParsers/ExcelTemplateAdapter.js

@ -46,25 +46,27 @@ export default class ExcelTemplateAdapter extends TemplateGenerator {
this.data[tn] = [] this.data[tn] = []
const ws = this.wb.Sheets[sheet] const ws = this.wb.Sheets[sheet]
const range = XLSX.utils.decode_range(ws['!ref']) const range = XLSX.utils.decode_range(ws['!ref'])
const originalRows = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, cellDates: true, defval: null }) const rows = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, cellDates: true, defval: null })
// fix precision bug & timezone offset issues introduced by xlsx if (this.name.slice(-3) !== 'csv') {
const basedate = new Date(1899, 11, 30, 0, 0, 0) // fix precision bug & timezone offset issues introduced by xlsx
// number of milliseconds since base date const basedate = new Date(1899, 11, 30, 0, 0, 0)
const dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000 // number of milliseconds since base date
// number of milliseconds in a day const dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000
const day_ms = 24 * 60 * 60 * 1000 // number of milliseconds in a day
// handle date1904 property const day_ms = 24 * 60 * 60 * 1000
const fixImportedDate = (date) => { // handle date1904 property
const parsed = XLSX.SSF.parse_date_code((date.getTime() - dnthresh) / day_ms, { const fixImportedDate = (date) => {
date1904: this.wb.Workbook.WBProps.date1904 const parsed = XLSX.SSF.parse_date_code((date.getTime() - dnthresh) / day_ms, {
}) date1904: this.wb.Workbook.WBProps.date1904
return new Date(parsed.y, parsed.m, parsed.d, parsed.H, parsed.M, parsed.S) })
return new Date(parsed.y, parsed.m, parsed.d, parsed.H, parsed.M, parsed.S)
}
// fix imported date
rows = rows.map(r => r.map((v) => {
return v instanceof Date ? fixImportedDate(v) : v
}))
} }
// fix imported date
const rows = originalRows.map(r => r.map((v) => {
return v instanceof Date ? fixImportedDate(v) : v
}))
const columnNameRowExist = +rows[0].every(v => v === null || typeof v === 'string') const columnNameRowExist = +rows[0].every(v => v === null || typeof v === 'string')

296
packages/nocodb/src/lib/meta/api/sync/helpers/job.ts

@ -28,7 +28,7 @@ export default async (
ncId: ncId, ncId: ncId,
ncParent: parent, ncParent: parent,
// name added to assist in quick debug // name added to assist in quick debug
ncName: ncName ncName: ncName,
}; };
}, },
@ -45,7 +45,7 @@ export default async (
// get nc-title from airtable ID // get nc-title from airtable ID
getNcNameFromAtId(aId) { getNcNameFromAtId(aId) {
return this.mapTbl[aId]?.ncName; return this.mapTbl[aId]?.ncName;
} },
}; };
function logBasic(log) { function logBasic(log) {
@ -99,20 +99,20 @@ export default async (
total: 0, total: 0,
grid: 0, grid: 0,
gallery: 0, gallery: 0,
form: 0 form: 0,
}, },
fetchAt: { fetchAt: {
count: 0, count: 0,
time: 0 time: 0,
}, },
migrationSkipLog: { migrationSkipLog: {
count: 0, count: 0,
log: [] log: [],
}, },
data: { data: {
records: 0, records: 0,
nestedLinks: 0 nestedLinks: 0,
} },
}; };
function updateMigrationSkipLog(tbl, col, type, reason?) { function updateMigrationSkipLog(tbl, col, type, reason?) {
@ -131,7 +131,7 @@ export default async (
if (!sDB.shareId) if (!sDB.shareId)
throw { throw {
message: message:
'Invalid Shared Base ID :: Ensure www.airtable.com/<SharedBaseID> is accessible. Refer https://bit.ly/3x0OdXI for details' 'Invalid Shared Base ID :: Ensure www.airtable.com/<SharedBaseID> is accessible. Refer https://bit.ly/3x0OdXI for details',
}; };
if (sDB.shareId.startsWith('exp')) { if (sDB.shareId.startsWith('exp')) {
@ -167,6 +167,10 @@ export default async (
return ft.view; return ft.view;
} }
function getRootDbType() {
return ncCreatedProjectSchema?.bases[0]?.type;
}
// base mapping table // base mapping table
const aTblNcTypeMap = { const aTblNcTypeMap = {
foreignKey: UITypes.LinkToAnotherRecord, foreignKey: UITypes.LinkToAnotherRecord,
@ -189,7 +193,7 @@ export default async (
lookup: UITypes.Lookup, lookup: UITypes.Lookup,
autoNumber: UITypes.AutoNumber, autoNumber: UITypes.AutoNumber,
barcode: UITypes.Barcode, barcode: UITypes.Barcode,
button: UITypes.Button button: UITypes.Button,
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -211,15 +215,20 @@ export default async (
const col_alias = name.trim().replace(/\./g, '_'); const col_alias = name.trim().replace(/\./g, '_');
// check if already a column exists with same name? // check if already a column exists with same name?
const duplicateColumn = table.columns.find(x => x.title === col_alias); const duplicateTitle = table.columns.find(
if (duplicateColumn) { (x) => x.title?.toLowerCase() === col_alias?.toLowerCase()
if (enableErrorLogs) console.log(`## Duplicate ${col_alias}`); );
const duplicateColumn = table.columns.find(
(x) => x.column_name?.toLowerCase() === col_name?.toLowerCase()
);
if (duplicateTitle) {
if (enableErrorLogs) console.log(`## Duplicate title ${col_alias}`);
} }
return { return {
// kludge: error observed in Nc with space around column-name // kludge: error observed in Nc with space around column-name
title: col_alias + (duplicateColumn ? '_2' : ''), title: col_alias + (duplicateTitle ? '_2' : ''),
column_name: col_name + (duplicateColumn ? '_2' : '') column_name: col_name + (duplicateColumn ? '_2' : ''),
}; };
} }
@ -227,15 +236,15 @@ export default async (
// //
// @ts-ignore // @ts-ignore
function aTbl_getTableName(tblId) { function aTbl_getTableName(tblId) {
const sheetObj = g_aTblSchema.find(tbl => tbl.id === tblId); const sheetObj = g_aTblSchema.find((tbl) => tbl.id === tblId);
return { return {
tn: sheetObj.name tn: sheetObj.name,
}; };
} }
const ncSchema = { const ncSchema = {
tables: [], tables: [],
tablesById: {} tablesById: {},
}; };
// aTbl: retrieve column name from column ID // aTbl: retrieve column name from column ID
@ -243,11 +252,11 @@ export default async (
function aTbl_getColumnName(colId): any { function aTbl_getColumnName(colId): any {
for (let i = 0; i < g_aTblSchema.length; i++) { for (let i = 0; i < g_aTblSchema.length; i++) {
const sheetObj = g_aTblSchema[i]; const sheetObj = g_aTblSchema[i];
const column = sheetObj.columns.find(col => col.id === colId); const column = sheetObj.columns.find((col) => col.id === colId);
if (column !== undefined) if (column !== undefined)
return { return {
tn: sheetObj.name, tn: sheetObj.name,
cn: column.name cn: column.name,
}; };
} }
} }
@ -282,7 +291,7 @@ export default async (
// not migrated column, skip // not migrated column, skip
if (ncColId === undefined || ncTblId === undefined) return 0; if (ncColId === undefined || ncTblId === undefined) return 0;
return ncSchema.tablesById[ncTblId].columns.find(x => x.id === ncColId); return ncSchema.tablesById[ncTblId].columns.find((x) => x.id === ncColId);
} }
// retrieve nc table schema using table name // retrieve nc table schema using table name
@ -294,12 +303,12 @@ export default async (
// let ncTbl = await api.dbTable.read(ncTblId); // let ncTbl = await api.dbTable.read(ncTblId);
// return ncTbl; // return ncTbl;
return ncSchema.tables.find(x => x.title === tableName); return ncSchema.tables.find((x) => x.title === tableName);
} }
// delete project if already exists // delete project if already exists
async function init({ async function init({
projectName projectName,
}: { }: {
projectName?: string; projectName?: string;
projectId?: string; projectId?: string;
@ -307,7 +316,7 @@ export default async (
// delete 'sample' project if already exists // delete 'sample' project if already exists
const x = await api.project.list(); const x = await api.project.list();
const sampleProj = x.list.find(a => a.title === projectName); const sampleProj = x.list.find((a) => a.title === projectName);
if (sampleProj) { if (sampleProj) {
await api.project.delete(sampleProj.id); await api.project.delete(sampleProj.id);
} }
@ -386,7 +395,7 @@ export default async (
// const csvOpt = "'" + opt.join("','") + "'"; // const csvOpt = "'" + opt.join("','") + "'";
const optSansDuplicate = [...new Set(opt)]; const optSansDuplicate = [...new Set(opt)];
const csvOpt = optSansDuplicate const csvOpt = optSansDuplicate
.map(v => `'${v.replace(/'/g, "\\'").replace(/,/g, '.')}'`) .map((v) => `'${v.replace(/'/g, "\\'").replace(/,/g, '.')}'`)
.join(','); .join(',');
return { type: 'select', data: csvOpt }; return { type: 'select', data: csvOpt };
} }
@ -433,15 +442,15 @@ export default async (
column_name: ncSysFields.id, column_name: ncSysFields.id,
uidt: UITypes.ID, uidt: UITypes.ID,
meta: { meta: {
ag: 'nc' ag: 'nc',
} },
}, },
{ {
title: ncSysFields.hash, title: ncSysFields.hash,
column_name: ncSysFields.hash, column_name: ncSysFields.hash,
uidt: UITypes.SingleLineText, uidt: UITypes.SingleLineText,
system: true system: true,
} },
]; ];
for (let j = 0; j < tblSchema[i].columns.length; j++) { for (let j = 0; j < tblSchema[i].columns.length; j++) {
@ -458,7 +467,7 @@ export default async (
// Enable to use aTbl identifiers as is: id: col.id, // Enable to use aTbl identifiers as is: id: col.id,
title: ncName.title, title: ncName.title,
column_name: uniqueColNameGen(ncName.column_name), column_name: uniqueColNameGen(ncName.column_name),
uidt: getNocoType(col) uidt: getNocoType(col),
}; };
// not supported datatype: pure formula field // not supported datatype: pure formula field
@ -484,6 +493,15 @@ export default async (
// for single line text column type // for single line text column type
if (col.type === 'text') ncCol.dt = 'text'; if (col.type === 'text') ncCol.dt = 'text';
// #fix-2363-decimal-out-of-range
if (['sqlite3', 'mysql2'].includes(getRootDbType())) {
if (ncCol.uidt === UITypes.Decimal) {
ncCol.dt = 'double';
ncCol.dtxp = 22;
ncCol.dtxs = '2';
}
}
// additional column parameters when applicable // additional column parameters when applicable
const colOptions = getNocoTypeOptions(col); const colOptions = getNocoTypeOptions(col);
@ -528,7 +546,8 @@ export default async (
await sMap.addToMappingTbl(aTblSchema[idx].id, table.id, table.title); await sMap.addToMappingTbl(aTblSchema[idx].id, table.id, table.title);
for (let colIdx = 0; colIdx < table.columns.length; colIdx++) { for (let colIdx = 0; colIdx < table.columns.length; colIdx++) {
const aId = aTblSchema[idx].columns.find( const aId = aTblSchema[idx].columns.find(
x => x.name.trim().replace(/\./g, '_') === table.columns[colIdx].title (x) =>
x.name.trim().replace(/\./g, '_') === table.columns[colIdx].title
)?.id; )?.id;
if (aId) if (aId)
await sMap.addToMappingTbl( await sMap.addToMappingTbl(
@ -545,11 +564,11 @@ export default async (
const view = await api.dbView.list(table.id); const view = await api.dbView.list(table.id);
recordPerfStats(_perfStart, 'dbView.list'); recordPerfStats(_perfStart, 'dbView.list');
const aTbl_grid = aTblSchema[idx].views.find(x => x.type === 'grid'); const aTbl_grid = aTblSchema[idx].views.find((x) => x.type === 'grid');
logDetailed(`NC API: dbView.update ${view.list[0].id} ${aTbl_grid.name}`); logDetailed(`NC API: dbView.update ${view.list[0].id} ${aTbl_grid.name}`);
_perfStart = recordPerfStart(); _perfStart = recordPerfStart();
await api.dbView.update(view.list[0].id, { await api.dbView.update(view.list[0].id, {
title: aTbl_grid.name title: aTbl_grid.name,
}); });
recordPerfStats(_perfStart, 'dbView.update'); recordPerfStats(_perfStart, 'dbView.update');
@ -572,7 +591,7 @@ export default async (
// Link to another RECORD // Link to another RECORD
for (let idx = 0; idx < aTblSchema.length; idx++) { for (let idx = 0; idx < aTblSchema.length; idx++) {
const aTblLinkColumns = aTblSchema[idx].columns.filter( const aTblLinkColumns = aTblSchema[idx].columns.filter(
x => x.type === 'foreignKey' (x) => x.type === 'foreignKey'
); );
// Link columns exist // Link columns exist
@ -639,7 +658,7 @@ export default async (
column_name: ncName.column_name, column_name: ncName.column_name,
parentId: srcTableId, parentId: srcTableId,
childId: childTableId, childId: childTableId,
type: 'mm' type: 'mm',
// aTblLinkColumns[i].typeOptions.relationship === 'many' // aTblLinkColumns[i].typeOptions.relationship === 'many'
// ? 'mm' // ? 'mm'
// : 'hm' // : 'hm'
@ -648,7 +667,9 @@ export default async (
updateNcTblSchema(ncTbl); updateNcTblSchema(ncTbl);
const ncId = ncTbl.columns.find(x => x.title === ncName.title)?.id; const ncId = ncTbl.columns.find(
(x) => x.title === ncName.title
)?.id;
await sMap.addToMappingTbl( await sMap.addToMappingTbl(
aTblLinkColumns[i].id, aTblLinkColumns[i].id,
ncId, ncId,
@ -663,12 +684,12 @@ export default async (
title: ncName.title, title: ncName.title,
parentId: srcTableId, parentId: srcTableId,
childId: childTableId, childId: childTableId,
type: 'mm' type: 'mm',
}, },
aTbl: { aTbl: {
tblId: aTblSchema[idx].id, tblId: aTblSchema[idx].id,
...aTblLinkColumns[i] ...aTblLinkColumns[i],
} },
}; };
ncLinkMappingTable.push(link); ncLinkMappingTable.push(link);
@ -681,7 +702,7 @@ export default async (
// 3. using foreign parent & child column ID, find associated mapping in child table // 3. using foreign parent & child column ID, find associated mapping in child table
// 4. update column name // 4. update column name
const x = ncLinkMappingTable.findIndex( const x = ncLinkMappingTable.findIndex(
x => (x) =>
x.aTbl.tblId === x.aTbl.tblId ===
aTblLinkColumns[i].typeOptions.foreignTableId && aTblLinkColumns[i].typeOptions.foreignTableId &&
x.aTbl.id === aTblLinkColumns[i].typeOptions.symmetricColumnId x.aTbl.id === aTblLinkColumns[i].typeOptions.symmetricColumnId
@ -704,7 +725,7 @@ export default async (
// let parentTblSchema = ncSchema.tablesById[ncLinkMappingTable[x].nc.parentId] // let parentTblSchema = ncSchema.tablesById[ncLinkMappingTable[x].nc.parentId]
let parentLinkColumn = parentTblSchema.columns.find( let parentLinkColumn = parentTblSchema.columns.find(
col => col.title === ncLinkMappingTable[x].nc.title (col) => col.title === ncLinkMappingTable[x].nc.title
); );
if (parentLinkColumn === undefined) { if (parentLinkColumn === undefined) {
@ -720,7 +741,7 @@ export default async (
// hack // fix me // hack // fix me
if (parentLinkColumn.uidt !== 'LinkToAnotherRecord') { if (parentLinkColumn.uidt !== 'LinkToAnotherRecord') {
parentLinkColumn = parentTblSchema.columns.find( parentLinkColumn = parentTblSchema.columns.find(
col => col.title === ncLinkMappingTable[x].nc.title + '_2' (col) => col.title === ncLinkMappingTable[x].nc.title + '_2'
); );
} }
@ -731,7 +752,7 @@ export default async (
// mapping between child & parent column id is direct // mapping between child & parent column id is direct
// //
childLinkColumn = childTblSchema.columns.find( childLinkColumn = childTblSchema.columns.find(
col => (col) =>
col.uidt === UITypes.LinkToAnotherRecord && col.uidt === UITypes.LinkToAnotherRecord &&
col.colOptions.fk_child_column_id === col.colOptions.fk_child_column_id ===
parentLinkColumn.colOptions.fk_child_column_id && parentLinkColumn.colOptions.fk_child_column_id &&
@ -743,7 +764,7 @@ export default async (
// mapping between child & parent column id is inverted // mapping between child & parent column id is inverted
// //
childLinkColumn = childTblSchema.columns.find( childLinkColumn = childTblSchema.columns.find(
col => (col) =>
col.uidt === UITypes.LinkToAnotherRecord && col.uidt === UITypes.LinkToAnotherRecord &&
col.colOptions.fk_child_column_id === col.colOptions.fk_child_column_id ===
parentLinkColumn.colOptions.fk_parent_column_id && parentLinkColumn.colOptions.fk_parent_column_id &&
@ -756,7 +777,7 @@ export default async (
// check if already a column exists with this name? // check if already a column exists with this name?
const duplicate = childTblSchema.columns.find( const duplicate = childTblSchema.columns.find(
x => x.title === aTblLinkColumns[i].name (x) => x.title === aTblLinkColumns[i].name
); );
const suffix = duplicate ? '_2' : ''; const suffix = duplicate ? '_2' : '';
if (duplicate) if (duplicate)
@ -780,7 +801,7 @@ export default async (
{ {
...childLinkColumn, ...childLinkColumn,
title: ncName.title, title: ncName.title,
column_name: ncName.column_name column_name: ncName.column_name,
} }
); );
recordPerfStats(_perfStart, 'dbTableColumn.update'); recordPerfStats(_perfStart, 'dbTableColumn.update');
@ -788,7 +809,7 @@ export default async (
updateNcTblSchema(ncTbl); updateNcTblSchema(ncTbl);
const ncId = ncTbl.columns.find( const ncId = ncTbl.columns.find(
x => x.title === aTblLinkColumns[i].name + suffix (x) => x.title === aTblLinkColumns[i].name + suffix
)?.id; )?.id;
await sMap.addToMappingTbl( await sMap.addToMappingTbl(
aTblLinkColumns[i].id, aTblLinkColumns[i].id,
@ -808,7 +829,7 @@ export default async (
// LookUps // LookUps
for (let idx = 0; idx < aTblSchema.length; idx++) { for (let idx = 0; idx < aTblSchema.length; idx++) {
const aTblColumns = aTblSchema[idx].columns.filter( const aTblColumns = aTblSchema[idx].columns.filter(
x => x.type === 'lookup' (x) => x.type === 'lookup'
); );
// parent table ID // parent table ID
@ -820,8 +841,9 @@ export default async (
// Lookup // Lookup
for (let i = 0; i < aTblColumns.length; i++) { for (let i = 0; i < aTblColumns.length; i++) {
logDetailed( logDetailed(
`[${idx + 1}/${aTblSchema.length}] Configuring Lookup :: [${i + `[${idx + 1}/${aTblSchema.length}] Configuring Lookup :: [${
1}/${aTblColumns.length}] ${aTblSchema[idx].name}` i + 1
}/${aTblColumns.length}] ${aTblSchema[idx].name}`
); );
// something is not right, skip // something is not right, skip
@ -868,14 +890,15 @@ export default async (
title: ncName.title, title: ncName.title,
column_name: ncName.column_name, column_name: ncName.column_name,
fk_relation_column_id: ncRelationColumnId, fk_relation_column_id: ncRelationColumnId,
fk_lookup_column_id: ncLookupColumnId fk_lookup_column_id: ncLookupColumnId,
}); });
recordPerfStats(_perfStart, 'dbTableColumn.create'); recordPerfStats(_perfStart, 'dbTableColumn.create');
updateNcTblSchema(ncTbl); updateNcTblSchema(ncTbl);
const ncId = ncTbl.columns.find(x => x.title === aTblColumns[i].name) const ncId = ncTbl.columns.find(
?.id; (x) => x.title === aTblColumns[i].name
)?.id;
await sMap.addToMappingTbl( await sMap.addToMappingTbl(
aTblColumns[i].id, aTblColumns[i].id,
ncId, ncId,
@ -944,14 +967,14 @@ export default async (
title: ncName.title, title: ncName.title,
column_name: ncName.column_name, column_name: ncName.column_name,
fk_relation_column_id: ncRelationColumnId, fk_relation_column_id: ncRelationColumnId,
fk_lookup_column_id: ncLookupColumnId fk_lookup_column_id: ncLookupColumnId,
}); });
recordPerfStats(_perfStart, 'dbTableColumn.create'); recordPerfStats(_perfStart, 'dbTableColumn.create');
updateNcTblSchema(ncTbl); updateNcTblSchema(ncTbl);
const ncId = ncTbl.columns.find( const ncId = ncTbl.columns.find(
x => x.title === nestedLookupTbl[0].name (x) => x.title === nestedLookupTbl[0].name
)?.id; )?.id;
await sMap.addToMappingTbl( await sMap.addToMappingTbl(
nestedLookupTbl[0].id, nestedLookupTbl[0].id,
@ -983,7 +1006,7 @@ export default async (
MIN: 'min', MIN: 'min',
OR: '', OR: '',
SUM: 'sum', SUM: 'sum',
XOR: '' XOR: '',
}; };
return aTbl_ncRollUp[fn]; return aTbl_ncRollUp[fn];
} }
@ -993,7 +1016,7 @@ export default async (
// Rollup // Rollup
for (let idx = 0; idx < aTblSchema.length; idx++) { for (let idx = 0; idx < aTblSchema.length; idx++) {
const aTblColumns = aTblSchema[idx].columns.filter( const aTblColumns = aTblSchema[idx].columns.filter(
x => x.type === 'rollup' (x) => x.type === 'rollup'
); );
// parent table ID // parent table ID
@ -1005,8 +1028,9 @@ export default async (
// rollup exist // rollup exist
for (let i = 0; i < aTblColumns.length; i++) { for (let i = 0; i < aTblColumns.length; i++) {
logDetailed( logDetailed(
`[${idx + 1}/${aTblSchema.length}] Configuring Rollup :: [${i + `[${idx + 1}/${aTblSchema.length}] Configuring Rollup :: [${
1}/${aTblColumns.length}] ${aTblSchema[idx].name}` i + 1
}/${aTblColumns.length}] ${aTblSchema[idx].name}`
); );
// fetch associated rollup function // fetch associated rollup function
@ -1087,14 +1111,15 @@ export default async (
column_name: ncName.column_name, column_name: ncName.column_name,
fk_relation_column_id: ncRelationColumnId, fk_relation_column_id: ncRelationColumnId,
fk_rollup_column_id: ncRollupColumnId, fk_rollup_column_id: ncRollupColumnId,
rollup_function: ncRollupFn rollup_function: ncRollupFn,
}); });
recordPerfStats(_perfStart, 'dbTableColumn.create'); recordPerfStats(_perfStart, 'dbTableColumn.create');
updateNcTblSchema(ncTbl); updateNcTblSchema(ncTbl);
const ncId = ncTbl.columns.find(x => x.title === aTblColumns[i].name) const ncId = ncTbl.columns.find(
?.id; (x) => x.title === aTblColumns[i].name
)?.id;
await sMap.addToMappingTbl( await sMap.addToMappingTbl(
aTblColumns[i].id, aTblColumns[i].id,
ncId, ncId,
@ -1143,14 +1168,15 @@ export default async (
title: ncName.title, title: ncName.title,
column_name: ncName.column_name, column_name: ncName.column_name,
fk_relation_column_id: ncRelationColumnId, fk_relation_column_id: ncRelationColumnId,
fk_lookup_column_id: ncLookupColumnId fk_lookup_column_id: ncLookupColumnId,
}); });
recordPerfStats(_perfStart, 'dbTableColumn.create'); recordPerfStats(_perfStart, 'dbTableColumn.create');
updateNcTblSchema(ncTbl); updateNcTblSchema(ncTbl);
const ncId = ncTbl.columns.find(x => x.title === nestedLookupTbl[0].name) const ncId = ncTbl.columns.find(
?.id; (x) => x.title === nestedLookupTbl[0].name
)?.id;
await sMap.addToMappingTbl( await sMap.addToMappingTbl(
nestedLookupTbl[0].id, nestedLookupTbl[0].id,
ncId, ncId,
@ -1205,7 +1231,7 @@ export default async (
recordPerfStats(_perfStart, 'dbView.gridColumnsList'); recordPerfStats(_perfStart, 'dbView.gridColumnsList');
} }
return viewDetails.find(x => x.fk_column_id === ncColumnId)?.id; return viewDetails.find((x) => x.fk_column_id === ncColumnId)?.id;
} }
////////// Data processing ////////// Data processing
@ -1217,7 +1243,7 @@ export default async (
// kludge - // kludge -
// trim spaces on either side of column name // trim spaces on either side of column name
// leads to error in NocoDB // leads to error in NocoDB
Object.keys(rec).forEach(key => { Object.keys(rec).forEach((key) => {
const replacedKey = key.trim().replace(/\./g, '_'); const replacedKey = key.trim().replace(/\./g, '_');
if (key !== replacedKey) { if (key !== replacedKey) {
rec[replacedKey] = rec[key]; rec[replacedKey] = rec[key];
@ -1228,7 +1254,7 @@ export default async (
// post-processing on the record // post-processing on the record
for (const [key, value] of Object.entries(rec as { [key: string]: any })) { for (const [key, value] of Object.entries(rec as { [key: string]: any })) {
// retrieve datatype // retrieve datatype
const dt = table.columns.find(x => x.title === key)?.uidt; const dt = table.columns.find((x) => x.title === key)?.uidt;
switch (dt) { switch (dt) {
// https://www.npmjs.com/package/validator // https://www.npmjs.com/package/validator
@ -1245,7 +1271,7 @@ export default async (
if (ncLinkDataStore[table.title][record.id] === undefined) if (ncLinkDataStore[table.title][record.id] === undefined)
ncLinkDataStore[table.title][record.id] = { ncLinkDataStore[table.title][record.id] = {
id: record.id, id: record.id,
fields: {} fields: {},
}; };
ncLinkDataStore[table.title][record.id]['fields'][key] = value; ncLinkDataStore[table.title][record.id]['fields'][key] = value;
} }
@ -1280,9 +1306,7 @@ export default async (
case UITypes.DateTime: case UITypes.DateTime:
case UITypes.CreateTime: case UITypes.CreateTime:
case UITypes.LastModifiedTime: case UITypes.LastModifiedTime:
rec[key] = dayjs(value) rec[key] = dayjs(value).utc().format('YYYY-MM-DD HH:mm');
.utc()
.format('YYYY-MM-DD HH:mm');
break; break;
case UITypes.Date: case UITypes.Date:
@ -1291,9 +1315,7 @@ export default async (
rec[key] = null; rec[key] = null;
logBasic(`:: Invalid date ${value}`); logBasic(`:: Invalid date ${value}`);
} else { } else {
rec[key] = dayjs(value) rec[key] = dayjs(value).utc().format('YYYY-MM-DD');
.utc()
.format('YYYY-MM-DD');
} }
break; break;
@ -1302,7 +1324,7 @@ export default async (
break; break;
case UITypes.MultiSelect: case UITypes.MultiSelect:
rec[key] = value.map(v => `${v.replace(/,/g, '.')}`).join(','); rec[key] = value.map((v) => `${v.replace(/,/g, '.')}`).join(',');
break; break;
case UITypes.Attachment: case UITypes.Attachment:
@ -1313,18 +1335,18 @@ export default async (
try { try {
logBasic( logBasic(
` :: Retrieving attachment :: ${value ` :: Retrieving attachment :: ${value
?.map(a => a.filename?.split('?')?.[0]) ?.map((a) => a.filename?.split('?')?.[0])
.join(', ')}` .join(', ')}`
); );
tempArr = await api.storage.uploadByUrl( tempArr = await api.storage.uploadByUrl(
{ {
path: `noco/${sDB.projectName}/${table.title}/${key}` path: `noco/${sDB.projectName}/${table.title}/${key}`,
}, },
value?.map(attachment => ({ value?.map((attachment) => ({
fileName: attachment.filename?.split('?')?.[0], fileName: attachment.filename?.split('?')?.[0],
url: attachment.url, url: attachment.url,
size: attachment.size, size: attachment.size,
mimetype: attachment.type mimetype: attachment.type,
})) }))
); );
} catch (e) { } catch (e) {
@ -1354,7 +1376,7 @@ export default async (
.select({ .select({
pageSize: 100, pageSize: 100,
// maxRecords: 100, // maxRecords: 100,
fields: fields fields: fields,
}) })
.eachPage( .eachPage(
async function page(records, fetchNextPage) { async function page(records, fetchNextPage) {
@ -1363,11 +1385,12 @@ export default async (
// This function (`page`) will get called for each page of records. // This function (`page`) will get called for each page of records.
// records.forEach(record => callback(table, record)); // records.forEach(record => callback(table, record));
logBasic( logBasic(
`:: ${table.title} / ${fields} : ${recordCnt + `:: ${table.title} / ${fields} : ${
1} ~ ${(recordCnt += 100)}` recordCnt + 1
} ~ ${(recordCnt += 100)}`
); );
await Promise.all( await Promise.all(
records.map(r => callback(projName, table, r, fields)) records.map((r) => callback(projName, table, r, fields))
); );
// To fetch the next page of records, call `fetchNextPage`. // To fetch the next page of records, call `fetchNextPage`.
@ -1390,7 +1413,7 @@ export default async (
function nc_isLinkExists(airtableFieldId) { function nc_isLinkExists(airtableFieldId) {
return !!ncLinkMappingTable.find( return !!ncLinkMappingTable.find(
x => x.aTbl.typeOptions.symmetricColumnId === airtableFieldId (x) => x.aTbl.typeOptions.symmetricColumnId === airtableFieldId
); );
} }
@ -1399,7 +1422,7 @@ export default async (
logDetailed(`Create Project: ${projName}`); logDetailed(`Create Project: ${projName}`);
const _perfStart = recordPerfStart(); const _perfStart = recordPerfStart();
ncCreatedProjectSchema = await api.project.create({ ncCreatedProjectSchema = await api.project.create({
title: projName title: projName,
}); });
recordPerfStats(_perfStart, 'project.create'); recordPerfStats(_perfStart, 'project.create');
} }
@ -1417,7 +1440,7 @@ export default async (
for (let idx = 0; idx < aTblSchema.length; idx++) { for (let idx = 0; idx < aTblSchema.length; idx++) {
const tblId = (await nc_getTableSchema(aTblSchema[idx].name)).id; const tblId = (await nc_getTableSchema(aTblSchema[idx].name)).id;
const galleryViews = aTblSchema[idx].views.filter( const galleryViews = aTblSchema[idx].views.filter(
x => x.type === 'gallery' (x) => x.type === 'gallery'
); );
const configuredViews = rtc.view.grid + rtc.view.gallery + rtc.view.form; const configuredViews = rtc.view.grid + rtc.view.gallery + rtc.view.form;
@ -1429,7 +1452,7 @@ export default async (
// create view // create view
await getViewData(galleryViews[i].id); await getViewData(galleryViews[i].id);
const viewName = aTblSchema[idx].views.find( const viewName = aTblSchema[idx].views.find(
x => x.id === galleryViews[i].id (x) => x.id === galleryViews[i].id
)?.name; )?.name;
logBasic( logBasic(
@ -1455,7 +1478,7 @@ export default async (
if (!sDB.options.syncViews) return; if (!sDB.options.syncViews) return;
for (let idx = 0; idx < aTblSchema.length; idx++) { for (let idx = 0; idx < aTblSchema.length; idx++) {
const tblId = sMap.getNcIdFromAtId(aTblSchema[idx].id); const tblId = sMap.getNcIdFromAtId(aTblSchema[idx].id);
const formViews = aTblSchema[idx].views.filter(x => x.type === 'form'); const formViews = aTblSchema[idx].views.filter((x) => x.type === 'form');
const configuredViews = rtc.view.grid + rtc.view.gallery + rtc.view.form; const configuredViews = rtc.view.grid + rtc.view.gallery + rtc.view.form;
rtc.view.form += formViews.length; rtc.view.form += formViews.length;
@ -1465,7 +1488,7 @@ export default async (
// create view // create view
const vData = await getViewData(formViews[i].id); const vData = await getViewData(formViews[i].id);
const viewName = aTblSchema[idx].views.find( const viewName = aTblSchema[idx].views.find(
x => x.id === formViews[i].id (x) => x.id === formViews[i].id
)?.name; )?.name;
logBasic( logBasic(
@ -1496,7 +1519,7 @@ export default async (
subheading: desc, subheading: desc,
success_msg: msg, success_msg: msg,
submit_another_form: refreshMode.includes('REFRESH_BUTTON'), submit_another_form: refreshMode.includes('REFRESH_BUTTON'),
show_blank_form: refreshMode.includes('AUTO_REFRESH') show_blank_form: refreshMode.includes('AUTO_REFRESH'),
}; };
logDetailed(`NC API dbView.formCreate :: ${viewName}`); logDetailed(`NC API dbView.formCreate :: ${viewName}`);
@ -1527,7 +1550,7 @@ export default async (
async function nocoConfigureGridView(sDB, aTblSchema) { async function nocoConfigureGridView(sDB, aTblSchema) {
for (let idx = 0; idx < aTblSchema.length; idx++) { for (let idx = 0; idx < aTblSchema.length; idx++) {
const tblId = sMap.getNcIdFromAtId(aTblSchema[idx].id); const tblId = sMap.getNcIdFromAtId(aTblSchema[idx].id);
const gridViews = aTblSchema[idx].views.filter(x => x.type === 'grid'); const gridViews = aTblSchema[idx].views.filter((x) => x.type === 'grid');
let viewCnt = idx; let viewCnt = idx;
if (syncDB.options.syncViews) if (syncDB.options.syncViews)
@ -1541,13 +1564,13 @@ export default async (
// retrieve view name & associated NC-ID // retrieve view name & associated NC-ID
const viewName = aTblSchema[idx].views.find( const viewName = aTblSchema[idx].views.find(
x => x.id === gridViews[i].id (x) => x.id === gridViews[i].id
)?.name; )?.name;
const _perfStart = recordPerfStart(); const _perfStart = recordPerfStart();
const viewList: any = await api.dbView.list(tblId); const viewList: any = await api.dbView.list(tblId);
recordPerfStats(_perfStart, 'dbView.list'); recordPerfStats(_perfStart, 'dbView.list');
let ncViewId = viewList?.list?.find(x => x.tn === viewName)?.id; let ncViewId = viewList?.list?.find((x) => x.tn === viewName)?.id;
logBasic( logBasic(
`:: [${viewCnt + i + 1}/${rtc.view.total}] Grid : ${ `:: [${viewCnt + i + 1}/${rtc.view.total}] Grid : ${
@ -1560,7 +1583,7 @@ export default async (
logDetailed(`NC API dbView.gridCreate :: ${viewName}`); logDetailed(`NC API dbView.gridCreate :: ${viewName}`);
const _perfStart = recordPerfStart(); const _perfStart = recordPerfStart();
const viewCreated = await api.dbView.gridCreate(tblId, { const viewCreated = await api.dbView.gridCreate(tblId, {
title: viewName title: viewName,
}); });
recordPerfStats(_perfStart, 'dbView.gridCreate'); recordPerfStats(_perfStart, 'dbView.gridCreate');
@ -1591,7 +1614,7 @@ export default async (
logDetailed(` Configure filter set`); logDetailed(` Configure filter set`);
// skip filters if nested // skip filters if nested
if (!vData.filters.filterSet.find(x => x?.type === 'nested')) { if (!vData.filters.filterSet.find((x) => x?.type === 'nested')) {
await nc_configureFilters(ncViewId, vData.filters); await nc_configureFilters(ncViewId, vData.filters);
} }
} }
@ -1613,7 +1636,7 @@ export default async (
edit: 'editor', edit: 'editor',
comment: 'commenter', comment: 'commenter',
read: 'viewer', read: 'viewer',
none: 'viewer' none: 'viewer',
}; };
const userList = aTblSchema.appBlanket.userInfoById; const userList = aTblSchema.appBlanket.userInfoById;
const totalUsers = Object.keys(userList).length; const totalUsers = Object.keys(userList).length;
@ -1628,10 +1651,16 @@ export default async (
); );
const _perfStart = recordPerfStart(); const _perfStart = recordPerfStart();
insertJobs.push( insertJobs.push(
api.auth.projectUserAdd(ncCreatedProjectSchema.id, { api.auth
email: value.email, .projectUserAdd(ncCreatedProjectSchema.id, {
roles: userRoles[value.permissionLevel] email: value.email,
}) roles: userRoles[value.permissionLevel],
})
.catch((e) =>
e.response?.data?.msg
? logBasic(`NOTICE: ${e.response.data.msg}`)
: console.log(e)
)
); );
recordPerfStats(_perfStart, 'auth.projectUserAdd'); recordPerfStats(_perfStart, 'auth.projectUserAdd');
} }
@ -1642,7 +1671,7 @@ export default async (
const tblId = tblSchema.id; const tblId = tblSchema.id;
// replace entry from array if already exists // replace entry from array if already exists
const idx = ncSchema.tables.findIndex(x => x.id === tblId); const idx = ncSchema.tables.findIndex((x) => x.id === tblId);
if (idx !== -1) ncSchema.tables.splice(idx, 1); if (idx !== -1) ncSchema.tables.splice(idx, 1);
ncSchema.tables.push(tblSchema); ncSchema.tables.push(tblSchema);
@ -1671,27 +1700,27 @@ export default async (
columns: 0, columns: 0,
links: 0, links: 0,
lookup: 0, lookup: 0,
rollup: 0 rollup: 0,
}, },
nc: { nc: {
columns: 0, columns: 0,
links: 0, links: 0,
lookup: 0, lookup: 0,
rollup: 0, rollup: 0,
invalidColumn: 0 invalidColumn: 0,
} },
}; };
for (let idx = 0; idx < aTblSchema.length; idx++) { for (let idx = 0; idx < aTblSchema.length; idx++) {
migrationStatsObj.table_name = aTblSchema[idx].name; migrationStatsObj.table_name = aTblSchema[idx].name;
const aTblLinkColumns = aTblSchema[idx].columns.filter( const aTblLinkColumns = aTblSchema[idx].columns.filter(
x => x.type === 'foreignKey' (x) => x.type === 'foreignKey'
); );
const aTblLookup = aTblSchema[idx].columns.filter( const aTblLookup = aTblSchema[idx].columns.filter(
x => x.type === 'lookup' (x) => x.type === 'lookup'
); );
const aTblRollup = aTblSchema[idx].columns.filter( const aTblRollup = aTblSchema[idx].columns.filter(
x => x.type === 'rollup' (x) => x.type === 'rollup'
); );
let invalidColumnId = 0; let invalidColumnId = 0;
@ -1717,10 +1746,10 @@ export default async (
const ncTbl = await nc_getTableSchema(aTblSchema[idx].name); const ncTbl = await nc_getTableSchema(aTblSchema[idx].name);
const linkColumn = ncTbl.columns.filter( const linkColumn = ncTbl.columns.filter(
x => x.uidt === UITypes.LinkToAnotherRecord (x) => x.uidt === UITypes.LinkToAnotherRecord
); );
const lookup = ncTbl.columns.filter(x => x.uidt === UITypes.Lookup); const lookup = ncTbl.columns.filter((x) => x.uidt === UITypes.Lookup);
const rollup = ncTbl.columns.filter(x => x.uidt === UITypes.Rollup); const rollup = ncTbl.columns.filter((x) => x.uidt === UITypes.Rollup);
// all links hardwired as m2m. m2m generates additional tables per link // all links hardwired as m2m. m2m generates additional tables per link
// hence link/2 // hence link/2
@ -1776,7 +1805,7 @@ export default async (
} }
jsonfile.writeFileSync('stats.csv', perflog, { spaces: 2 }); jsonfile.writeFileSync('stats.csv', perflog, { spaces: 2 });
jsonfile.writeFileSync('skip.txt', rtc.migrationSkipLog.log, { jsonfile.writeFileSync('skip.txt', rtc.migrationSkipLog.log, {
spaces: 2 spaces: 2,
}); });
} }
@ -1796,16 +1825,16 @@ export default async (
total: rtc.view.total, total: rtc.view.total,
grid: rtc.view.grid, grid: rtc.view.grid,
gallery: rtc.view.gallery, gallery: rtc.view.gallery,
form: rtc.view.form form: rtc.view.form,
}, },
axios: { axios: {
count: rtc.fetchAt.count, count: rtc.fetchAt.count,
time: rtc.fetchAt.time time: rtc.fetchAt.time,
}, },
totalRecords: rtc.data.records, totalRecords: rtc.data.records,
nestedLinks: rtc.data.nestedLinks nestedLinks: rtc.data.nestedLinks,
} },
} },
}); });
} }
@ -1824,7 +1853,7 @@ export default async (
contains: 'like', contains: 'like',
doesNotContain: 'nlike', doesNotContain: 'nlike',
isAnyOf: 'eq', isAnyOf: 'eq',
isNoneOf: 'neq' isNoneOf: 'neq',
}; };
async function nc_configureFilters(viewId, f) { async function nc_configureFilters(viewId, f) {
@ -1871,7 +1900,7 @@ export default async (
fk_column_id: columnId, fk_column_id: columnId,
logical_op: f.conjunction, logical_op: f.conjunction,
comparison_op: filterMap[filter.operator], comparison_op: filterMap[filter.operator],
value: sMap.getNcNameFromAtId(filter.value[i]) value: sMap.getNcNameFromAtId(filter.value[i]),
}; };
ncFilters.push(fx); ncFilters.push(fx);
} }
@ -1882,7 +1911,7 @@ export default async (
fk_column_id: columnId, fk_column_id: columnId,
logical_op: f.conjunction, logical_op: f.conjunction,
comparison_op: filterMap[filter.operator], comparison_op: filterMap[filter.operator],
value: sMap.getNcNameFromAtId(filter.value) value: sMap.getNcNameFromAtId(filter.value),
}; };
ncFilters.push(fx); ncFilters.push(fx);
} }
@ -1894,7 +1923,7 @@ export default async (
fk_column_id: columnId, fk_column_id: columnId,
logical_op: f.conjunction, logical_op: f.conjunction,
comparison_op: filterMap[filter.operator], comparison_op: filterMap[filter.operator],
value: filter.value value: filter.value,
}; };
ncFilters.push(fx); ncFilters.push(fx);
} }
@ -1903,7 +1932,7 @@ export default async (
for (let i = 0; i < ncFilters.length; i++) { for (let i = 0; i < ncFilters.length; i++) {
const _perfStart = recordPerfStart(); const _perfStart = recordPerfStart();
await api.dbTableFilter.create(viewId, { await api.dbTableFilter.create(viewId, {
...ncFilters[i] ...ncFilters[i],
}); });
recordPerfStats(_perfStart, 'dbTableFilter.create'); recordPerfStats(_perfStart, 'dbTableFilter.create');
@ -1920,7 +1949,7 @@ export default async (
const _perfStart = recordPerfStart(); const _perfStart = recordPerfStart();
await api.dbTableSort.create(viewId, { await api.dbTableSort.create(viewId, {
fk_column_id: columnId, fk_column_id: columnId,
direction: s.sortSet[i].ascending ? 'asc' : 'dsc' direction: s.sortSet[i].ascending ? 'asc' : 'dsc',
}); });
recordPerfStats(_perfStart, 'dbTableSort.create'); recordPerfStats(_perfStart, 'dbTableSort.create');
} }
@ -1937,7 +1966,7 @@ export default async (
// retrieve table schema // retrieve table schema
const ncTbl = await nc_getTableSchema(tblName); const ncTbl = await nc_getTableSchema(tblName);
// retrieve view ID // retrieve view ID
const viewId = ncTbl.views.find(x => x.title === viewName).id; const viewId = ncTbl.views.find((x) => x.title === viewName).id;
let viewDetails; let viewDetails;
const _perfStart = recordPerfStart(); const _perfStart = recordPerfStart();
@ -1954,10 +1983,11 @@ export default async (
// nc-specific columns; default hide. // nc-specific columns; default hide.
for (let j = 0; j < hiddenColumns.length; j++) { for (let j = 0; j < hiddenColumns.length; j++) {
const ncColumnId = ncTbl.columns.find(x => x.title === hiddenColumns[j]) const ncColumnId = ncTbl.columns.find(
.id; (x) => x.title === hiddenColumns[j]
).id;
const ncViewColumnId = viewDetails.find( const ncViewColumnId = viewDetails.find(
x => x.fk_column_id === ncColumnId (x) => x.fk_column_id === ncColumnId
)?.id; )?.id;
// const ncViewColumnId = await nc_getViewColumnId( // const ncViewColumnId = await nc_getViewColumnId(
// viewId, // viewId,
@ -1970,7 +2000,7 @@ export default async (
const _perfStart = recordPerfStart(); const _perfStart = recordPerfStart();
await api.dbViewColumn.update(viewId, ncViewColumnId, { await api.dbViewColumn.update(viewId, ncViewColumnId, {
show: false, show: false,
order: j + 1 + c.length order: j + 1 + c.length,
}); });
recordPerfStats(_perfStart, 'dbViewColumn.update'); recordPerfStats(_perfStart, 'dbViewColumn.update');
} }
@ -2012,8 +2042,8 @@ export default async (
api = new Api({ api = new Api({
baseURL: syncDB.baseURL, baseURL: syncDB.baseURL,
headers: { headers: {
'xc-auth': syncDB.authToken 'xc-auth': syncDB.authToken,
} },
}); });
logDetailed('Project initialization started'); logDetailed('Project initialization started');
@ -2107,7 +2137,7 @@ export default async (
recordPerfStats(_perfStart, 'dbTable.read'); recordPerfStats(_perfStart, 'dbTable.read');
// not a migrated table, skip // not a migrated table, skip
if (undefined === aTblSchema.find(x => x.name === ncTbl.title)) if (undefined === aTblSchema.find((x) => x.name === ncTbl.title))
continue; continue;
recordCnt = 0; recordCnt = 0;
@ -2121,7 +2151,7 @@ export default async (
logBasic, logBasic,
nocoBaseDataProcessing_v2, nocoBaseDataProcessing_v2,
sDB: syncDB, sDB: syncDB,
logDetailed logDetailed,
}); });
rtc.data.records += recordsMap[ncTbl.id].length; rtc.data.records += recordsMap[ncTbl.id].length;
@ -2141,7 +2171,7 @@ export default async (
insertedAssocRef, insertedAssocRef,
logDetailed, logDetailed,
records: recordsMap[ncTbl.id], records: recordsMap[ncTbl.id],
atNcAliasRef atNcAliasRef,
}); });
} }
@ -2211,7 +2241,7 @@ export default async (
if (e.response?.data?.msg) { if (e.response?.data?.msg) {
Tele.event({ Tele.event({
event: 'a:airtable-import:error', event: 'a:airtable-import:error',
data: { error: e.response.data.msg } data: { error: e.response.data.msg },
}); });
throw new Error(e.response.data.msg); throw new Error(e.response.data.msg);
} }

5
packages/nocodb/src/lib/models/Project.ts

@ -237,6 +237,7 @@ export default class Project implements ProjectType {
let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT);
if (o) { if (o) {
// update data // update data
// new uuid is generated
if (o.uuid && updateObj.uuid && o.uuid !== updateObj.uuid) { if (o.uuid && updateObj.uuid && o.uuid !== updateObj.uuid) {
await NocoCache.del(`${CacheScope.PROJECT}:${o.uuid}`); await NocoCache.del(`${CacheScope.PROJECT}:${o.uuid}`);
await NocoCache.set( await NocoCache.set(
@ -244,6 +245,10 @@ export default class Project implements ProjectType {
projectId projectId
); );
} }
// disable shared base
if (o.uuid && updateObj.uuid === null) {
await NocoCache.del(`${CacheScope.PROJECT}:${o.uuid}`);
}
if (o.title && updateObj.title && o.title !== updateObj.title) { if (o.title && updateObj.title && o.title !== updateObj.title) {
await NocoCache.del(`${CacheScope.PROJECT}:${o.title}`); await NocoCache.del(`${CacheScope.PROJECT}:${o.title}`);
await NocoCache.set( await NocoCache.set(

12
packages/nocodb/src/lib/models/User.ts

@ -47,6 +47,11 @@ export default class User implements UserType {
'roles', 'roles',
'token_version' 'token_version'
]); ]);
if (insertObj.email) {
insertObj.email = insertObj.email.toLowerCase();
}
const { id } = await ncMeta.metaInsert2( const { id } = await ncMeta.metaInsert2(
null, null,
null, null,
@ -76,6 +81,10 @@ export default class User implements UserType {
'roles', 'roles',
'token_version' 'token_version'
]); ]);
if (updateObj.email) {
updateObj.email = updateObj.email.toLowerCase();
}
// get existing cache // get existing cache
const keys = [ const keys = [
// update user:<id> // update user:<id>
@ -97,7 +106,8 @@ export default class User implements UserType {
// set meta // set meta
return await ncMeta.metaUpdate(null, null, MetaTable.USERS, updateObj, id); return await ncMeta.metaUpdate(null, null, MetaTable.USERS, updateObj, id);
} }
public static async getByEmail(email, ncMeta = Noco.ncMeta) { public static async getByEmail(_email: string, ncMeta = Noco.ncMeta) {
const email = _email?.toLowerCase();
let user = let user =
email && email &&
(await NocoCache.get( (await NocoCache.get(

Loading…
Cancel
Save