|
|
|
@ -17,10 +17,6 @@ dayjs.extend(utc);
|
|
|
|
|
dayjs.extend(timezone); |
|
|
|
|
|
|
|
|
|
const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 4); |
|
|
|
|
|
|
|
|
|
// todo: tobe fixed
|
|
|
|
|
const META_TABLES = []; |
|
|
|
|
|
|
|
|
|
const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14); |
|
|
|
|
|
|
|
|
|
@Injectable() |
|
|
|
@ -300,44 +296,6 @@ export class MetaService {
|
|
|
|
|
// todo: need to fix
|
|
|
|
|
private trx: Knex.Transaction; |
|
|
|
|
|
|
|
|
|
// constructor(app: Noco, config: NcConfig, trx = null) {
|
|
|
|
|
// super(app, config);
|
|
|
|
|
//
|
|
|
|
|
// if (this.config?.meta?.db) {
|
|
|
|
|
// this.connection = trx || XKnex(this.config?.meta?.db);
|
|
|
|
|
// } else {
|
|
|
|
|
// let dbIndex = this.config.envs?.[this.config.workingEnv]?.db.findIndex(
|
|
|
|
|
// (c) => c.meta.dbAlias === this.config?.auth?.jwt?.dbAlias
|
|
|
|
|
// );
|
|
|
|
|
// dbIndex = dbIndex === -1 ? 0 : dbIndex;
|
|
|
|
|
// this.connection = XKnex(
|
|
|
|
|
// this.config.envs?.[this.config.workingEnv]?.db[dbIndex] as any
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// this.trx = trx;
|
|
|
|
|
// NcConnectionMgr.setXcMeta(this);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// public get knexConnection(): XKnex {
|
|
|
|
|
// return (this.trx || this.connection) as any;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// public updateKnex(connectionConfig): void {
|
|
|
|
|
// this.connection = XKnex(connectionConfig);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// public async metaInit(): Promise<boolean> {
|
|
|
|
|
// await this.connection.migrate.latest({
|
|
|
|
|
// migrationSource: new XcMigrationSource(),
|
|
|
|
|
// tableName: 'xc_knex_migrations',
|
|
|
|
|
// });
|
|
|
|
|
// await this.connection.migrate.latest({
|
|
|
|
|
// migrationSource: new XcMigrationSourcev2(),
|
|
|
|
|
// tableName: 'xc_knex_migrationsv2',
|
|
|
|
|
// });
|
|
|
|
|
// return true;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Delete meta data |
|
|
|
|
* @param base_id - Base id |
|
|
|
@ -657,40 +615,6 @@ export class MetaService {
|
|
|
|
|
return await query; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public async metaDeleteAll( |
|
|
|
|
_project_id: string, |
|
|
|
|
_dbAlias: string, |
|
|
|
|
): Promise<void> { |
|
|
|
|
NcError.notImplemented('metaDeleteAll'); |
|
|
|
|
// await this.knexConnection..dropTableIfExists('nc_roles').;
|
|
|
|
|
// await this.knexConnection.schema.dropTableIfExists('nc_store').;
|
|
|
|
|
// await this.knexConnection.schema.dropTableIfExists('nc_hooks').;
|
|
|
|
|
// await this.knexConnection.schema.dropTableIfExists('nc_cron').;
|
|
|
|
|
// await this.knexConnection.schema.dropTableIfExists('nc_acl').;
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Check table meta data exists for a given base id and db alias |
|
|
|
|
* @param base_id - Base id |
|
|
|
|
* @param dbAlias - Database alias |
|
|
|
|
* @returns {Promise<boolean>} - True if meta data exists, false otherwise |
|
|
|
|
* */ |
|
|
|
|
public async isMetaDataExists( |
|
|
|
|
base_id: string, |
|
|
|
|
dbAlias: string, |
|
|
|
|
): Promise<boolean> { |
|
|
|
|
const query = this.knexConnection('nc_models'); |
|
|
|
|
if (base_id !== null && base_id !== undefined) { |
|
|
|
|
query.where('base_id', base_id); |
|
|
|
|
} |
|
|
|
|
if (dbAlias !== null && dbAlias !== undefined) { |
|
|
|
|
query.where('db_alias', dbAlias); |
|
|
|
|
} |
|
|
|
|
const data = await query.first(); |
|
|
|
|
|
|
|
|
|
return !!data; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async commit() { |
|
|
|
|
if (this.trx) { |
|
|
|
|
await this.trx.commit(); |
|
|
|
@ -718,85 +642,6 @@ export class MetaService {
|
|
|
|
|
return new MetaService(this.config, trx); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async metaReset( |
|
|
|
|
base_id: string, |
|
|
|
|
dbAlias: string, |
|
|
|
|
apiType?: string, |
|
|
|
|
): Promise<void> { |
|
|
|
|
// const apiType: string = this.config?.envs?.[this.config.env || this.config.workingEnv]?.db.find(d => {
|
|
|
|
|
// return d.meta.dbAlias === dbAlias;
|
|
|
|
|
// })?.meta?.api?.type;
|
|
|
|
|
|
|
|
|
|
if (apiType) { |
|
|
|
|
await Promise.all( |
|
|
|
|
META_TABLES?.[apiType]?.map((table) => { |
|
|
|
|
return (async () => { |
|
|
|
|
try { |
|
|
|
|
await this.knexConnection(table) |
|
|
|
|
.where({ db_alias: dbAlias, base_id }) |
|
|
|
|
.del(); |
|
|
|
|
} catch (e) { |
|
|
|
|
console.warn(`Error: ${table} reset failed`); |
|
|
|
|
} |
|
|
|
|
})(); |
|
|
|
|
}), |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Create a new base |
|
|
|
|
* @param baseName - Base name |
|
|
|
|
* @param config - Base config |
|
|
|
|
* @param description - Base description |
|
|
|
|
* @param meta - If true, will create a meta base |
|
|
|
|
* @returns {Promise<any>} - Created base |
|
|
|
|
* */ |
|
|
|
|
public async baseCreate( |
|
|
|
|
baseName: string, |
|
|
|
|
config: any, |
|
|
|
|
description?: string, |
|
|
|
|
meta?: boolean, |
|
|
|
|
): Promise<any> { |
|
|
|
|
try { |
|
|
|
|
const ranId = this.getNanoId(); |
|
|
|
|
const id = `${baseName.toLowerCase().replace(/\W+/g, '_')}_${ranId}`; |
|
|
|
|
if (meta) { |
|
|
|
|
config.prefix = `nc_${ranId}__`; |
|
|
|
|
// if(config.envs._noco?.db?.[0]?.meta?.tn){
|
|
|
|
|
// config.envs._noco.db[0].meta.tn += `_${prefix}`
|
|
|
|
|
// }
|
|
|
|
|
} |
|
|
|
|
config.id = id; |
|
|
|
|
const base: any = { |
|
|
|
|
id, |
|
|
|
|
title: baseName, |
|
|
|
|
description, |
|
|
|
|
config: CryptoJS.AES.encrypt( |
|
|
|
|
JSON.stringify(config), |
|
|
|
|
'secret', // todo: tobe replaced - this.config?.auth?.jwt?.secret
|
|
|
|
|
).toString(), |
|
|
|
|
}; |
|
|
|
|
// todo: check base name used or not
|
|
|
|
|
await this.knexConnection('nc_projects').insert({ |
|
|
|
|
...base, |
|
|
|
|
created_at: this.now(), |
|
|
|
|
updated_at: this.now(), |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// todo
|
|
|
|
|
await this.knexConnection(MetaTable.PROJECT).insert({ |
|
|
|
|
id, |
|
|
|
|
title: baseName, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
base.prefix = config.prefix; |
|
|
|
|
return base; |
|
|
|
|
} catch (e) { |
|
|
|
|
console.log(e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Update base config |
|
|
|
|
* @param baseId - Base id |
|
|
|
@ -840,251 +685,6 @@ export class MetaService {
|
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Get base list with decrypted config for a user |
|
|
|
|
* @returns {Promise<any[]>} - List of bases |
|
|
|
|
* */ |
|
|
|
|
public async userProjectList(userId: any): Promise<any[]> { |
|
|
|
|
return ( |
|
|
|
|
await this.knexConnection('nc_projects') |
|
|
|
|
.leftJoin( |
|
|
|
|
this.knexConnection('nc_projects_users') |
|
|
|
|
.where(`nc_projects_users.user_id`, userId) |
|
|
|
|
.as('user'), |
|
|
|
|
'user.base_id', |
|
|
|
|
'nc_projects.id', |
|
|
|
|
) |
|
|
|
|
.select('nc_projects.*') |
|
|
|
|
.select('user.user_id') |
|
|
|
|
.select( |
|
|
|
|
this.knexConnection('xc_users') |
|
|
|
|
.select('xc_users.email') |
|
|
|
|
.innerJoin( |
|
|
|
|
'nc_projects_users', |
|
|
|
|
'nc_projects_users.user_id', |
|
|
|
|
'=', |
|
|
|
|
'xc_users.id', |
|
|
|
|
) |
|
|
|
|
.whereRaw('nc_projects.id = nc_projects_users.base_id') |
|
|
|
|
.where('nc_projects_users.roles', 'like', '%owner%') |
|
|
|
|
.first() |
|
|
|
|
.as('owner'), |
|
|
|
|
) |
|
|
|
|
.select( |
|
|
|
|
this.knexConnection('xc_users') |
|
|
|
|
.count('xc_users.id') |
|
|
|
|
.innerJoin( |
|
|
|
|
'nc_projects_users', |
|
|
|
|
'nc_projects_users.user_id', |
|
|
|
|
'=', |
|
|
|
|
'xc_users.id', |
|
|
|
|
) |
|
|
|
|
.where((qb) => { |
|
|
|
|
qb.where('nc_projects_users.roles', 'like', '%creator%').orWhere( |
|
|
|
|
'nc_projects_users.roles', |
|
|
|
|
'like', |
|
|
|
|
'%owner%', |
|
|
|
|
); |
|
|
|
|
}) |
|
|
|
|
.whereRaw('nc_projects.id = nc_projects_users.base_id') |
|
|
|
|
.andWhere('xc_users.id', userId) |
|
|
|
|
.first() |
|
|
|
|
.as('is_creator'), |
|
|
|
|
) |
|
|
|
|
).map((p) => { |
|
|
|
|
p.allowed = p.user_id === userId; |
|
|
|
|
p.config = CryptoJS.AES.decrypt( |
|
|
|
|
p.config, |
|
|
|
|
'secret', // todo: tobe replaced - this.config?.auth?.jwt?.secret
|
|
|
|
|
).toString(CryptoJS.enc.Utf8); |
|
|
|
|
return p; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Check if user have access to a project |
|
|
|
|
* @param baseId - Base id |
|
|
|
|
* @param userId - User id |
|
|
|
|
* @returns {Promise<boolean>} - True if user have access, false otherwise |
|
|
|
|
* */ |
|
|
|
|
public async isUserHaveAccessToProject( |
|
|
|
|
baseId: string, |
|
|
|
|
userId: any, |
|
|
|
|
): Promise<boolean> { |
|
|
|
|
return !!(await this.knexConnection('nc_projects_users') |
|
|
|
|
.where({ |
|
|
|
|
base_id: baseId, |
|
|
|
|
user_id: userId, |
|
|
|
|
}) |
|
|
|
|
.first()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Get base by name |
|
|
|
|
* @param baseName - Base name |
|
|
|
|
* @param encrypt - If true, will skip the decryption of config |
|
|
|
|
* @returns {Promise<any>} - Base |
|
|
|
|
* */ |
|
|
|
|
public async baseGet(baseName: string, encrypt?): Promise<any> { |
|
|
|
|
const base = await this.knexConnection('nc_projects') |
|
|
|
|
.where({ |
|
|
|
|
title: baseName, |
|
|
|
|
}) |
|
|
|
|
.first(); |
|
|
|
|
|
|
|
|
|
if (base && !encrypt) { |
|
|
|
|
base.config = CryptoJS.AES.decrypt( |
|
|
|
|
base.config, |
|
|
|
|
'secret', // todo: tobe replaced - this.config?.auth?.jwt?.secret
|
|
|
|
|
).toString(CryptoJS.enc.Utf8); |
|
|
|
|
} |
|
|
|
|
return base; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Get base by id |
|
|
|
|
* @param baseId - Base id |
|
|
|
|
* @param encrypt - If true, will skip the decryption of config |
|
|
|
|
* @returns {Promise<any>} - Base |
|
|
|
|
* */ |
|
|
|
|
public async baseGetById(baseId: string, encrypt?): Promise<any> { |
|
|
|
|
const base = await this.knexConnection('nc_projects') |
|
|
|
|
.where({ |
|
|
|
|
id: baseId, |
|
|
|
|
}) |
|
|
|
|
.first(); |
|
|
|
|
if (base && !encrypt) { |
|
|
|
|
base.config = CryptoJS.AES.decrypt( |
|
|
|
|
base.config, |
|
|
|
|
'secret', // todo: tobe replaced - this.config?.auth?.jwt?.secret
|
|
|
|
|
).toString(CryptoJS.enc.Utf8); |
|
|
|
|
} |
|
|
|
|
return base; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Delete base by name |
|
|
|
|
* @param title - Base name |
|
|
|
|
* */ |
|
|
|
|
public baseDelete(title: string): Promise<any> { |
|
|
|
|
if (!title) { |
|
|
|
|
NcError.metaError({ |
|
|
|
|
message: 'Base title is required to delete base', |
|
|
|
|
sql: '', |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.knexConnection('nc_projects') |
|
|
|
|
.where({ |
|
|
|
|
title, |
|
|
|
|
}) |
|
|
|
|
.delete(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Delete base by id |
|
|
|
|
* @param id - Base id |
|
|
|
|
* */ |
|
|
|
|
public baseDeleteById(id: string): Promise<any> { |
|
|
|
|
if (!id) { |
|
|
|
|
NcError.metaError({ |
|
|
|
|
message: 'Base id is required to delete base', |
|
|
|
|
sql: '', |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
return this.knexConnection('nc_projects') |
|
|
|
|
.where({ |
|
|
|
|
id, |
|
|
|
|
}) |
|
|
|
|
.delete(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Update base status |
|
|
|
|
* @param baseId - Base id |
|
|
|
|
* @param status - Base status |
|
|
|
|
* */ |
|
|
|
|
public async baseStatusUpdate(baseId: string, status: string): Promise<any> { |
|
|
|
|
if (!baseId) { |
|
|
|
|
NcError.metaError({ |
|
|
|
|
message: 'Base id is required to update base status', |
|
|
|
|
sql: '', |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.knexConnection('nc_projects') |
|
|
|
|
.update({ |
|
|
|
|
status, |
|
|
|
|
}) |
|
|
|
|
.where({ |
|
|
|
|
id: baseId, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Add user to base |
|
|
|
|
* @param baseId - Base id |
|
|
|
|
* @param userId - User id |
|
|
|
|
* @param roles - User roles |
|
|
|
|
* */ |
|
|
|
|
public async baseAddUser( |
|
|
|
|
baseId: string, |
|
|
|
|
userId: any, |
|
|
|
|
roles: string, |
|
|
|
|
): Promise<any> { |
|
|
|
|
if ( |
|
|
|
|
await this.knexConnection('nc_projects_users') |
|
|
|
|
.where({ |
|
|
|
|
user_id: userId, |
|
|
|
|
base_id: baseId, |
|
|
|
|
}) |
|
|
|
|
.first() |
|
|
|
|
) { |
|
|
|
|
return {}; |
|
|
|
|
} |
|
|
|
|
return this.knexConnection('nc_projects_users').insert({ |
|
|
|
|
user_id: userId, |
|
|
|
|
base_id: baseId, |
|
|
|
|
roles, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Remove user from base |
|
|
|
|
* @param baseId - Base id |
|
|
|
|
* @param userId - User id |
|
|
|
|
* */ |
|
|
|
|
public baseRemoveUser(baseId: string, userId: any): Promise<any> { |
|
|
|
|
if (!baseId || !userId) { |
|
|
|
|
NcError.metaError({ |
|
|
|
|
message: 'Base id and user id is required to remove user from base', |
|
|
|
|
sql: '', |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.knexConnection('nc_projects_users') |
|
|
|
|
.where({ |
|
|
|
|
user_id: userId, |
|
|
|
|
base_id: baseId, |
|
|
|
|
}) |
|
|
|
|
.delete(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public removeXcUser(userId: any): Promise<any> { |
|
|
|
|
if (!userId) { |
|
|
|
|
NcError.metaError({ |
|
|
|
|
message: 'User id is required to remove user', |
|
|
|
|
sql: '', |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.knexConnection('xc_users') |
|
|
|
|
.where({ |
|
|
|
|
id: userId, |
|
|
|
|
}) |
|
|
|
|
.delete(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private getNanoId() { |
|
|
|
|
return nanoid(); |
|
|
|
|
} |
|
|
|
@ -1102,18 +702,6 @@ export class MetaService {
|
|
|
|
|
.format(this.isMySQL() ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD HH:mm:ssZ'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public async audit( |
|
|
|
|
base_id: string, |
|
|
|
|
dbAlias: string, |
|
|
|
|
target: string, |
|
|
|
|
data: any, |
|
|
|
|
): Promise<any> { |
|
|
|
|
if (['DATA', 'COMMENT'].includes(data?.op_type)) { |
|
|
|
|
return Promise.resolve(undefined); |
|
|
|
|
} |
|
|
|
|
return this.metaInsert(base_id, dbAlias, target, data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public async init(): Promise<boolean> { |
|
|
|
|
await this.connection.migrate.latest({ |
|
|
|
|
migrationSource: new XcMigrationSource(), |
|
|
|
|