diff --git a/packages/nocodb-sdk/src/lib/Api.ts b/packages/nocodb-sdk/src/lib/Api.ts index 75664a7e17..acd1b9d3f9 100644 --- a/packages/nocodb-sdk/src/lib/Api.ts +++ b/packages/nocodb-sdk/src/lib/Api.ts @@ -2100,6 +2100,11 @@ export interface BaseType { * @example p_124hhlkbeasewh */ id?: string; + /** + * Workspace ID + * @example ws_123456 + */ + fk_workspace_id?: string; /** Model for Bool */ is_meta?: BoolType; /** Meta Info such as theme colors */ diff --git a/packages/nocodb-sdk/src/lib/globals.ts b/packages/nocodb-sdk/src/lib/globals.ts index 3145173bac..d3194529f9 100644 --- a/packages/nocodb-sdk/src/lib/globals.ts +++ b/packages/nocodb-sdk/src/lib/globals.ts @@ -134,6 +134,7 @@ export enum NcErrorType { VIEW_NOT_FOUND = 'VIEW_NOT_FOUND', FIELD_NOT_FOUND = 'FIELD_NOT_FOUND', RECORD_NOT_FOUND = 'RECORD_NOT_FOUND', + GENERIC_NOT_FOUND = 'GENERIC_NOT_FOUND', ERROR_DUPLICATE_RECORD = 'ERROR_DUPLICATE_RECORD', USER_NOT_FOUND = 'USER_NOT_FOUND', INVALID_OFFSET_VALUE = 'INVALID_OFFSET_VALUE', diff --git a/packages/nocodb/src/Noco.ts b/packages/nocodb/src/Noco.ts index 44a47b7bdd..d6163cd335 100644 --- a/packages/nocodb/src/Noco.ts +++ b/packages/nocodb/src/Noco.ts @@ -13,7 +13,7 @@ import type { MetaService } from '~/meta/meta.service'; import type { IEventEmitter } from '~/modules/event-emitter/event-emitter.interface'; import type { Express } from 'express'; import type http from 'http'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; import { AppModule } from '~/app.module'; import { isEE } from '~/utils'; @@ -146,15 +146,26 @@ export default class Noco { if (this.config?.auth?.jwt) { if (!this.config.auth.jwt.secret) { let secret = ( - await this._ncMeta.metaGet('', '', MetaTable.STORE, { - key: 'nc_auth_jwt_secret', - }) + await this._ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.STORE, + { + key: 'nc_auth_jwt_secret', + }, + ) )?.value; if (!secret) { - await this._ncMeta.metaInsert('', '', MetaTable.STORE, { - key: 'nc_auth_jwt_secret', - value: (secret = uuidv4()), - }); + await this._ncMeta.metaInsert2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.STORE, + { + key: 'nc_auth_jwt_secret', + value: (secret = uuidv4()), + }, + true, + ); } this.config.auth.jwt.secret = secret; } @@ -166,15 +177,26 @@ export default class Noco { } } let serverId = ( - await this._ncMeta.metaGet('', '', MetaTable.STORE, { - key: 'nc_server_id', - }) + await this._ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.STORE, + { + key: 'nc_server_id', + }, + ) )?.value; if (!serverId) { - await this._ncMeta.metaInsert('', '', MetaTable.STORE, { - key: 'nc_server_id', - value: (serverId = T.id), - }); + await this._ncMeta.metaInsert2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.STORE, + { + key: 'nc_server_id', + value: (serverId = T.id), + }, + true, + ); } process.env.NC_SERVER_UUID = serverId; } diff --git a/packages/nocodb/src/controllers/api-docs/api-docs.controller.ts b/packages/nocodb/src/controllers/api-docs/api-docs.controller.ts index 3d8a073627..4c9ab3c437 100644 --- a/packages/nocodb/src/controllers/api-docs/api-docs.controller.ts +++ b/packages/nocodb/src/controllers/api-docs/api-docs.controller.ts @@ -13,6 +13,8 @@ import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { ApiDocsService } from '~/services/api-docs/api-docs.service'; import { PublicApiLimiterGuard } from '~/guards/public-api-limiter.guard'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext } from '~/interface/config'; @Controller() export class ApiDocsController { @@ -21,8 +23,12 @@ export class ApiDocsController { @Get(['/api/v1/db/meta/projects/:baseId/swagger.json']) @UseGuards(MetaApiLimiterGuard, GlobalGuard) @Acl('swaggerJson') - async swaggerJson(@Param('baseId') baseId: string, @Request() req) { - const swagger = await this.apiDocsService.swaggerJson({ + async swaggerJson( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + @Request() req, + ) { + const swagger = await this.apiDocsService.swaggerJson(context, { baseId: baseId, siteUrl: req.ncSiteUrl, }); @@ -33,8 +39,12 @@ export class ApiDocsController { @Get(['/api/v2/meta/bases/:baseId/swagger.json']) @UseGuards(MetaApiLimiterGuard, GlobalGuard) @Acl('swaggerJson') - async swaggerJsonV2(@Param('baseId') baseId: string, @Request() req) { - const swagger = await this.apiDocsService.swaggerJsonV2({ + async swaggerJsonV2( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + @Request() req, + ) { + const swagger = await this.apiDocsService.swaggerJsonV2(context, { baseId: baseId, siteUrl: req.ncSiteUrl, }); diff --git a/packages/nocodb/src/controllers/api-tokens.controller.ts b/packages/nocodb/src/controllers/api-tokens.controller.ts index 3549f388d9..acedfd9004 100644 --- a/packages/nocodb/src/controllers/api-tokens.controller.ts +++ b/packages/nocodb/src/controllers/api-tokens.controller.ts @@ -9,12 +9,12 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { ApiTokensService } from '~/services/api-tokens.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -26,7 +26,7 @@ export class ApiTokensController { '/api/v2/meta/bases/:baseId/api-tokens', ]) @Acl('baseApiTokenList') - async apiTokenList(@Req() req: Request) { + async apiTokenList(@Req() req: NcRequest) { return new PagedResponseImpl( await this.apiTokensService.apiTokenList({ userId: req['user'].id }), ); @@ -38,7 +38,7 @@ export class ApiTokensController { ]) @HttpCode(200) @Acl('baseApiTokenCreate') - async apiTokenCreate(@Req() req: Request, @Body() body) { + async apiTokenCreate(@Req() req: NcRequest, @Body() body) { return await this.apiTokensService.apiTokenCreate({ tokenBody: body, userId: req['user'].id, @@ -51,7 +51,7 @@ export class ApiTokensController { '/api/v2/meta/bases/:baseId/api-tokens/:token', ]) @Acl('baseApiTokenDelete') - async apiTokenDelete(@Req() req: Request, @Param('token') token: string) { + async apiTokenDelete(@Req() req: NcRequest, @Param('token') token: string) { return await this.apiTokensService.apiTokenDelete({ token, user: req['user'], diff --git a/packages/nocodb/src/controllers/attachments-secure.controller.ts b/packages/nocodb/src/controllers/attachments-secure.controller.ts index 5d7145307e..d39d310145 100644 --- a/packages/nocodb/src/controllers/attachments-secure.controller.ts +++ b/packages/nocodb/src/controllers/attachments-secure.controller.ts @@ -16,8 +16,8 @@ import hash from 'object-hash'; import moment from 'moment'; import { AnyFilesInterceptor } from '@nestjs/platform-express'; import { Response } from 'express'; -import type { Request } from 'express'; import type { AttachmentReqType, FileType } from 'nocodb-sdk'; +import type { NcRequest } from '~/interface/config'; import { GlobalGuard } from '~/guards/global/global.guard'; import { AttachmentsService } from '~/services/attachments.service'; import { PresignedUrl } from '~/models'; @@ -34,7 +34,7 @@ export class AttachmentsSecureController { @UseInterceptors(UploadAllowedInterceptor, AnyFilesInterceptor()) async upload( @UploadedFiles() files: Array, - @Req() req: Request & { user: { id: string } }, + @Req() req: NcRequest & { user: { id: string } }, ) { const path = `${moment().format('YYYY/MM/DD')}/${hash(req.user.id)}`; @@ -53,7 +53,7 @@ export class AttachmentsSecureController { @UseGuards(MetaApiLimiterGuard, GlobalGuard) async uploadViaURL( @Body() body: Array, - @Req() req: Request & { user: { id: string } }, + @Req() req: NcRequest & { user: { id: string } }, ) { const path = `${moment().format('YYYY/MM/DD')}/${hash(req.user.id)}`; diff --git a/packages/nocodb/src/controllers/attachments.controller.ts b/packages/nocodb/src/controllers/attachments.controller.ts index 353e840eb7..5e6f621545 100644 --- a/packages/nocodb/src/controllers/attachments.controller.ts +++ b/packages/nocodb/src/controllers/attachments.controller.ts @@ -14,13 +14,14 @@ import { UseInterceptors, } from '@nestjs/common'; import { AnyFilesInterceptor } from '@nestjs/platform-express'; -import { Request, Response } from 'express'; +import { Response } from 'express'; import type { AttachmentReqType, FileType } from 'nocodb-sdk'; import { UploadAllowedInterceptor } from '~/interceptors/is-upload-allowed/is-upload-allowed.interceptor'; import { GlobalGuard } from '~/guards/global/global.guard'; import { AttachmentsService } from '~/services/attachments.service'; import { PresignedUrl } from '~/models'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { NcRequest } from '~/interface/config'; @Controller() export class AttachmentsController { @@ -30,7 +31,7 @@ export class AttachmentsController { @Post(['/api/v1/db/storage/upload', '/api/v2/storage/upload']) @HttpCode(200) @UseInterceptors(UploadAllowedInterceptor, AnyFilesInterceptor()) - async upload(@UploadedFiles() files: Array, @Req() req: Request) { + async upload(@UploadedFiles() files: Array, @Req() req: NcRequest) { const attachments = await this.attachmentsService.upload({ files: files, path: req.query?.path?.toString(), @@ -47,7 +48,7 @@ export class AttachmentsController { async uploadViaURL( @Body() body: Array, @Query('path') path: string, - @Req() req: Request, + @Req() req: NcRequest, ) { const attachments = await this.attachmentsService.uploadViaURL({ urls: body, diff --git a/packages/nocodb/src/controllers/audits.controller.ts b/packages/nocodb/src/controllers/audits.controller.ts index 41f059e6a7..cb61306719 100644 --- a/packages/nocodb/src/controllers/audits.controller.ts +++ b/packages/nocodb/src/controllers/audits.controller.ts @@ -8,12 +8,13 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { AuditsService } from '~/services/audits.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -22,7 +23,7 @@ export class AuditsController { @Get(['/api/v1/db/meta/audits/', '/api/v2/meta/audits/']) @Acl('auditList') - async auditListRow(@Req() req: Request) { + async auditListRow(@Req() req: NcRequest) { return new PagedResponseImpl( await this.auditsService.auditOnlyList({ query: req.query as any }), ); @@ -34,8 +35,12 @@ export class AuditsController { ]) @HttpCode(200) @Acl('auditRowUpdate') - async auditRowUpdate(@Param('rowId') rowId: string, @Body() body: any) { - return await this.auditsService.auditRowUpdate({ + async auditRowUpdate( + @TenantContext() context: NcContext, + @Param('rowId') rowId: string, + @Body() body: any, + ) { + return await this.auditsService.auditRowUpdate(context, { rowId, body, }); @@ -46,7 +51,7 @@ export class AuditsController { '/api/v2/meta/bases/:baseId/audits/', ]) @Acl('auditList') - async auditList(@Req() req: Request, @Param('baseId') baseId: string) { + async auditList(@Req() req: NcRequest, @Param('baseId') baseId: string) { return new PagedResponseImpl( await this.auditsService.auditList({ query: req.query, diff --git a/packages/nocodb/src/controllers/base-users.controller.ts b/packages/nocodb/src/controllers/base-users.controller.ts index 05197e702f..63858a7a8e 100644 --- a/packages/nocodb/src/controllers/base-users.controller.ts +++ b/packages/nocodb/src/controllers/base-users.controller.ts @@ -10,13 +10,14 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { ProjectRoles, ProjectUserReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { BaseUsersService } from '~/services/base-users/base-users.service'; import { NcError } from '~/helpers/catchError'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @UseGuards(MetaApiLimiterGuard, GlobalGuard) @Controller() @@ -28,8 +29,12 @@ export class BaseUsersController { '/api/v2/meta/bases/:baseId/users', ]) @Acl('baseUserList') - async userList(@Param('baseId') baseId: string, @Req() req: Request) { - const baseRoles = Object.keys(req.user?.base_roles ?? {}); + async userList( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + @Req() req: NcRequest, + ) { + const baseRoles = Object.keys((req.user as any)?.base_roles ?? {}); const mode = baseRoles.includes(ProjectRoles.OWNER) || baseRoles.includes(ProjectRoles.CREATOR) @@ -37,7 +42,7 @@ export class BaseUsersController { : 'viewer'; return { - users: await this.baseUsersService.userList({ + users: await this.baseUsersService.userList(context, { baseId, mode, }), @@ -51,15 +56,16 @@ export class BaseUsersController { @HttpCode(200) @Acl('userInvite') async userInvite( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, - @Req() req: Request, + @Req() req: NcRequest, @Body() body: ProjectUserReqType, ): Promise { // todo: move this to a service if (!body.email) { NcError.badRequest('Email is required'); } - return await this.baseUsersService.userInvite({ + return await this.baseUsersService.userInvite(context, { baseId, baseUser: body, req, @@ -72,15 +78,16 @@ export class BaseUsersController { ]) @Acl('baseUserUpdate') async baseUserUpdate( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('userId') userId: string, - @Req() req: Request, + @Req() req: NcRequest, @Body() body: ProjectUserReqType & { base_id: string; }, ): Promise { - await this.baseUsersService.baseUserUpdate({ + await this.baseUsersService.baseUserUpdate(context, { baseUser: body, baseId, userId, @@ -97,11 +104,12 @@ export class BaseUsersController { ]) @Acl('baseUserDelete') async baseUserDelete( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('userId') userId: string, - @Req() req: Request, + @Req() req: NcRequest, ): Promise { - await this.baseUsersService.baseUserDelete({ + await this.baseUsersService.baseUserDelete(context, { baseId, userId, req, @@ -118,12 +126,13 @@ export class BaseUsersController { @HttpCode(200) @Acl('baseUserInviteResend') async baseUserInviteResend( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('userId') userId: string, - @Req() req: Request, + @Req() req: NcRequest, @Body() body: ProjectUserReqType, ): Promise { - await this.baseUsersService.baseUserInviteResend({ + await this.baseUsersService.baseUserInviteResend(context, { baseId: baseId, userId: userId, baseUser: body, @@ -140,11 +149,12 @@ export class BaseUsersController { ]) @Acl('baseUserMetaUpdate') async baseUserMetaUpdate( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, - @Req() req: Request, + @Req() req: NcRequest, @Body() body: ProjectUserReqType, ): Promise { - return await this.baseUsersService.baseUserMetaUpdate({ + return await this.baseUsersService.baseUserMetaUpdate(context, { baseId, body, user: req.user, diff --git a/packages/nocodb/src/controllers/bases.controller.ts b/packages/nocodb/src/controllers/bases.controller.ts index 3128fc0015..7adee5ef23 100644 --- a/packages/nocodb/src/controllers/bases.controller.ts +++ b/packages/nocodb/src/controllers/bases.controller.ts @@ -11,7 +11,6 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import isDocker from 'is-docker'; import { ProjectReqType } from 'nocodb-sdk'; import type { BaseType } from 'nocodb-sdk'; @@ -23,6 +22,8 @@ import { BasesService } from '~/services/bases.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { Filter } from '~/models'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @UseGuards(MetaApiLimiterGuard, GlobalGuard) @Controller() @@ -33,8 +34,12 @@ export class BasesController { scope: 'org', }) @Get(['/api/v1/db/meta/projects/', '/api/v2/meta/bases/']) - async list(@Query() queryParams: Record, @Req() req: Request) { - const bases = await this.projectsService.baseList({ + async list( + @TenantContext() context: NcContext, + @Query() queryParams: Record, + @Req() req: NcRequest, + ) { + const bases = await this.projectsService.baseList(context, { user: req.user, query: queryParams, }); @@ -62,8 +67,11 @@ export class BasesController { @Acl('baseGet') @Get(['/api/v1/db/meta/projects/:baseId', '/api/v2/meta/bases/:baseId']) - async baseGet(@Param('baseId') baseId: string) { - const base = await this.projectsService.getProjectWithInfo({ + async baseGet( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + ) { + const base = await this.projectsService.getProjectWithInfo(context, { baseId: baseId, }); @@ -75,11 +83,12 @@ export class BasesController { @Acl('baseUpdate') @Patch(['/api/v1/db/meta/projects/:baseId', '/api/v2/meta/bases/:baseId']) async baseUpdate( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Body() body: Record, - @Req() req: Request, + @Req() req: NcRequest, ) { - const base = await this.projectsService.baseUpdate({ + const base = await this.projectsService.baseUpdate(context, { baseId, base: body, user: req.user, @@ -91,8 +100,12 @@ export class BasesController { @Acl('baseDelete') @Delete(['/api/v1/db/meta/projects/:baseId', '/api/v2/meta/bases/:baseId']) - async baseDelete(@Param('baseId') baseId: string, @Req() req: Request) { - const deleted = await this.projectsService.baseSoftDelete({ + async baseDelete( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + @Req() req: NcRequest, + ) { + const deleted = await this.projectsService.baseSoftDelete(context, { baseId, user: req.user, req, @@ -106,7 +119,11 @@ export class BasesController { }) @Post(['/api/v1/db/meta/projects', '/api/v2/meta/bases']) @HttpCode(200) - async baseCreate(@Body() baseBody: ProjectReqType, @Req() req: Request) { + async baseCreate( + @TenantContext() context: NcContext, + @Body() baseBody: ProjectReqType, + @Req() req: NcRequest, + ) { const base = await this.projectsService.baseCreate({ base: baseBody, req, @@ -121,7 +138,10 @@ export class BasesController { '/api/v1/db/meta/projects/:baseId/has-empty-or-null-filters', '/api/v2/meta/bases/:baseId/has-empty-or-null-filters', ]) - async hasEmptyOrNullFilters(@Param('baseId') baseId: string) { - return await Filter.hasEmptyOrNullFilters(baseId); + async hasEmptyOrNullFilters( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + ) { + return await Filter.hasEmptyOrNullFilters(context, baseId); } } diff --git a/packages/nocodb/src/controllers/bulk-data-alias.controller.ts b/packages/nocodb/src/controllers/bulk-data-alias.controller.ts index 740979667d..3ff72916c2 100644 --- a/packages/nocodb/src/controllers/bulk-data-alias.controller.ts +++ b/packages/nocodb/src/controllers/bulk-data-alias.controller.ts @@ -10,11 +10,13 @@ import { Res, UseGuards, } from '@nestjs/common'; -import { Request, Response } from 'express'; +import { Response } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { BulkDataAliasService } from '~/services/bulk-data-alias.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { DataApiLimiterGuard } from '~/guards/data-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(DataApiLimiterGuard, GlobalGuard) @@ -25,13 +27,14 @@ export class BulkDataAliasController { @HttpCode(200) @Acl('bulkDataInsert') async bulkDataInsert( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Res() res: Response, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Body() body: any, ) { - const exists = await this.bulkDataAliasService.bulkDataInsert({ + const exists = await this.bulkDataAliasService.bulkDataInsert(context, { body: body, cookie: req, baseName: baseName, @@ -44,12 +47,13 @@ export class BulkDataAliasController { @Patch(['/api/v1/db/data/bulk/:orgs/:baseName/:tableName']) @Acl('bulkDataUpdate') async bulkDataUpdate( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Body() body: any, ) { - return await this.bulkDataAliasService.bulkDataUpdate({ + return await this.bulkDataAliasService.bulkDataUpdate(context, { body: body, cookie: req, baseName: baseName, @@ -61,12 +65,13 @@ export class BulkDataAliasController { @Patch(['/api/v1/db/data/bulk/:orgs/:baseName/:tableName/all']) @Acl('bulkDataUpdateAll') async bulkDataUpdateAll( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Body() body: any, ) { - return await this.bulkDataAliasService.bulkDataUpdateAll({ + return await this.bulkDataAliasService.bulkDataUpdateAll(context, { body: body, cookie: req, baseName: baseName, @@ -78,12 +83,13 @@ export class BulkDataAliasController { @Delete(['/api/v1/db/data/bulk/:orgs/:baseName/:tableName']) @Acl('bulkDataDelete') async bulkDataDelete( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Body() body: any, ) { - return await this.bulkDataAliasService.bulkDataDelete({ + return await this.bulkDataAliasService.bulkDataDelete(context, { body: body, cookie: req, baseName: baseName, @@ -96,11 +102,12 @@ export class BulkDataAliasController { @Delete(['/api/v1/db/data/bulk/:orgs/:baseName/:tableName/all']) @Acl('bulkDataDeleteAll') async bulkDataDeleteAll( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, ) { - return await this.bulkDataAliasService.bulkDataDeleteAll({ + return await this.bulkDataAliasService.bulkDataDeleteAll(context, { // cookie: req, baseName: baseName, tableName: tableName, diff --git a/packages/nocodb/src/controllers/calendars-datas.controller.ts b/packages/nocodb/src/controllers/calendars-datas.controller.ts index 47fb47146c..87d08ac708 100644 --- a/packages/nocodb/src/controllers/calendars-datas.controller.ts +++ b/packages/nocodb/src/controllers/calendars-datas.controller.ts @@ -7,13 +7,15 @@ import { Res, UseGuards, } from '@nestjs/common'; -import { Request, Response } from 'express'; +import { Response } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { DataApiLimiterGuard } from '~/guards/data-api-limiter.guard'; import { CalendarDatasService } from '~/services/calendar-datas.service'; import { parseHrtimeToMilliSeconds } from '~/helpers'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(DataApiLimiterGuard, GlobalGuard) @@ -23,12 +25,13 @@ export class CalendarDatasController { @Get(['/api/v1/db/calendar-data/:orgs/:baseName/:tableName/views/:viewName']) @Acl('dataList') async dataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewName') viewId: string, @Query('from_date') fromDate: string, @Query('to_date') toDate: string, ) { - return await this.calendarDatasService.getCalendarDataList({ + return await this.calendarDatasService.getCalendarDataList(context, { viewId: viewId, query: req.query, from_date: fromDate, @@ -41,7 +44,8 @@ export class CalendarDatasController { ]) @Acl('dataList') async calendarDataCount( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Res() res: Response, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @@ -51,12 +55,15 @@ export class CalendarDatasController { ) { const startTime = process.hrtime(); - const data = await this.calendarDatasService.getCalendarRecordCount({ - query: req.query, - viewId: viewName, - from_date: fromDate, - to_date: toDate, - }); + const data = await this.calendarDatasService.getCalendarRecordCount( + context, + { + query: req.query, + viewId: viewName, + from_date: fromDate, + to_date: toDate, + }, + ); const elapsedSeconds = parseHrtimeToMilliSeconds(process.hrtime(startTime)); res.setHeader('xc-db-response', elapsedSeconds); @@ -68,18 +75,22 @@ export class CalendarDatasController { '/api/v2/public/calendar-view/:sharedViewUuid/countByDate', ]) async countByDate( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, @Query('from_date') fromDate: string, @Query('to_date') toDate: string, ) { - return await this.calendarDatasService.getPublicCalendarRecordCount({ - query: req.query, - password: req.headers?.['xc-password'] as string, - sharedViewUuid, - from_date: fromDate, - to_date: toDate, - }); + return await this.calendarDatasService.getPublicCalendarRecordCount( + context, + { + query: req.query, + password: req.headers?.['xc-password'] as string, + sharedViewUuid, + from_date: fromDate, + to_date: toDate, + }, + ); } @Get([ @@ -87,12 +98,13 @@ export class CalendarDatasController { '/api/v2/public/calendar-view/:sharedViewUuid', ]) async getPublicCalendarDataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, @Query('from_date') fromDate: string, @Query('to_date') toDate: string, ) { - return await this.calendarDatasService.getPublicCalendarDataList({ + return await this.calendarDatasService.getPublicCalendarDataList(context, { query: req.query, password: req.headers?.['xc-password'] as string, sharedViewUuid, diff --git a/packages/nocodb/src/controllers/calendars.controller.ts b/packages/nocodb/src/controllers/calendars.controller.ts index e8d1df52ac..70575a4a74 100644 --- a/packages/nocodb/src/controllers/calendars.controller.ts +++ b/packages/nocodb/src/controllers/calendars.controller.ts @@ -9,12 +9,13 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { ViewCreateReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { CalendarsService } from '~/services/calendars.service'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -26,8 +27,11 @@ export class CalendarsController { '/api/v2/meta/calendars/:calendarViewId', ]) @Acl('calendarViewGet') - async calendarViewGet(@Param('calendarViewId') calendarViewId: string) { - return await this.calendarsService.calendarViewGet({ + async calendarViewGet( + @TenantContext() context: NcContext, + @Param('calendarViewId') calendarViewId: string, + ) { + return await this.calendarsService.calendarViewGet(context, { calendarViewId, }); } @@ -39,11 +43,12 @@ export class CalendarsController { @HttpCode(200) @Acl('calendarViewCreate') async calendarViewCreate( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: ViewCreateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.calendarsService.calendarViewCreate({ + return await this.calendarsService.calendarViewCreate(context, { tableId, calendar: body, user: req.user, @@ -57,11 +62,12 @@ export class CalendarsController { ]) @Acl('calendarViewUpdate') async calendarViewUpdate( + @TenantContext() context: NcContext, @Param('calendarViewId') calendarViewId: string, @Body() body, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.calendarsService.calendarViewUpdate({ + return await this.calendarsService.calendarViewUpdate(context, { calendarViewId, calendar: body, req, diff --git a/packages/nocodb/src/controllers/columns.controller.ts b/packages/nocodb/src/controllers/columns.controller.ts index d27ace33ce..5e2094409e 100644 --- a/packages/nocodb/src/controllers/columns.controller.ts +++ b/packages/nocodb/src/controllers/columns.controller.ts @@ -10,13 +10,14 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { ColumnReqType } from 'nocodb-sdk'; import type { Column } from '~/models'; import { GlobalGuard } from '~/guards/global/global.guard'; import { ColumnsService } from '~/services/columns.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -30,11 +31,12 @@ export class ColumnsController { @HttpCode(200) @Acl('columnAdd') async columnAdd( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: ColumnReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.columnsService.columnAdd({ + return await this.columnsService.columnAdd(context, { tableId, column: body, req, @@ -48,11 +50,12 @@ export class ColumnsController { ]) @Acl('columnUpdate') async columnUpdate( + @TenantContext() context: NcContext, @Param('columnId') columnId: string, @Body() body: ColumnReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.columnsService.columnUpdate({ + return await this.columnsService.columnUpdate(context, { columnId: columnId, column: body, req, @@ -65,8 +68,12 @@ export class ColumnsController { '/api/v2/meta/columns/:columnId', ]) @Acl('columnDelete') - async columnDelete(@Param('columnId') columnId: string, @Req() req: Request) { - return await this.columnsService.columnDelete({ + async columnDelete( + @TenantContext() context: NcContext, + @Param('columnId') columnId: string, + @Req() req: NcRequest, + ) { + return await this.columnsService.columnDelete(context, { columnId, req, user: req.user, @@ -75,8 +82,11 @@ export class ColumnsController { @Get(['/api/v1/db/meta/columns/:columnId', '/api/v2/meta/columns/:columnId']) @Acl('columnGet') - async columnGet(@Param('columnId') columnId: string) { - return await this.columnsService.columnGet({ columnId }); + async columnGet( + @TenantContext() context: NcContext, + @Param('columnId') columnId: string, + ) { + return await this.columnsService.columnGet(context, { columnId }); } @Post([ @@ -85,8 +95,11 @@ export class ColumnsController { ]) @HttpCode(200) @Acl('columnSetAsPrimary') - async columnSetAsPrimary(@Param('columnId') columnId: string) { - return await this.columnsService.columnSetAsPrimary({ columnId }); + async columnSetAsPrimary( + @TenantContext() context: NcContext, + @Param('columnId') columnId: string, + ) { + return await this.columnsService.columnSetAsPrimary(context, { columnId }); } @Get([ @@ -94,8 +107,11 @@ export class ColumnsController { '/api/v2/meta/tables/:tableId/columns/hash', ]) @Acl('columnsHash') - async columnsHash(@Param('tableId') tableId: string) { - return await this.columnsService.columnsHash(tableId); + async columnsHash( + @TenantContext() context: NcContext, + @Param('tableId') tableId: string, + ) { + return await this.columnsService.columnsHash(context, tableId); } @Post([ @@ -105,6 +121,7 @@ export class ColumnsController { @HttpCode(200) @Acl('columnBulk') async columnBulk( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: { @@ -114,8 +131,8 @@ export class ColumnsController { column: Partial; }[]; }, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.columnsService.columnBulk(tableId, body, req); + return await this.columnsService.columnBulk(context, tableId, body, req); } } diff --git a/packages/nocodb/src/controllers/command-palette.controller.ts b/packages/nocodb/src/controllers/command-palette.controller.ts index 85e41faae6..2e94cf5e45 100644 --- a/packages/nocodb/src/controllers/command-palette.controller.ts +++ b/packages/nocodb/src/controllers/command-palette.controller.ts @@ -1,10 +1,10 @@ import { Controller, HttpCode, Post, Req, UseGuards } from '@nestjs/common'; -import { Request } from 'express'; import type { UserType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { CommandPaletteService } from '~/services/command-palette.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -16,7 +16,7 @@ export class CommandPaletteController { scope: 'org', }) @HttpCode(200) - async commandPalette(@Req() req: Request) { + async commandPalette(@Req() req: NcRequest) { const data = this.commandPaletteService.commandPalette({ user: req?.user as UserType, body: req.body, diff --git a/packages/nocodb/src/controllers/comments.controller.ts b/packages/nocodb/src/controllers/comments.controller.ts index afd5c8effa..20d89e6111 100644 --- a/packages/nocodb/src/controllers/comments.controller.ts +++ b/packages/nocodb/src/controllers/comments.controller.ts @@ -16,7 +16,8 @@ import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { CommentsService } from '~/services/comments.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; -import { NcRequest } from '~/interface/config'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -25,17 +26,21 @@ export class CommentsController { @Get(['/api/v1/db/meta/comments', '/api/v2/meta/comments']) @Acl('commentList') - async commentList(@Req() req: any) { + async commentList(@TenantContext() context: NcContext, @Req() req: any) { return new PagedResponseImpl( - await this.commentsService.commentList({ query: req.query }), + await this.commentsService.commentList(context, { query: req.query }), ); } @Post(['/api/v1/db/meta/comments', '/api/v2/meta/comments']) @HttpCode(200) @Acl('commentRow') - async commentRow(@Req() req: NcRequest, @Body() body: any) { - return await this.commentsService.commentRow({ + async commentRow( + @TenantContext() context: NcContext, + @Req() req: NcRequest, + @Body() body: any, + ) { + return await this.commentsService.commentRow(context, { user: req.user, body: body, req, @@ -48,10 +53,11 @@ export class CommentsController { ]) @Acl('commentDelete') async commentDelete( + @TenantContext() context: NcContext, @Req() req: NcRequest, @Param('commentId') commentId: string, ) { - return await this.commentsService.commentDelete({ + return await this.commentsService.commentDelete(context, { commentId, user: req.user, req, @@ -64,11 +70,12 @@ export class CommentsController { ]) @Acl('commentUpdate') async commentUpdate( + @TenantContext() context: NcContext, @Param('commentId') commentId: string, @Req() req: any, @Body() body: any, ) { - return await this.commentsService.commentUpdate({ + return await this.commentsService.commentUpdate(context, { commentId: commentId, user: req.user, body: body, @@ -79,10 +86,11 @@ export class CommentsController { @Get(['/api/v1/db/meta/comments/count', '/api/v2/meta/comments/count']) @Acl('commentsCount') async commentsCount( + @TenantContext() context: NcContext, @Query('fk_model_id') fk_model_id: string, @Query('ids') ids: string[], ) { - return await this.commentsService.commentsCount({ + return await this.commentsService.commentsCount(context, { fk_model_id, ids, }); diff --git a/packages/nocodb/src/controllers/data-alias-export.controller.ts b/packages/nocodb/src/controllers/data-alias-export.controller.ts index 2f63ec986b..acc482c8f3 100644 --- a/packages/nocodb/src/controllers/data-alias-export.controller.ts +++ b/packages/nocodb/src/controllers/data-alias-export.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get, Req, Res, UseGuards } from '@nestjs/common'; -import { Request, Response } from 'express'; +import { Response } from 'express'; import * as XLSX from 'xlsx'; import { GlobalGuard } from '~/guards/global/global.guard'; import { DatasService } from '~/services/datas.service'; @@ -7,6 +7,8 @@ import { extractCsvData, extractXlsxData } from '~/helpers/dataHelpers'; import { View } from '~/models'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { DataApiLimiterGuard } from '~/guards/data-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(DataApiLimiterGuard, GlobalGuard) @@ -18,14 +20,25 @@ export class DataAliasExportController { '/api/v1/db/data/:orgs/:baseName/:tableName/views/:viewName/export/excel', ]) @Acl('exportExcel') - async excelDataExport(@Req() req: Request, @Res() res: Response) { + async excelDataExport( + @TenantContext() context: NcContext, + @Req() req: NcRequest, + @Res() res: Response, + ) { const { model, view } = - await this.datasService.getViewAndModelFromRequestByAliasOrId(req); + await this.datasService.getViewAndModelFromRequestByAliasOrId( + context, + req, + ); let targetView = view; if (!targetView) { - targetView = await View.getDefaultView(model.id); + targetView = await View.getDefaultView(context, model.id); } - const { offset, elapsed, data } = await extractXlsxData(targetView, req); + const { offset, elapsed, data } = await extractXlsxData( + context, + targetView, + req, + ); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, data, targetView.title); const buf = XLSX.write(wb, { type: 'base64', bookType: 'xlsx' }); @@ -45,14 +58,25 @@ export class DataAliasExportController { '/api/v1/db/data/:orgs/:baseName/:tableName/export/csv', ]) @Acl('exportCsv') - async csvDataExport(@Req() req: Request, @Res() res: Response) { + async csvDataExport( + @TenantContext() context: NcContext, + @Req() req: NcRequest, + @Res() res: Response, + ) { const { model, view } = - await this.datasService.getViewAndModelFromRequestByAliasOrId(req); + await this.datasService.getViewAndModelFromRequestByAliasOrId( + context, + req, + ); let targetView = view; if (!targetView) { - targetView = await View.getDefaultView(model.id); + targetView = await View.getDefaultView(context, model.id); } - const { offset, elapsed, data } = await extractCsvData(targetView, req); + const { offset, elapsed, data } = await extractCsvData( + context, + targetView, + req, + ); res.set({ 'Access-Control-Expose-Headers': 'nc-export-offset', diff --git a/packages/nocodb/src/controllers/data-alias-nested.controller.ts b/packages/nocodb/src/controllers/data-alias-nested.controller.ts index 9ea4045092..406697d9b8 100644 --- a/packages/nocodb/src/controllers/data-alias-nested.controller.ts +++ b/packages/nocodb/src/controllers/data-alias-nested.controller.ts @@ -8,11 +8,12 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { DataAliasNestedService } from '~/services/data-alias-nested.service'; import { GlobalGuard } from '~/guards/global/global.guard'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { DataApiLimiterGuard } from '~/guards/data-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(DataApiLimiterGuard, GlobalGuard) @@ -23,13 +24,14 @@ export class DataAliasNestedController { @Get(['/api/v1/db/data/:orgs/:baseName/:tableName/:rowId/mm/:columnName']) @Acl('mmList') async mmList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('columnName') columnName: string, @Param('rowId') rowId: string, @Param('baseName') baseName: string, @Param('tableName') tableName: string, ) { - return await this.dataAliasNestedService.mmList({ + return await this.dataAliasNestedService.mmList(context, { query: req.query, columnName: columnName, rowId: rowId, @@ -43,13 +45,14 @@ export class DataAliasNestedController { ]) @Acl('mmExcludedList') async mmExcludedList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('columnName') columnName: string, @Param('rowId') rowId: string, @Param('baseName') baseName: string, @Param('tableName') tableName: string, ) { - return await this.dataAliasNestedService.mmExcludedList({ + return await this.dataAliasNestedService.mmExcludedList(context, { query: req.query, columnName: columnName, rowId: rowId, @@ -63,13 +66,14 @@ export class DataAliasNestedController { ]) @Acl('hmExcludedList') async hmExcludedList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('columnName') columnName: string, @Param('rowId') rowId: string, @Param('baseName') baseName: string, @Param('tableName') tableName: string, ) { - return await this.dataAliasNestedService.hmExcludedList({ + return await this.dataAliasNestedService.hmExcludedList(context, { query: req.query, columnName: columnName, rowId: rowId, @@ -83,13 +87,14 @@ export class DataAliasNestedController { ]) @Acl('btExcludedList') async btExcludedList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('columnName') columnName: string, @Param('rowId') rowId: string, @Param('baseName') baseName: string, @Param('tableName') tableName: string, ) { - return await this.dataAliasNestedService.btExcludedList({ + return await this.dataAliasNestedService.btExcludedList(context, { query: req.query, columnName: columnName, rowId: rowId, @@ -103,13 +108,14 @@ export class DataAliasNestedController { ]) @Acl('ooExcludedList') async ooExcludedList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('columnName') columnName: string, @Param('rowId') rowId: string, @Param('baseName') baseName: string, @Param('tableName') tableName: string, ) { - return await this.dataAliasNestedService.ooExcludedList({ + return await this.dataAliasNestedService.ooExcludedList(context, { query: req.query, columnName: columnName, rowId: rowId, @@ -123,13 +129,14 @@ export class DataAliasNestedController { @Get(['/api/v1/db/data/:orgs/:baseName/:tableName/:rowId/hm/:columnName']) @Acl('hmList') async hmList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('columnName') columnName: string, @Param('rowId') rowId: string, @Param('baseName') baseName: string, @Param('tableName') tableName: string, ) { - return await this.dataAliasNestedService.hmList({ + return await this.dataAliasNestedService.hmList(context, { query: req.query, columnName: columnName, rowId: rowId, @@ -143,14 +150,15 @@ export class DataAliasNestedController { ]) @Acl('relationDataRemove') async relationDataRemove( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('columnName') columnName: string, @Param('rowId') rowId: string, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('refRowId') refRowId: string, ) { - await this.dataAliasNestedService.relationDataRemove({ + await this.dataAliasNestedService.relationDataRemove(context, { columnName: columnName, rowId: rowId, baseName: baseName, @@ -169,14 +177,15 @@ export class DataAliasNestedController { @Acl('relationDataAdd') @HttpCode(200) async relationDataAdd( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('columnName') columnName: string, @Param('rowId') rowId: string, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('refRowId') refRowId: string, ) { - await this.dataAliasNestedService.relationDataAdd({ + await this.dataAliasNestedService.relationDataAdd(context, { columnName: columnName, rowId: rowId, baseName: baseName, diff --git a/packages/nocodb/src/controllers/data-alias.controller.ts b/packages/nocodb/src/controllers/data-alias.controller.ts index a1228605d1..733dcf8383 100644 --- a/packages/nocodb/src/controllers/data-alias.controller.ts +++ b/packages/nocodb/src/controllers/data-alias.controller.ts @@ -12,12 +12,14 @@ import { Res, UseGuards, } from '@nestjs/common'; -import { Request, Response } from 'express'; +import { Response } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { parseHrtimeToMilliSeconds } from '~/helpers'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { DatasService } from '~/services/datas.service'; import { DataApiLimiterGuard } from '~/guards/data-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(DataApiLimiterGuard, GlobalGuard) @@ -31,7 +33,8 @@ export class DataAliasController { ]) @Acl('dataList') async dataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Res() res: Response, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @@ -39,7 +42,7 @@ export class DataAliasController { @Query('opt') opt: string, ) { const startTime = process.hrtime(); - const responseData = await this.datasService.dataList({ + const responseData = await this.datasService.dataList(context, { query: req.query, baseName: baseName, tableName: tableName, @@ -63,12 +66,13 @@ export class DataAliasController { ]) @Acl('dataFindOne') async dataFindOne( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('viewName') viewName: string, ) { - return await this.datasService.dataFindOne({ + return await this.datasService.dataFindOne(context, { query: req.query, baseName: baseName, tableName: tableName, @@ -82,12 +86,13 @@ export class DataAliasController { ]) @Acl('dataGroupBy') async dataGroupBy( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('viewName') viewName: string, ) { - return await this.datasService.dataGroupBy({ + return await this.datasService.dataGroupBy(context, { query: req.query, baseName: baseName, tableName: tableName, @@ -101,13 +106,14 @@ export class DataAliasController { ]) @Acl('dataCount') async dataCount( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Res() res: Response, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('viewName') viewName: string, ) { - const countResult = await this.datasService.dataCount({ + const countResult = await this.datasService.dataCount(context, { query: req.query, baseName: baseName, tableName: tableName, @@ -124,14 +130,15 @@ export class DataAliasController { @HttpCode(200) @Acl('dataInsert') async dataInsert( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('viewName') viewName: string, @Body() body: any, @Query('opt') opt: string, ) { - return await this.datasService.dataInsert({ + return await this.datasService.dataInsert(context, { baseName: baseName, tableName: tableName, viewName: viewName, @@ -147,14 +154,15 @@ export class DataAliasController { ]) @Acl('dataUpdate') async dataUpdate( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('viewName') viewName: string, @Param('rowId') rowId: string, @Query('opt') opt: string, ) { - return await this.datasService.dataUpdate({ + return await this.datasService.dataUpdate(context, { baseName: baseName, tableName: tableName, viewName: viewName, @@ -171,13 +179,14 @@ export class DataAliasController { ]) @Acl('dataDelete') async dataDelete( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('viewName') viewName: string, @Param('rowId') rowId: string, ) { - return await this.datasService.dataDelete({ + return await this.datasService.dataDelete(context, { baseName: baseName, tableName: tableName, viewName: viewName, @@ -192,7 +201,8 @@ export class DataAliasController { ]) @Acl('dataRead') async dataRead( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('viewName') viewName: string, @@ -200,7 +210,7 @@ export class DataAliasController { @Query('opt') opt: string, @Query('getHiddenColumn') getHiddenColumn: boolean, ) { - return await this.datasService.dataRead({ + return await this.datasService.dataRead(context, { baseName: baseName, tableName: tableName, viewName: viewName, @@ -217,14 +227,15 @@ export class DataAliasController { ]) @Acl('dataExist') async dataExist( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Res() res: Response, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @Param('viewName') viewName: string, @Param('rowId') rowId: string, ) { - const exists = await this.datasService.dataExist({ + const exists = await this.datasService.dataExist(context, { baseName: baseName, tableName: tableName, viewName: viewName, @@ -243,7 +254,8 @@ export class DataAliasController { ]) @Acl('groupedDataList') async groupedDataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Res() res: Response, @Param('baseName') baseName: string, @Param('tableName') tableName: string, @@ -251,7 +263,7 @@ export class DataAliasController { @Param('columnId') columnId: string, ) { const startTime = process.hrtime(); - const groupedData = await this.datasService.groupedDataList({ + const groupedData = await this.datasService.groupedDataList(context, { baseName: baseName, tableName: tableName, viewName: viewName, diff --git a/packages/nocodb/src/controllers/data-table.controller.ts b/packages/nocodb/src/controllers/data-table.controller.ts index 04a8501661..e69eba44f1 100644 --- a/packages/nocodb/src/controllers/data-table.controller.ts +++ b/packages/nocodb/src/controllers/data-table.controller.ts @@ -12,12 +12,14 @@ import { Res, UseGuards, } from '@nestjs/common'; -import { Request, Response } from 'express'; +import { Response } from 'express'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { DataTableService } from '~/services/data-table.service'; import { parseHrtimeToMilliSeconds } from '~/helpers'; import { DataApiLimiterGuard } from '~/guards/data-api-limiter.guard'; import { GlobalGuard } from '~/guards/global/global.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(DataApiLimiterGuard, GlobalGuard) @@ -28,13 +30,14 @@ export class DataTableController { @Get('/api/v2/tables/:modelId/records') @Acl('dataList') async dataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Res() res: Response, @Param('modelId') modelId: string, @Query('viewId') viewId: string, ) { const startTime = process.hrtime(); - const responseData = await this.dataTableService.dataList({ + const responseData = await this.dataTableService.dataList(context, { query: req.query, modelId: modelId, viewId: viewId, @@ -47,12 +50,13 @@ export class DataTableController { @Get(['/api/v2/tables/:modelId/records/count']) @Acl('dataCount') async dataCount( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Res() res: Response, @Param('modelId') modelId: string, @Query('viewId') viewId: string, ) { - const countResult = await this.dataTableService.dataCount({ + const countResult = await this.dataTableService.dataCount(context, { query: req.query, modelId, viewId, @@ -65,12 +69,13 @@ export class DataTableController { @HttpCode(200) @Acl('dataInsert') async dataInsert( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('modelId') modelId: string, @Query('viewId') viewId: string, @Body() body: any, ) { - return await this.dataTableService.dataInsert({ + return await this.dataTableService.dataInsert(context, { modelId: modelId, body: body, viewId, @@ -81,12 +86,13 @@ export class DataTableController { @Patch(['/api/v2/tables/:modelId/records']) @Acl('dataUpdate') async dataUpdate( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('modelId') modelId: string, @Query('viewId') viewId: string, @Param('rowId') _rowId: string, ) { - return await this.dataTableService.dataUpdate({ + return await this.dataTableService.dataUpdate(context, { modelId: modelId, body: req.body, cookie: req, @@ -97,12 +103,13 @@ export class DataTableController { @Delete(['/api/v2/tables/:modelId/records']) @Acl('dataDelete') async dataDelete( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('modelId') modelId: string, @Query('viewId') viewId: string, @Param('rowId') _rowId: string, ) { - return await this.dataTableService.dataDelete({ + return await this.dataTableService.dataDelete(context, { modelId: modelId, cookie: req, viewId, @@ -113,12 +120,13 @@ export class DataTableController { @Get(['/api/v2/tables/:modelId/records/:rowId']) @Acl('dataRead') async dataRead( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('modelId') modelId: string, @Query('viewId') viewId: string, @Param('rowId') rowId: string, ) { - return await this.dataTableService.dataRead({ + return await this.dataTableService.dataRead(context, { modelId, rowId: rowId, query: req.query, @@ -129,13 +137,14 @@ export class DataTableController { @Get(['/api/v2/tables/:modelId/links/:columnId/records/:rowId']) @Acl('nestedDataList') async nestedDataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('modelId') modelId: string, @Query('viewId') viewId: string, @Param('columnId') columnId: string, @Param('rowId') rowId: string, ) { - return await this.dataTableService.nestedDataList({ + return await this.dataTableService.nestedDataList(context, { modelId, rowId: rowId, query: req.query, @@ -147,7 +156,8 @@ export class DataTableController { @Post(['/api/v2/tables/:modelId/links/:columnId/records/:rowId']) @Acl('nestedDataLink') async nestedLink( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('modelId') modelId: string, @Query('viewId') viewId: string, @Param('columnId') columnId: string, @@ -161,7 +171,7 @@ export class DataTableController { | Record | Record[], ) { - return await this.dataTableService.nestedLink({ + return await this.dataTableService.nestedLink(context, { modelId, rowId: rowId, query: req.query, @@ -175,7 +185,8 @@ export class DataTableController { @Delete(['/api/v2/tables/:modelId/links/:columnId/records/:rowId']) @Acl('nestedDataUnlink') async nestedUnlink( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('modelId') modelId: string, @Query('viewId') viewId: string, @Param('columnId') columnId: string, @@ -183,7 +194,7 @@ export class DataTableController { @Body() refRowIds: string | string[] | number | number[] | Record, ) { - return await this.dataTableService.nestedUnlink({ + return await this.dataTableService.nestedUnlink(context, { modelId, rowId: rowId, query: req.query, @@ -198,7 +209,8 @@ export class DataTableController { @Post(['/api/v2/tables/:modelId/links/:columnId/records']) @Acl('nestedDataListCopyPasteOrDeleteAll') async nestedListCopyPasteOrDeleteAll( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('modelId') modelId: string, @Query('viewId') viewId: string, @Param('columnId') columnId: string, @@ -210,7 +222,7 @@ export class DataTableController { fk_related_model_id: string; }[], ) { - return await this.dataTableService.nestedListCopyPasteOrDeleteAll({ + return await this.dataTableService.nestedListCopyPasteOrDeleteAll(context, { modelId, query: req.query, viewId, diff --git a/packages/nocodb/src/controllers/datas.controller.ts b/packages/nocodb/src/controllers/datas.controller.ts index 49c51a676c..32823bfebb 100644 --- a/packages/nocodb/src/controllers/datas.controller.ts +++ b/packages/nocodb/src/controllers/datas.controller.ts @@ -10,11 +10,12 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { DatasService } from '~/services/datas.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { DataApiLimiterGuard } from '~/guards/data-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(DataApiLimiterGuard, GlobalGuard) @@ -23,8 +24,12 @@ export class DatasController { @Get('/data/:viewId/') @Acl('dataList') - async dataList(@Req() req: Request, @Param('viewId') viewId: string) { - return await this.datasService.dataListByViewId({ + async dataList( + @TenantContext() context: NcContext, + @Req() req: NcRequest, + @Param('viewId') viewId: string, + ) { + return await this.datasService.dataListByViewId(context, { viewId: viewId, query: req.query, }); @@ -33,12 +38,13 @@ export class DatasController { @Get('/data/:viewId/:rowId/mm/:colId') @Acl('mmList') async mmList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('colId') colId: string, @Param('rowId') rowId: string, ) { - return await this.datasService.mmList({ + return await this.datasService.mmList(context, { viewId: viewId, colId: colId, rowId: rowId, @@ -49,12 +55,13 @@ export class DatasController { @Get('/data/:viewId/:rowId/mm/:colId/exclude') @Acl('mmExcludedList') async mmExcludedList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('colId') colId: string, @Param('rowId') rowId: string, ) { - return await this.datasService.mmExcludedList({ + return await this.datasService.mmExcludedList(context, { viewId: viewId, colId: colId, rowId: rowId, @@ -65,12 +72,13 @@ export class DatasController { @Get('/data/:viewId/:rowId/hm/:colId/exclude') @Acl('hmExcludedList') async hmExcludedList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('colId') colId: string, @Param('rowId') rowId: string, ) { - await this.datasService.hmExcludedList({ + await this.datasService.hmExcludedList(context, { viewId: viewId, colId: colId, rowId: rowId, @@ -81,12 +89,13 @@ export class DatasController { @Get('/data/:viewId/:rowId/bt/:colId/exclude') @Acl('btExcludedList') async btExcludedList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('colId') colId: string, @Param('rowId') rowId: string, ) { - return await this.datasService.btExcludedList({ + return await this.datasService.btExcludedList(context, { viewId: viewId, colId: colId, rowId: rowId, @@ -97,12 +106,13 @@ export class DatasController { @Get('/data/:viewId/:rowId/hm/:colId') @Acl('hmList') async hmList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('colId') colId: string, @Param('rowId') rowId: string, ) { - return await this.datasService.hmList({ + return await this.datasService.hmList(context, { viewId: viewId, colId: colId, rowId: rowId, @@ -113,11 +123,12 @@ export class DatasController { @Get('/data/:viewId/:rowId') @Acl('dataRead') async dataRead( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('rowId') rowId: string, ) { - return await this.datasService.dataReadByViewId({ + return await this.datasService.dataReadByViewId(context, { viewId, rowId, query: req.query, @@ -128,11 +139,12 @@ export class DatasController { @HttpCode(200) @Acl('dataInsert') async dataInsert( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Body() body: any, ) { - return await this.datasService.dataInsertByViewId({ + return await this.datasService.dataInsertByViewId(context, { viewId: viewId, body: body, cookie: req, @@ -142,12 +154,13 @@ export class DatasController { @Patch('/data/:viewId/:rowId') @Acl('dataUpdate') async dataUpdate( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('rowId') rowId: string, @Body() body: any, ) { - return await this.datasService.dataUpdateByViewId({ + return await this.datasService.dataUpdateByViewId(context, { viewId: viewId, rowId: rowId, body: body, @@ -158,11 +171,12 @@ export class DatasController { @Delete('/data/:viewId/:rowId') @Acl('dataDelete') async dataDelete( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('rowId') rowId: string, ) { - return await this.datasService.dataDeleteByViewId({ + return await this.datasService.dataDeleteByViewId(context, { viewId: viewId, rowId: rowId, cookie: req, @@ -172,14 +186,15 @@ export class DatasController { @Delete('/data/:viewId/:rowId/:relationType/:colId/:childId') @Acl('relationDataDelete') async relationDataDelete( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('rowId') rowId: string, @Param('relationType') relationType: string, @Param('colId') colId: string, @Param('childId') childId: string, ) { - await this.datasService.relationDataDelete({ + await this.datasService.relationDataDelete(context, { viewId: viewId, colId: colId, childId: childId, @@ -194,14 +209,15 @@ export class DatasController { @HttpCode(200) @Acl('relationDataAdd') async relationDataAdd( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('viewId') viewId: string, @Param('rowId') rowId: string, @Param('relationType') relationType: string, @Param('colId') colId: string, @Param('childId') childId: string, ) { - await this.datasService.relationDataAdd({ + await this.datasService.relationDataAdd(context, { viewId: viewId, colId: colId, childId: childId, diff --git a/packages/nocodb/src/controllers/extensions.controller.ts b/packages/nocodb/src/controllers/extensions.controller.ts index 5332794d5c..1472c7f18d 100644 --- a/packages/nocodb/src/controllers/extensions.controller.ts +++ b/packages/nocodb/src/controllers/extensions.controller.ts @@ -14,8 +14,9 @@ import { GlobalGuard } from '~/guards/global/global.guard'; import { ExtensionsService } from '~/services/extensions.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; -import { NcRequest } from '~/interface/config'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -24,20 +25,25 @@ export class ExtensionsController { @Get(['/api/v2/extensions/:baseId']) @Acl('extensionList') - async extensionList(@Param('baseId') baseId: string, @Req() _req: NcRequest) { + async extensionList( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + @Req() _req: NcRequest, + ) { return new PagedResponseImpl( - await this.extensionsService.extensionList({ baseId }), + await this.extensionsService.extensionList(context, { baseId }), ); } @Post(['/api/v2/extensions/:baseId']) @Acl('extensionCreate') async extensionCreate( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Body() body: Partial, @Req() req: NcRequest, ) { - return await this.extensionsService.extensionCreate({ + return await this.extensionsService.extensionCreate(context, { extension: { ...body, base_id: baseId, @@ -48,18 +54,22 @@ export class ExtensionsController { @Get(['/api/v2/extensions/:extensionId']) @Acl('extensionRead') - async extensionRead(@Param('extensionId') extensionId: string) { - return await this.extensionsService.extensionRead({ extensionId }); + async extensionRead( + @TenantContext() context: NcContext, + @Param('extensionId') extensionId: string, + ) { + return await this.extensionsService.extensionRead(context, { extensionId }); } @Patch(['/api/v2/extensions/:extensionId']) @Acl('extensionUpdate') async extensionUpdate( + @TenantContext() context: NcContext, @Param('extensionId') extensionId: string, @Body() body: Partial, @Req() req: NcRequest, ) { - return await this.extensionsService.extensionUpdate({ + return await this.extensionsService.extensionUpdate(context, { extensionId, extension: body, req, @@ -69,10 +79,11 @@ export class ExtensionsController { @Delete(['/api/v2/extensions/:extensionId']) @Acl('extensionDelete') async extensionDelete( + @TenantContext() context: NcContext, @Param('extensionId') extensionId: string, @Req() req: NcRequest, ) { - return await this.extensionsService.extensionDelete({ + return await this.extensionsService.extensionDelete(context, { extensionId, req, }); diff --git a/packages/nocodb/src/controllers/filters.controller.ts b/packages/nocodb/src/controllers/filters.controller.ts index c435914af3..567e136962 100644 --- a/packages/nocodb/src/controllers/filters.controller.ts +++ b/packages/nocodb/src/controllers/filters.controller.ts @@ -10,13 +10,14 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { FilterReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { FiltersService } from '~/services/filters.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -28,9 +29,12 @@ export class FiltersController { '/api/v2/meta/views/:viewId/filters', ]) @Acl('filterList') - async filterList(@Param('viewId') viewId: string) { + async filterList( + @TenantContext() context: NcContext, + @Param('viewId') viewId: string, + ) { return new PagedResponseImpl( - await this.filtersService.filterList({ + await this.filtersService.filterList(context, { viewId, }), ); @@ -43,11 +47,12 @@ export class FiltersController { @HttpCode(200) @Acl('filterCreate') async filterCreate( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Body() body: FilterReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - const filter = await this.filtersService.filterCreate({ + const filter = await this.filtersService.filterCreate(context, { filter: body, viewId: viewId, user: req.user, @@ -63,11 +68,12 @@ export class FiltersController { @HttpCode(200) @Acl('hookFilterCreate') async hookFilterCreate( + @TenantContext() context: NcContext, @Param('hookId') hookId: string, @Body() body: FilterReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - const filter = await this.filtersService.hookFilterCreate({ + const filter = await this.filtersService.hookFilterCreate(context, { filter: body, hookId, user: req.user, @@ -78,8 +84,11 @@ export class FiltersController { @Get(['/api/v1/db/meta/filters/:filterId', '/api/v2/meta/filters/:filterId']) @Acl('filterGet') - async filterGet(@Param('filterId') filterId: string) { - return await this.filtersService.filterGet({ filterId }); + async filterGet( + @TenantContext() context: NcContext, + @Param('filterId') filterId: string, + ) { + return await this.filtersService.filterGet(context, { filterId }); } @Get([ @@ -87,9 +96,12 @@ export class FiltersController { '/api/v2/meta/filters/:filterParentId/children', ]) @Acl('filterChildrenList') - async filterChildrenRead(@Param('filterParentId') filterParentId: string) { + async filterChildrenRead( + @TenantContext() context: NcContext, + @Param('filterParentId') filterParentId: string, + ) { return new PagedResponseImpl( - await this.filtersService.filterChildrenList({ + await this.filtersService.filterChildrenList(context, { filterId: filterParentId, }), ); @@ -101,11 +113,12 @@ export class FiltersController { ]) @Acl('filterUpdate') async filterUpdate( + @TenantContext() context: NcContext, @Param('filterId') filterId: string, @Body() body: FilterReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - const filter = await this.filtersService.filterUpdate({ + const filter = await this.filtersService.filterUpdate(context, { filterId: filterId, filter: body, user: req.user, @@ -119,8 +132,12 @@ export class FiltersController { '/api/v2/meta/filters/:filterId', ]) @Acl('filterDelete') - async filterDelete(@Param('filterId') filterId: string, @Req() req: Request) { - const filter = await this.filtersService.filterDelete({ + async filterDelete( + @TenantContext() context: NcContext, + @Param('filterId') filterId: string, + @Req() req: NcRequest, + ) { + const filter = await this.filtersService.filterDelete(context, { req, filterId, }); @@ -132,9 +149,12 @@ export class FiltersController { '/api/v2/meta/hooks/:hookId/filters', ]) @Acl('hookFilterList') - async hookFilterList(@Param('hookId') hookId: string) { + async hookFilterList( + @TenantContext() context: NcContext, + @Param('hookId') hookId: string, + ) { return new PagedResponseImpl( - await this.filtersService.hookFilterList({ + await this.filtersService.hookFilterList(context, { hookId: hookId, }), ); diff --git a/packages/nocodb/src/controllers/form-columns.controller.ts b/packages/nocodb/src/controllers/form-columns.controller.ts index 3dd212036c..99e0462d8b 100644 --- a/packages/nocodb/src/controllers/form-columns.controller.ts +++ b/packages/nocodb/src/controllers/form-columns.controller.ts @@ -1,9 +1,10 @@ import { Body, Controller, Param, Patch, Req, UseGuards } from '@nestjs/common'; -import { Request } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { FormColumnsService } from '~/services/form-columns.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; class FormColumnUpdateReqType {} @@ -18,12 +19,13 @@ export class FormColumnsController { ]) @Acl('formViewUpdate') async columnUpdate( + @TenantContext() context: NcContext, @Param('formViewColumnId') formViewColumnId: string, @Body() formViewColumnbody: FormColumnUpdateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.formColumnsService.columnUpdate({ + return await this.formColumnsService.columnUpdate(context, { formViewColumnId, formViewColumn: formViewColumnbody, req, diff --git a/packages/nocodb/src/controllers/forms.controller.ts b/packages/nocodb/src/controllers/forms.controller.ts index bbf2d65cdd..6264fda8d7 100644 --- a/packages/nocodb/src/controllers/forms.controller.ts +++ b/packages/nocodb/src/controllers/forms.controller.ts @@ -9,12 +9,13 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { ViewCreateReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { FormsService } from '~/services/forms.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -23,8 +24,11 @@ export class FormsController { @Get(['/api/v1/db/meta/forms/:formViewId', '/api/v2/meta/forms/:formViewId']) @Acl('formViewGet') - async formViewGet(@Param('formViewId') formViewId: string) { - const formViewData = await this.formsService.formViewGet({ + async formViewGet( + @TenantContext() context: NcContext, + @Param('formViewId') formViewId: string, + ) { + const formViewData = await this.formsService.formViewGet(context, { formViewId, }); return formViewData; @@ -37,11 +41,12 @@ export class FormsController { @HttpCode(200) @Acl('formViewCreate') async formViewCreate( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: ViewCreateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - const view = await this.formsService.formViewCreate({ + const view = await this.formsService.formViewCreate(context, { body, tableId, user: req.user, @@ -55,11 +60,12 @@ export class FormsController { ]) @Acl('formViewUpdate') async formViewUpdate( + @TenantContext() context: NcContext, @Param('formViewId') formViewId: string, @Body() body, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.formsService.formViewUpdate({ + return await this.formsService.formViewUpdate(context, { formViewId, form: body, req, diff --git a/packages/nocodb/src/controllers/galleries.controller.ts b/packages/nocodb/src/controllers/galleries.controller.ts index c9440b3cfe..d1b82a47f6 100644 --- a/packages/nocodb/src/controllers/galleries.controller.ts +++ b/packages/nocodb/src/controllers/galleries.controller.ts @@ -9,12 +9,13 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { GalleryUpdateReqType, ViewCreateReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { GalleriesService } from '~/services/galleries.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -26,8 +27,11 @@ export class GalleriesController { '/api/v2/meta/galleries/:galleryViewId', ]) @Acl('galleryViewGet') - async galleryViewGet(@Param('galleryViewId') galleryViewId: string) { - return await this.galleriesService.galleryViewGet({ + async galleryViewGet( + @TenantContext() context: NcContext, + @Param('galleryViewId') galleryViewId: string, + ) { + return await this.galleriesService.galleryViewGet(context, { galleryViewId, }); } @@ -39,11 +43,12 @@ export class GalleriesController { @HttpCode(200) @Acl('galleryViewCreate') async galleryViewCreate( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: ViewCreateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.galleriesService.galleryViewCreate({ + return await this.galleriesService.galleryViewCreate(context, { gallery: body, // todo: sanitize tableId, @@ -58,12 +63,13 @@ export class GalleriesController { ]) @Acl('galleryViewUpdate') async galleryViewUpdate( + @TenantContext() context: NcContext, @Param('galleryViewId') galleryViewId: string, @Body() body: GalleryUpdateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.galleriesService.galleryViewUpdate({ + return await this.galleriesService.galleryViewUpdate(context, { galleryViewId, gallery: body, req, diff --git a/packages/nocodb/src/controllers/grid-columns.controller.ts b/packages/nocodb/src/controllers/grid-columns.controller.ts index 039ff3154a..db4d0702ff 100644 --- a/packages/nocodb/src/controllers/grid-columns.controller.ts +++ b/packages/nocodb/src/controllers/grid-columns.controller.ts @@ -12,7 +12,8 @@ import { GlobalGuard } from '~/guards/global/global.guard'; import { GridColumnsService } from '~/services/grid-columns.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; -import { NcRequest } from '~/interface/config'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -24,8 +25,11 @@ export class GridColumnsController { '/api/v2/meta/grids/:gridViewId/grid-columns', ]) @Acl('columnList') - async columnList(@Param('gridViewId') gridViewId: string) { - return await this.gridColumnsService.columnList({ + async columnList( + @TenantContext() context: NcContext, + @Param('gridViewId') gridViewId: string, + ) { + return await this.gridColumnsService.columnList(context, { gridViewId, }); } @@ -35,12 +39,13 @@ export class GridColumnsController { ]) @Acl('gridColumnUpdate') async gridColumnUpdate( + @TenantContext() context: NcContext, @Param('gridViewColumnId') gridViewColumnId: string, @Body() body: GridColumnReqType, @Req() req: NcRequest, ) { - return this.gridColumnsService.gridColumnUpdate({ + return this.gridColumnsService.gridColumnUpdate(context, { gridViewColumnId, grid: body, req, diff --git a/packages/nocodb/src/controllers/grids.controller.ts b/packages/nocodb/src/controllers/grids.controller.ts index b3a7a00e79..c3b37c306e 100644 --- a/packages/nocodb/src/controllers/grids.controller.ts +++ b/packages/nocodb/src/controllers/grids.controller.ts @@ -13,7 +13,8 @@ import { GlobalGuard } from '~/guards/global/global.guard'; import { GridsService } from '~/services/grids.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; -import { NcRequest } from '~/interface/config'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -27,11 +28,12 @@ export class GridsController { @HttpCode(200) @Acl('gridViewCreate') async gridViewCreate( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: ViewCreateReqType, @Req() req: NcRequest, ) { - const view = await this.gridsService.gridViewCreate({ + const view = await this.gridsService.gridViewCreate(context, { grid: body, tableId, req, @@ -41,11 +43,12 @@ export class GridsController { @Patch(['/api/v1/db/meta/grids/:viewId', '/api/v2/meta/grids/:viewId']) @Acl('gridViewUpdate') async gridViewUpdate( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Body() body, @Req() req: NcRequest, ) { - return await this.gridsService.gridViewUpdate({ + return await this.gridsService.gridViewUpdate(context, { viewId, grid: body, req, diff --git a/packages/nocodb/src/controllers/hooks.controller.ts b/packages/nocodb/src/controllers/hooks.controller.ts index ef3e951d4a..a46234ea01 100644 --- a/packages/nocodb/src/controllers/hooks.controller.ts +++ b/packages/nocodb/src/controllers/hooks.controller.ts @@ -10,7 +10,6 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { HookReqType, HookTestReqType } from 'nocodb-sdk'; import type { HookType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; @@ -18,6 +17,8 @@ import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { HooksService } from '~/services/hooks.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -29,8 +30,13 @@ export class HooksController { '/api/v2/meta/tables/:tableId/hooks', ]) @Acl('hookList') - async hookList(@Param('tableId') tableId: string) { - return new PagedResponseImpl(await this.hooksService.hookList({ tableId })); + async hookList( + @TenantContext() context: NcContext, + @Param('tableId') tableId: string, + ) { + return new PagedResponseImpl( + await this.hooksService.hookList(context, { tableId }), + ); } @Post([ @@ -40,11 +46,12 @@ export class HooksController { @HttpCode(200) @Acl('hookCreate') async hookCreate( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: HookReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - const hook = await this.hooksService.hookCreate({ + const hook = await this.hooksService.hookCreate(context, { hook: body, tableId, req, @@ -54,18 +61,27 @@ export class HooksController { @Delete(['/api/v1/db/meta/hooks/:hookId', '/api/v2/meta/hooks/:hookId']) @Acl('hookDelete') - async hookDelete(@Param('hookId') hookId: string, @Req() req: Request) { - return await this.hooksService.hookDelete({ hookId, req }); + async hookDelete( + @TenantContext() context: NcContext, + @Param('hookId') hookId: string, + @Req() req: NcRequest, + ) { + return await this.hooksService.hookDelete(context, { hookId, req }); } @Patch(['/api/v1/db/meta/hooks/:hookId', '/api/v2/meta/hooks/:hookId']) @Acl('hookUpdate') async hookUpdate( + @TenantContext() context: NcContext, @Param('hookId') hookId: string, @Body() body: HookReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.hooksService.hookUpdate({ hookId, hook: body, req }); + return await this.hooksService.hookUpdate(context, { + hookId, + hook: body, + req, + }); } @Post([ @@ -74,9 +90,13 @@ export class HooksController { ]) @HttpCode(200) @Acl('hookTest') - async hookTest(@Body() body: HookTestReqType, @Req() req: Request) { + async hookTest( + @TenantContext() context: NcContext, + @Body() body: HookTestReqType, + @Req() req: NcRequest, + ) { try { - await this.hooksService.hookTest({ + await this.hooksService.hookTest(context, { hookTest: { ...body, payload: { @@ -100,11 +120,12 @@ export class HooksController { ]) @Acl('tableSampleData') async tableSampleData( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Param('operation') operation: HookType['operation'], @Param('version') version: HookType['version'], ) { - return await this.hooksService.tableSampleData({ + return await this.hooksService.tableSampleData(context, { tableId, operation, version, @@ -116,15 +137,19 @@ export class HooksController { '/api/v2/meta/hooks/:hookId/logs', ]) @Acl('hookLogList') - async hookLogList(@Param('hookId') hookId: string, @Req() req: Request) { + async hookLogList( + @TenantContext() context: NcContext, + @Param('hookId') hookId: string, + @Req() req: NcRequest, + ) { return new PagedResponseImpl( - await this.hooksService.hookLogList({ + await this.hooksService.hookLogList(context, { query: req.query, hookId, }), { ...req.query, - count: await this.hooksService.hookLogCount({ + count: await this.hooksService.hookLogCount(context, { hookId, }), }, diff --git a/packages/nocodb/src/controllers/kanbans.controller.ts b/packages/nocodb/src/controllers/kanbans.controller.ts index 656bf59905..e058271071 100644 --- a/packages/nocodb/src/controllers/kanbans.controller.ts +++ b/packages/nocodb/src/controllers/kanbans.controller.ts @@ -9,12 +9,13 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { ViewCreateReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { KanbansService } from '~/services/kanbans.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -26,8 +27,11 @@ export class KanbansController { '/api/v2/meta/kanbans/:kanbanViewId', ]) @Acl('kanbanViewGet') - async kanbanViewGet(@Param('kanbanViewId') kanbanViewId: string) { - return await this.kanbansService.kanbanViewGet({ + async kanbanViewGet( + @TenantContext() context: NcContext, + @Param('kanbanViewId') kanbanViewId: string, + ) { + return await this.kanbansService.kanbanViewGet(context, { kanbanViewId, }); } @@ -39,11 +43,12 @@ export class KanbansController { @HttpCode(200) @Acl('kanbanViewCreate') async kanbanViewCreate( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: ViewCreateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.kanbansService.kanbanViewCreate({ + return await this.kanbansService.kanbanViewCreate(context, { tableId, kanban: body, user: req.user, @@ -57,12 +62,13 @@ export class KanbansController { ]) @Acl('kanbanViewUpdate') async kanbanViewUpdate( + @TenantContext() context: NcContext, @Param('kanbanViewId') kanbanViewId: string, @Body() body, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.kanbansService.kanbanViewUpdate({ + return await this.kanbansService.kanbanViewUpdate(context, { kanbanViewId, kanban: body, req, diff --git a/packages/nocodb/src/controllers/maps.controller.ts b/packages/nocodb/src/controllers/maps.controller.ts index 7131125e89..5f29b9e0e7 100644 --- a/packages/nocodb/src/controllers/maps.controller.ts +++ b/packages/nocodb/src/controllers/maps.controller.ts @@ -9,12 +9,13 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { MapUpdateReqType, ViewCreateReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { MapsService } from '~/services/maps.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -23,8 +24,11 @@ export class MapsController { @Get(['/api/v1/db/meta/maps/:mapViewId', '/api/v2/meta/maps/:mapViewId']) @Acl('mapViewGet') - async mapViewGet(@Param('mapViewId') mapViewId: string) { - return await this.mapsService.mapViewGet({ mapViewId }); + async mapViewGet( + @TenantContext() context: NcContext, + @Param('mapViewId') mapViewId: string, + ) { + return await this.mapsService.mapViewGet(context, { mapViewId }); } @Post([ @@ -34,11 +38,12 @@ export class MapsController { @HttpCode(200) @Acl('mapViewCreate') async mapViewCreate( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: ViewCreateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - const view = await this.mapsService.mapViewCreate({ + const view = await this.mapsService.mapViewCreate(context, { tableId, map: body, user: req.user, @@ -50,12 +55,13 @@ export class MapsController { @Patch(['/api/v1/db/meta/maps/:mapViewId', '/api/v2/meta/maps/:mapViewId']) @Acl('mapViewUpdate') async mapViewUpdate( + @TenantContext() context: NcContext, @Param('mapViewId') mapViewId: string, @Body() body: MapUpdateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.mapsService.mapViewUpdate({ + return await this.mapsService.mapViewUpdate(context, { mapViewId: mapViewId, map: body, req, diff --git a/packages/nocodb/src/controllers/meta-diffs.controller.ts b/packages/nocodb/src/controllers/meta-diffs.controller.ts index d974a92cb3..b2abb16d34 100644 --- a/packages/nocodb/src/controllers/meta-diffs.controller.ts +++ b/packages/nocodb/src/controllers/meta-diffs.controller.ts @@ -3,6 +3,8 @@ import { GlobalGuard } from '~/guards/global/global.guard'; import { MetaDiffsService } from '~/services/meta-diffs.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -14,8 +16,11 @@ export class MetaDiffsController { '/api/v2/meta/bases/:baseId/meta-diff', ]) @Acl('metaDiff') - async metaDiff(@Param('baseId') baseId: string) { - return await this.metaDiffsService.metaDiff({ baseId }); + async metaDiff( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + ) { + return await this.metaDiffsService.metaDiff(context, { baseId }); } @Get([ @@ -24,10 +29,11 @@ export class MetaDiffsController { ]) @Acl('metaDiff') async baseMetaDiff( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('sourceId') sourceId: string, ) { - return await this.metaDiffsService.baseMetaDiff({ + return await this.metaDiffsService.baseMetaDiff(context, { sourceId, baseId, }); diff --git a/packages/nocodb/src/controllers/model-visibilities.controller.ts b/packages/nocodb/src/controllers/model-visibilities.controller.ts index 6e0f49b9a7..1dbba1e8f6 100644 --- a/packages/nocodb/src/controllers/model-visibilities.controller.ts +++ b/packages/nocodb/src/controllers/model-visibilities.controller.ts @@ -13,7 +13,8 @@ import { GlobalGuard } from '~/guards/global/global.guard'; import { ModelVisibilitiesService } from '~/services/model-visibilities.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; -import { NcRequest } from '~/interface/config'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -29,11 +30,12 @@ export class ModelVisibilitiesController { @HttpCode(200) @Acl('modelVisibilitySet') async xcVisibilityMetaSetAll( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Body() body: any, @Req() req: NcRequest, ) { - await this.modelVisibilitiesService.xcVisibilityMetaSetAll({ + await this.modelVisibilitiesService.xcVisibilityMetaSetAll(context, { visibilityRule: body, baseId, req, @@ -48,10 +50,11 @@ export class ModelVisibilitiesController { ]) @Acl('modelVisibilityList') async modelVisibilityList( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Query('includeM2M') includeM2M: boolean | string, ) { - return await this.modelVisibilitiesService.xcVisibilityMetaGet({ + return await this.modelVisibilitiesService.xcVisibilityMetaGet(context, { baseId, includeM2M: includeM2M === true || includeM2M === 'true', }); diff --git a/packages/nocodb/src/controllers/notifications.controller.ts b/packages/nocodb/src/controllers/notifications.controller.ts index 751e21ab3c..e3d180d3e9 100644 --- a/packages/nocodb/src/controllers/notifications.controller.ts +++ b/packages/nocodb/src/controllers/notifications.controller.ts @@ -18,8 +18,8 @@ import { GlobalGuard } from '~/guards/global/global.guard'; import { extractProps } from '~/helpers/extractProps'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { NcRequest } from '~/interface/config'; -import { NcError } from '~/helpers/catchError'; import { PubSubRedis } from '~/redis/pubsub-redis'; +import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14); const POLL_INTERVAL = 30000; @@ -30,6 +30,9 @@ export class NotificationsController { constructor(private readonly notificationsService: NotificationsService) {} @Get('/api/v1/notifications/poll') + @Acl('notification', { + scope: 'org', + }) async notificationPoll( @Req() req: NcRequest, @Res() @@ -40,10 +43,6 @@ export class NotificationsController { res.setHeader('Cache-Control', 'no-cache, must-revalidate'); res.resId = nanoidv2(); - if (!req.user?.id) { - NcError.authenticationRequired(); - } - this.notificationsService.addConnection(req.user.id, res); if (PubSubRedis.available) { @@ -72,6 +71,9 @@ export class NotificationsController { } @Get('/api/v1/notifications') + @Acl('notification', { + scope: 'org', + }) async notificationList(@Req() req: NcRequest) { return this.notificationsService.notificationList({ user: req.user, @@ -82,6 +84,9 @@ export class NotificationsController { } @Patch('/api/v1/notifications/:notificationId') + @Acl('notification', { + scope: 'org', + }) async notificationUpdate( @Param('notificationId') notificationId, @Body() body, @@ -95,6 +100,9 @@ export class NotificationsController { } @Delete('/api/v1/notifications/:notificationId') + @Acl('notification', { + scope: 'org', + }) async notificationDelete( @Param('notificationId') notificationId, @Req() req: NcRequest, @@ -106,6 +114,9 @@ export class NotificationsController { } @Post('/api/v1/notifications/mark-all-read') + @Acl('notification', { + scope: 'org', + }) @HttpCode(200) async markAllRead(@Req() req: NcRequest) { return this.notificationsService.markAllRead({ diff --git a/packages/nocodb/src/controllers/old-datas/old-datas.controller.ts b/packages/nocodb/src/controllers/old-datas/old-datas.controller.ts index aacec8edef..57f889f3e7 100644 --- a/packages/nocodb/src/controllers/old-datas/old-datas.controller.ts +++ b/packages/nocodb/src/controllers/old-datas/old-datas.controller.ts @@ -15,6 +15,8 @@ import { OldDatasService } from './old-datas.service'; import { GlobalGuard } from '~/guards/global/global.guard'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { DataApiLimiterGuard } from '~/guards/data-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext } from '~/interface/config'; @Controller() @UseGuards(DataApiLimiterGuard, GlobalGuard) @@ -24,13 +26,14 @@ export class OldDatasController { @Get('/nc/:baseId/api/v1/:tableName') @Acl('dataList') async dataList( + @TenantContext() context: NcContext, @Request() req, @Response() res, @Param('baseId') baseId: string, @Param('tableName') tableName: string, ) { res.json( - await this.oldDatasService.dataList({ + await this.oldDatasService.dataList(context, { query: req.query, baseId: baseId, tableName: tableName, @@ -41,13 +44,14 @@ export class OldDatasController { @Get('/nc/:baseId/api/v1/:tableName/count') @Acl('dataCount') async dataCount( + @TenantContext() context: NcContext, @Request() req, @Response() res, @Param('baseId') baseId: string, @Param('tableName') tableName: string, ) { res.json( - await this.oldDatasService.dataCount({ + await this.oldDatasService.dataCount(context, { query: req.query, baseId: baseId, tableName: tableName, @@ -59,6 +63,7 @@ export class OldDatasController { @HttpCode(200) @Acl('dataInsert') async dataInsert( + @TenantContext() context: NcContext, @Request() req, @Response() res, @Param('baseId') baseId: string, @@ -66,7 +71,7 @@ export class OldDatasController { @Body() body: any, ) { res.json( - await this.oldDatasService.dataInsert({ + await this.oldDatasService.dataInsert(context, { baseId: baseId, tableName: tableName, body: body, @@ -78,6 +83,7 @@ export class OldDatasController { @Get('/nc/:baseId/api/v1/:tableName/:rowId') @Acl('dataRead') async dataRead( + @TenantContext() context: NcContext, @Request() req, @Response() res, @Param('baseId') baseId: string, @@ -85,7 +91,7 @@ export class OldDatasController { @Param('rowId') rowId: string, ) { res.json( - await this.oldDatasService.dataRead({ + await this.oldDatasService.dataRead(context, { baseId: baseId, tableName: tableName, rowId: rowId, @@ -97,6 +103,7 @@ export class OldDatasController { @Patch('/nc/:baseId/api/v1/:tableName/:rowId') @Acl('dataUpdate') async dataUpdate( + @TenantContext() context: NcContext, @Request() req, @Response() res, @Param('baseId') baseId: string, @@ -104,7 +111,7 @@ export class OldDatasController { @Param('rowId') rowId: string, ) { res.json( - await this.oldDatasService.dataUpdate({ + await this.oldDatasService.dataUpdate(context, { baseId: baseId, tableName: tableName, body: req.body, @@ -117,6 +124,7 @@ export class OldDatasController { @Delete('/nc/:baseId/api/v1/:tableName/:rowId') @Acl('dataDelete') async dataDelete( + @TenantContext() context: NcContext, @Request() req, @Response() res, @Param('baseId') baseId: string, @@ -124,7 +132,7 @@ export class OldDatasController { @Param('rowId') rowId: string, ) { res.json( - await this.oldDatasService.dataDelete({ + await this.oldDatasService.dataDelete(context, { baseId: baseId, tableName: tableName, cookie: req, 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 2e1c9c56a7..d74b1028a5 100644 --- a/packages/nocodb/src/controllers/old-datas/old-datas.service.ts +++ b/packages/nocodb/src/controllers/old-datas/old-datas.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { nocoExecute } from 'nc-help'; import type { OldPathParams } from '~/helpers/dataHelpers'; +import type { NcContext } from '~/interface/config'; import getAst from '~/helpers/getAst'; import { NcError } from '~/helpers/catchError'; import { Base, Model, Source, View } from '~/models'; @@ -8,17 +9,20 @@ import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; @Injectable() export class OldDatasService { - async dataList(param: OldPathParams & { query: any }) { - const { model, view } = await this.getViewAndModelFromRequest(param); - const source = await Source.get(model.source_id); + async dataList(context: NcContext, param: OldPathParams & { query: any }) { + const { model, view } = await this.getViewAndModelFromRequest( + context, + param, + ); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { ast } = await getAst({ + const { ast } = await getAst(context, { query: param.query, model, view, @@ -35,11 +39,14 @@ export class OldDatasService { return await nocoExecute(ast, await baseModel.list(listArgs), {}, listArgs); } - async dataCount(param: OldPathParams & { query: any }) { - const { model, view } = await this.getViewAndModelFromRequest(param); - const source = await Source.get(model.source_id); + async dataCount(context: NcContext, param: OldPathParams & { query: any }) { + const { model, view } = await this.getViewAndModelFromRequest( + context, + param, + ); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -53,12 +60,18 @@ export class OldDatasService { return await baseModel.count(listArgs); } - async dataInsert(param: OldPathParams & { body: unknown; cookie: any }) { - const { model, view } = await this.getViewAndModelFromRequest(param); + async dataInsert( + context: NcContext, + param: OldPathParams & { body: unknown; cookie: any }, + ) { + const { model, view } = await this.getViewAndModelFromRequest( + context, + param, + ); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -67,18 +80,24 @@ export class OldDatasService { return await baseModel.insert(param.body, null, param.cookie); } - async dataRead(param: OldPathParams & { query: any; rowId: string }) { - const { model, view } = await this.getViewAndModelFromRequest(param); + async dataRead( + context: NcContext, + param: OldPathParams & { query: any; rowId: string }, + ) { + const { model, view } = await this.getViewAndModelFromRequest( + context, + param, + ); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { ast } = await getAst({ + const { ast } = await getAst(context, { query: param.query, model, view, @@ -93,12 +112,16 @@ export class OldDatasService { } async dataUpdate( + context: NcContext, param: OldPathParams & { body: unknown; cookie: any; rowId: string }, ) { - const { model, view } = await this.getViewAndModelFromRequest(param); - const source = await Source.get(model.source_id); + const { model, view } = await this.getViewAndModelFromRequest( + context, + param, + ); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -112,10 +135,16 @@ export class OldDatasService { ); } - async dataDelete(param: OldPathParams & { rowId: string; cookie: any }) { - const { model, view } = await this.getViewAndModelFromRequest(param); - const source = await Source.get(model.source_id); - const baseModel = await Model.getBaseModelSQL({ + async dataDelete( + context: NcContext, + param: OldPathParams & { rowId: string; cookie: any }, + ) { + const { model, view } = await this.getViewAndModelFromRequest( + context, + param, + ); + const source = await Source.get(context, model.source_id); + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -124,15 +153,15 @@ export class OldDatasService { return await baseModel.delByPk(param.rowId, null, param.cookie); } - async getViewAndModelFromRequest(req) { - const base = await Base.getWithInfo(req.params.baseId); - const model = await Model.getByAliasOrId({ + async getViewAndModelFromRequest(context: NcContext, req) { + const base = await Base.getWithInfo(context, req.params.baseId); + const model = await Model.getByAliasOrId(context, { base_id: base.id, aliasOrId: req.params.tableName, }); const view = req.params.viewName && - (await View.getByTitleOrId({ + (await View.getByTitleOrId(context, { titleOrId: req.params.viewName, fk_model_id: model.id, })); diff --git a/packages/nocodb/src/controllers/org-tokens.controller.ts b/packages/nocodb/src/controllers/org-tokens.controller.ts index 49540aef0c..a879471fd1 100644 --- a/packages/nocodb/src/controllers/org-tokens.controller.ts +++ b/packages/nocodb/src/controllers/org-tokens.controller.ts @@ -9,7 +9,6 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { ApiTokenReqType } from 'nocodb-sdk'; import { AuthGuard } from '@nestjs/passport'; import { getConditionalHandler } from '~/helpers/getHandler'; @@ -17,6 +16,7 @@ import { OrgTokensEeService } from '~/services/org-tokens-ee.service'; import { OrgTokensService } from '~/services/org-tokens.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { NcRequest } from '~/interface/config'; @UseGuards(MetaApiLimiterGuard, AuthGuard('jwt')) @Controller() @@ -31,7 +31,7 @@ export class OrgTokensController { scope: 'org', blockApiTokenAccess: true, }) - async apiTokenList(@Req() req: Request) { + async apiTokenList(@Req() req: NcRequest) { return await getConditionalHandler( this.orgTokensService.apiTokenList, this.orgTokensEeService.apiTokenListEE, @@ -47,7 +47,7 @@ export class OrgTokensController { scope: 'org', blockApiTokenAccess: true, }) - async apiTokenCreate(@Req() req: Request, @Body() body: ApiTokenReqType) { + async apiTokenCreate(@Req() req: NcRequest, @Body() body: ApiTokenReqType) { return await this.orgTokensService.apiTokenCreate({ apiToken: body, user: req['user'], @@ -61,7 +61,7 @@ export class OrgTokensController { // allowedRoles: [OrgUserRoles.SUPER], blockApiTokenAccess: true, }) - async apiTokenDelete(@Req() req: Request, @Param('token') token: string) { + async apiTokenDelete(@Req() req: NcRequest, @Param('token') token: string) { await this.orgTokensService.apiTokenDelete({ token, user: req['user'], diff --git a/packages/nocodb/src/controllers/org-users.controller.ts b/packages/nocodb/src/controllers/org-users.controller.ts index f7410f4039..aa72026360 100644 --- a/packages/nocodb/src/controllers/org-users.controller.ts +++ b/packages/nocodb/src/controllers/org-users.controller.ts @@ -10,7 +10,6 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { OrgUserRoles } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; @@ -18,6 +17,7 @@ import { OrgUsersService } from '~/services/org-users.service'; import { User } from '~/models'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -30,7 +30,7 @@ export class OrgUsersController { allowedRoles: [OrgUserRoles.SUPER_ADMIN], blockApiTokenAccess: true, }) - async userList(@Req() req: Request) { + async userList(@Req() req: NcRequest) { return new PagedResponseImpl( await this.orgUsersService.userList({ query: req.query, @@ -76,7 +76,7 @@ export class OrgUsersController { allowedRoles: [OrgUserRoles.SUPER_ADMIN], blockApiTokenAccess: true, }) - async userAdd(@Body() body, @Req() req: Request) { + async userAdd(@Body() body, @Req() req: NcRequest) { const result = await this.orgUsersService.userAdd({ user: req.body, req, @@ -105,7 +105,7 @@ export class OrgUsersController { blockApiTokenAccess: true, }) async userInviteResend( - @Req() req: Request, + @Req() req: NcRequest, @Param('userId') userId: string, ): Promise { await this.orgUsersService.userInviteResend({ @@ -123,7 +123,10 @@ export class OrgUsersController { allowedRoles: [OrgUserRoles.SUPER_ADMIN], blockApiTokenAccess: true, }) - async generateResetUrl(@Req() req: Request, @Param('userId') userId: string) { + async generateResetUrl( + @Req() req: NcRequest, + @Param('userId') userId: string, + ) { const result = await this.orgUsersService.generateResetUrl({ siteUrl: req.ncSiteUrl, userId, diff --git a/packages/nocodb/src/controllers/public-datas-export.controller.ts b/packages/nocodb/src/controllers/public-datas-export.controller.ts index 97d5674976..cdac515935 100644 --- a/packages/nocodb/src/controllers/public-datas-export.controller.ts +++ b/packages/nocodb/src/controllers/public-datas-export.controller.ts @@ -17,6 +17,8 @@ import { PublicDatasExportService } from '~/services/public-datas-export.service import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; import { Column, Model, Source, View } from '~/models'; import { PublicApiLimiterGuard } from '~/guards/public-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext } from '~/interface/config'; @UseGuards(PublicApiLimiterGuard) @Controller() @@ -30,11 +32,12 @@ export class PublicDatasExportController { '/api/v2/public/shared-view/:publicDataUuid/rows/export/excel', ]) async exportExcel( + @TenantContext() context: NcContext, @Request() req, @Response() res, @Param('publicDataUuid') publicDataUuid: string, ) { - const view = await View.getByUUID(publicDataUuid); + const view = await View.getByUUID(context, publicDataUuid); if (!view) NcError.viewNotFound(publicDataUuid); if ( view.type !== ViewTypes.GRID && @@ -49,11 +52,16 @@ export class PublicDatasExportController { NcError.invalidSharedViewPassword(); } - const model = await view.getModelWithInfo(); + const model = await view.getModelWithInfo(context); - await view.getColumns(); + await view.getColumns(context); - const { offset, dbRows, elapsed } = await this.getDbRows(model, view, req); + const { offset, dbRows, elapsed } = await this.getDbRows( + context, + model, + view, + req, + ); const fields = req.query.fields as string[]; @@ -85,8 +93,12 @@ export class PublicDatasExportController { '/api/v1/db/public/shared-view/:publicDataUuid/rows/export/csv', '/api/v2/public/shared-view/:publicDataUuid/rows/export/csv', ]) - async exportCsv(@Request() req, @Response() res) { - const view = await View.getByUUID(req.params.publicDataUuid); + async exportCsv( + @TenantContext() context: NcContext, + @Request() req, + @Response() res, + ) { + const view = await View.getByUUID(context, req.params.publicDataUuid); const fields = req.query.fields; if (!view) NcError.viewNotFound(req.params.publicDataUuid); @@ -103,10 +115,15 @@ export class PublicDatasExportController { NcError.invalidSharedViewPassword(); } - const model = await view.getModelWithInfo(); - await view.getColumns(); + const model = await view.getModelWithInfo(context); + await view.getColumns(context); - const { offset, dbRows, elapsed } = await this.getDbRows(model, view, req); + const { offset, dbRows, elapsed } = await this.getDbRows( + context, + model, + view, + req, + ); const data = papaparse.unparse( { @@ -142,7 +159,7 @@ export class PublicDatasExportController { res.send(data); } - async getDbRows(model, view: View, req) { + async getDbRows(@TenantContext() context: NcContext, model, view: View, req) { view.model.columns = view.columns .filter((c) => c.show) .map( @@ -164,14 +181,14 @@ export class PublicDatasExportController { listArgs.sortArr = JSON.parse(listArgs.sortArrJson); } catch (e) {} - const source = await Source.get(model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const source = await Source.get(context, model.source_id); + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { ast } = await getAst({ + const { ast } = await getAst(context, { query: req.query, model, view, @@ -209,7 +226,7 @@ export class PublicDatasExportController { const dbRow = { ...row }; for (const column of view.model.columns) { - dbRow[column.title] = await serializeCellValue({ + dbRow[column.title] = await serializeCellValue(context, { value: row[column.title], column, siteUrl: req.ncSiteUrl, diff --git a/packages/nocodb/src/controllers/public-datas.controller.ts b/packages/nocodb/src/controllers/public-datas.controller.ts index 4f411709ac..692311414f 100644 --- a/packages/nocodb/src/controllers/public-datas.controller.ts +++ b/packages/nocodb/src/controllers/public-datas.controller.ts @@ -8,10 +8,11 @@ import { UseGuards, UseInterceptors, } from '@nestjs/common'; -import { Request } from 'express'; import { AnyFilesInterceptor } from '@nestjs/platform-express'; import { PublicDatasService } from '~/services/public-datas.service'; import { PublicApiLimiterGuard } from '~/guards/public-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @UseGuards(PublicApiLimiterGuard) @Controller() @@ -23,10 +24,11 @@ export class PublicDatasController { '/api/v2/public/shared-view/:sharedViewUuid/rows', ]) async dataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, ) { - const pagedResponse = await this.publicDatasService.dataList({ + const pagedResponse = await this.publicDatasService.dataList(context, { query: req.query, password: req.headers?.['xc-password'] as string, sharedViewUuid, @@ -39,10 +41,11 @@ export class PublicDatasController { '/api/v2/public/shared-view/:sharedViewUuid/groupby', ]) async dataGroupBy( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, ) { - return await this.publicDatasService.dataGroupBy({ + return await this.publicDatasService.dataGroupBy(context, { query: req.query, password: req.headers?.['xc-password'] as string, sharedViewUuid: sharedViewUuid, @@ -54,11 +57,12 @@ export class PublicDatasController { '/api/v2/public/shared-view/:sharedViewUuid/group/:columnId', ]) async groupedDataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, @Param('columnId') columnId: string, ) { - const groupedData = await this.publicDatasService.groupedDataList({ + const groupedData = await this.publicDatasService.groupedDataList(context, { query: req.query, password: req.headers?.['xc-password'] as string, sharedViewUuid: sharedViewUuid, @@ -74,10 +78,11 @@ export class PublicDatasController { @HttpCode(200) @UseInterceptors(AnyFilesInterceptor()) async dataInsert( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, ) { - const insertResult = await this.publicDatasService.dataInsert({ + const insertResult = await this.publicDatasService.dataInsert(context, { sharedViewUuid: sharedViewUuid, password: req.headers?.['xc-password'] as string, body: req.body?.data, @@ -93,7 +98,8 @@ export class PublicDatasController { '/api/v2/public/shared-view/:sharedViewUuid/nested/:columnId', ]) async relDataList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, @Param('columnId') columnId: string, ) { @@ -107,7 +113,7 @@ export class PublicDatasController { } } - const pagedResponse = await this.publicDatasService.relDataList({ + const pagedResponse = await this.publicDatasService.relDataList(context, { query: req.query, password: req.headers?.['xc-password'] as string, sharedViewUuid: sharedViewUuid, @@ -123,18 +129,22 @@ export class PublicDatasController { '/api/v2/public/shared-view/:sharedViewUuid/rows/:rowId/mm/:columnId', ]) async publicMmList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, @Param('rowId') rowId: string, @Param('columnId') columnId: string, ) { - const paginatedResponse = await this.publicDatasService.publicMmList({ - query: req.query, - password: req.headers?.['xc-password'] as string, - sharedViewUuid: sharedViewUuid, - columnId: columnId, - rowId: rowId, - }); + const paginatedResponse = await this.publicDatasService.publicMmList( + context, + { + query: req.query, + password: req.headers?.['xc-password'] as string, + sharedViewUuid: sharedViewUuid, + columnId: columnId, + rowId: rowId, + }, + ); return paginatedResponse; } @@ -143,18 +153,22 @@ export class PublicDatasController { '/api/v2/public/shared-view/:sharedViewUuid/rows/:rowId/hm/:columnId', ]) async publicHmList( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, @Param('rowId') rowId: string, @Param('columnId') columnId: string, ) { - const paginatedResponse = await this.publicDatasService.publicHmList({ - query: req.query, - password: req.headers?.['xc-password'] as string, - sharedViewUuid: sharedViewUuid, - columnId: columnId, - rowId: rowId, - }); + const paginatedResponse = await this.publicDatasService.publicHmList( + context, + { + query: req.query, + password: req.headers?.['xc-password'] as string, + sharedViewUuid: sharedViewUuid, + columnId: columnId, + rowId: rowId, + }, + ); return paginatedResponse; } } diff --git a/packages/nocodb/src/controllers/public-metas.controller.ts b/packages/nocodb/src/controllers/public-metas.controller.ts index f9bf2b67e5..b1dd0cf068 100644 --- a/packages/nocodb/src/controllers/public-metas.controller.ts +++ b/packages/nocodb/src/controllers/public-metas.controller.ts @@ -1,7 +1,8 @@ import { Controller, Get, Param, Req, UseGuards } from '@nestjs/common'; -import { Request } from 'express'; import { PublicMetasService } from '~/services/public-metas.service'; import { PublicApiLimiterGuard } from '~/guards/public-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @UseGuards(PublicApiLimiterGuard) @Controller() @@ -13,10 +14,11 @@ export class PublicMetasController { '/api/v2/public/shared-view/:sharedViewUuid/meta', ]) async viewMetaGet( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('sharedViewUuid') sharedViewUuid: string, ) { - return await this.publicMetasService.viewMetaGet({ + return await this.publicMetasService.viewMetaGet(context, { password: req.headers?.['xc-password'] as string, sharedViewUuid: sharedViewUuid, }); @@ -27,9 +29,10 @@ export class PublicMetasController { '/api/v2/public/shared-base/:sharedBaseUuid/meta', ]) async publicSharedBaseGet( + @TenantContext() context: NcContext, @Param('sharedBaseUuid') sharedBaseUuid: string, ): Promise { - return await this.publicMetasService.publicSharedBaseGet({ + return await this.publicMetasService.publicSharedBaseGet(context, { sharedBaseUuid, }); } diff --git a/packages/nocodb/src/controllers/shared-bases.controller.ts b/packages/nocodb/src/controllers/shared-bases.controller.ts index 0466974170..193570ca1e 100644 --- a/packages/nocodb/src/controllers/shared-bases.controller.ts +++ b/packages/nocodb/src/controllers/shared-bases.controller.ts @@ -10,11 +10,12 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { SharedBasesService } from '~/services/shared-bases.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -28,17 +29,21 @@ export class SharedBasesController { @HttpCode(200) @Acl('createSharedBaseLink') async createSharedBaseLink( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Body() body: any, @Param('baseId') baseId: string, ): Promise { - const sharedBase = await this.sharedBasesService.createSharedBaseLink({ - baseId: baseId, - roles: body?.roles, - password: body?.password, - siteUrl: req.ncSiteUrl, - req, - }); + const sharedBase = await this.sharedBasesService.createSharedBaseLink( + context, + { + baseId: baseId, + roles: body?.roles, + password: body?.password, + siteUrl: req.ncSiteUrl, + req, + }, + ); return sharedBase; } @@ -49,17 +54,21 @@ export class SharedBasesController { ]) @Acl('updateSharedBaseLink') async updateSharedBaseLink( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Body() body: any, @Param('baseId') baseId: string, ): Promise { - const sharedBase = await this.sharedBasesService.updateSharedBaseLink({ - baseId: baseId, - roles: body?.roles, - password: body?.password, - siteUrl: req.ncSiteUrl, - req, - }); + const sharedBase = await this.sharedBasesService.updateSharedBaseLink( + context, + { + baseId: baseId, + roles: body?.roles, + password: body?.password, + siteUrl: req.ncSiteUrl, + req, + }, + ); return sharedBase; } @@ -70,13 +79,17 @@ export class SharedBasesController { ]) @Acl('disableSharedBaseLink') async disableSharedBaseLink( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, - @Req() req: Request, + @Req() req: NcRequest, ): Promise { - const sharedBase = await this.sharedBasesService.disableSharedBaseLink({ - baseId, - req, - }); + const sharedBase = await this.sharedBasesService.disableSharedBaseLink( + context, + { + baseId, + req, + }, + ); return sharedBase; } @@ -87,13 +100,17 @@ export class SharedBasesController { ]) @Acl('getSharedBaseLink') async getSharedBaseLink( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseId') baseId: string, ): Promise { - const sharedBase = await this.sharedBasesService.getSharedBaseLink({ - baseId: baseId, - siteUrl: req.ncSiteUrl, - }); + const sharedBase = await this.sharedBasesService.getSharedBaseLink( + context, + { + baseId: baseId, + siteUrl: req.ncSiteUrl, + }, + ); return sharedBase; } diff --git a/packages/nocodb/src/controllers/sorts.controller.ts b/packages/nocodb/src/controllers/sorts.controller.ts index d6ec600bd2..e33edfca9a 100644 --- a/packages/nocodb/src/controllers/sorts.controller.ts +++ b/packages/nocodb/src/controllers/sorts.controller.ts @@ -16,7 +16,8 @@ import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { SortsService } from '~/services/sorts.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; -import { NcRequest } from '~/interface/config'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -28,9 +29,12 @@ export class SortsController { '/api/v2/meta/views/:viewId/sorts/', ]) @Acl('sortList') - async sortList(@Param('viewId') viewId: string) { + async sortList( + @TenantContext() context: NcContext, + @Param('viewId') viewId: string, + ) { return new PagedResponseImpl( - await this.sortsService.sortList({ + await this.sortsService.sortList(context, { viewId, }), ); @@ -43,11 +47,12 @@ export class SortsController { @HttpCode(200) @Acl('sortCreate') async sortCreate( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Body() body: SortReqType, @Req() req: NcRequest, ) { - const sort = await this.sortsService.sortCreate({ + const sort = await this.sortsService.sortCreate(context, { sort: body, viewId, req, @@ -57,8 +62,11 @@ export class SortsController { @Get(['/api/v1/db/meta/sorts/:sortId', '/api/v2/meta/sorts/:sortId']) @Acl('sortGet') - async sortGet(@Param('sortId') sortId: string) { - const sort = await this.sortsService.sortGet({ + async sortGet( + @TenantContext() context: NcContext, + @Param('sortId') sortId: string, + ) { + const sort = await this.sortsService.sortGet(context, { sortId, }); return sort; @@ -67,11 +75,12 @@ export class SortsController { @Patch(['/api/v1/db/meta/sorts/:sortId', '/api/v2/meta/sorts/:sortId']) @Acl('sortUpdate') async sortUpdate( + @TenantContext() context: NcContext, @Param('sortId') sortId: string, @Body() body: SortReqType, @Req() req: NcRequest, ) { - const sort = await this.sortsService.sortUpdate({ + const sort = await this.sortsService.sortUpdate(context, { sortId, sort: body, req, @@ -81,8 +90,12 @@ export class SortsController { @Delete(['/api/v1/db/meta/sorts/:sortId', '/api/v2/meta/sorts/:sortId']) @Acl('sortDelete') - async sortDelete(@Param('sortId') sortId: string, @Req() req: NcRequest) { - const sort = await this.sortsService.sortDelete({ + async sortDelete( + @TenantContext() context: NcContext, + @Param('sortId') sortId: string, + @Req() req: NcRequest, + ) { + const sort = await this.sortsService.sortDelete(context, { sortId, req, }); diff --git a/packages/nocodb/src/controllers/sources.controller.ts b/packages/nocodb/src/controllers/sources.controller.ts index 6413e7be3b..35ccbec805 100644 --- a/packages/nocodb/src/controllers/sources.controller.ts +++ b/packages/nocodb/src/controllers/sources.controller.ts @@ -7,13 +7,14 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { BaseReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { SourcesService } from '~/services/sources.service'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -25,8 +26,11 @@ export class SourcesController { '/api/v2/meta/bases/:baseId/sources/:sourceId', ]) @Acl('baseGet') - async baseGet(@Param('sourceId') sourceId: string) { - const source = await this.sourcesService.baseGetWithConfig({ + async baseGet( + @TenantContext() context: NcContext, + @Param('sourceId') sourceId: string, + ) { + const source = await this.sourcesService.baseGetWithConfig(context, { sourceId, }); @@ -43,12 +47,13 @@ export class SourcesController { ]) @Acl('baseUpdate') async baseUpdate( + @TenantContext() context: NcContext, @Param('sourceId') sourceId: string, @Param('baseId') baseId: string, @Body() body: BaseReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - const source = await this.sourcesService.baseUpdate({ + const source = await this.sourcesService.baseUpdate(context, { sourceId, source: body, baseId, @@ -63,8 +68,11 @@ export class SourcesController { '/api/v2/meta/bases/:baseId/sources', ]) @Acl('baseList') - async baseList(@Param('baseId') baseId: string) { - const sources = await this.sourcesService.baseList({ + async baseList( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + ) { + const sources = await this.sourcesService.baseList(context, { baseId, }); diff --git a/packages/nocodb/src/controllers/sql-views.controller.ts b/packages/nocodb/src/controllers/sql-views.controller.ts index dea09ae540..6b7b829d00 100644 --- a/packages/nocodb/src/controllers/sql-views.controller.ts +++ b/packages/nocodb/src/controllers/sql-views.controller.ts @@ -10,6 +10,8 @@ import { SqlViewsService } from '~/services/sql-views.service'; import { GlobalGuard } from '~/guards/global/global.guard'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -22,12 +24,13 @@ export class SqlViewsController { ]) @Acl('sqlViewCreate') async sqlViewCreate( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('sourceId') sourceId: string, @Request() req, @Body() body, ) { - const table = await this.sqlViewsService.sqlViewCreate({ + const table = await this.sqlViewsService.sqlViewCreate(context, { clientIp: (req as any).clientIp, body, baseId, diff --git a/packages/nocodb/src/controllers/sync.controller.ts b/packages/nocodb/src/controllers/sync.controller.ts index 0147ef2042..4ea8037756 100644 --- a/packages/nocodb/src/controllers/sync.controller.ts +++ b/packages/nocodb/src/controllers/sync.controller.ts @@ -14,7 +14,8 @@ import { GlobalGuard } from '~/guards/global/global.guard'; import { SyncService } from '~/services/sync.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; -import { NcRequest } from '~/interface/config'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -29,10 +30,11 @@ export class SyncController { ]) @Acl('syncSourceList') async syncSourceList( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('sourceId') sourceId?: string, ) { - return await this.syncService.syncSourceList({ + return await this.syncService.syncSourceList(context, { baseId, sourceId, }); @@ -47,12 +49,13 @@ export class SyncController { @HttpCode(200) @Acl('syncSourceCreate') async syncCreate( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Body() body: any, @Req() req: NcRequest, @Param('sourceId') sourceId?: string, ) { - return await this.syncService.syncCreate({ + return await this.syncService.syncCreate(context, { baseId: baseId, sourceId: sourceId, userId: (req as any).user.id, @@ -63,8 +66,12 @@ export class SyncController { @Delete(['/api/v1/db/meta/syncs/:syncId', '/api/v2/meta/syncs/:syncId']) @Acl('syncSourceDelete') - async syncDelete(@Param('syncId') syncId: string, @Req() req: NcRequest) { - return await this.syncService.syncDelete({ + async syncDelete( + @TenantContext() context: NcContext, + @Param('syncId') syncId: string, + @Req() req: NcRequest, + ) { + return await this.syncService.syncDelete(context, { syncId: syncId, req, }); @@ -73,11 +80,12 @@ export class SyncController { @Patch(['/api/v1/db/meta/syncs/:syncId', '/api/v2/meta/syncs/:syncId']) @Acl('syncSourceUpdate') async syncUpdate( + @TenantContext() context: NcContext, @Param('syncId') syncId: string, @Body() body: any, @Req() req: NcRequest, ) { - return await this.syncService.syncUpdate({ + return await this.syncService.syncUpdate(context, { syncId: syncId, syncPayload: body, req, diff --git a/packages/nocodb/src/controllers/tables.controller.ts b/packages/nocodb/src/controllers/tables.controller.ts index 9cd7f0c4fa..97ae5f8551 100644 --- a/packages/nocodb/src/controllers/tables.controller.ts +++ b/packages/nocodb/src/controllers/tables.controller.ts @@ -17,6 +17,8 @@ import { TablesService } from '~/services/tables.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -31,13 +33,14 @@ export class TablesController { ]) @Acl('tableList') async tableList( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('sourceId') sourceId: string, @Query('includeM2M') includeM2M: string, @Request() req, ) { return new PagedResponseImpl( - await this.tablesService.getAccessibleTables({ + await this.tablesService.getAccessibleTables(context, { baseId, sourceId, includeM2M: includeM2M === 'true', @@ -55,12 +58,13 @@ export class TablesController { @HttpCode(200) @Acl('tableCreate') async tableCreate( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('sourceId') sourceId: string, @Body() body: TableReqType, @Request() req, ) { - const result = await this.tablesService.tableCreate({ + const result = await this.tablesService.tableCreate(context, { baseId: baseId, sourceId: sourceId, table: body, @@ -72,11 +76,18 @@ export class TablesController { @Get(['/api/v1/db/meta/tables/:tableId', '/api/v2/meta/tables/:tableId']) @Acl('tableGet') - async tableGet(@Param('tableId') tableId: string, @Request() req) { - const table = await this.tablesService.getTableWithAccessibleViews({ - tableId: req.params.tableId, - user: req.user, - }); + async tableGet( + @TenantContext() context: NcContext, + @Param('tableId') tableId: string, + @Request() req, + ) { + const table = await this.tablesService.getTableWithAccessibleViews( + context, + { + tableId: req.params.tableId, + user: req.user, + }, + ); return table; } @@ -84,11 +95,12 @@ export class TablesController { @Patch(['/api/v1/db/meta/tables/:tableId', '/api/v2/meta/tables/:tableId']) @Acl('tableUpdate') async tableUpdate( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: TableReqType, @Request() req, ) { - await this.tablesService.tableUpdate({ + await this.tablesService.tableUpdate(context, { tableId: tableId, table: body, baseId: req.ncBaseId, @@ -100,8 +112,12 @@ export class TablesController { @Delete(['/api/v1/db/meta/tables/:tableId', '/api/v2/meta/tables/:tableId']) @Acl('tableDelete') - async tableDelete(@Param('tableId') tableId: string, @Request() req) { - const result = await this.tablesService.tableDelete({ + async tableDelete( + @TenantContext() context: NcContext, + @Param('tableId') tableId: string, + @Request() req, + ) { + const result = await this.tablesService.tableDelete(context, { tableId: req.params.tableId, user: (req as any).user, req, @@ -117,10 +133,11 @@ export class TablesController { @Acl('tableReorder') @HttpCode(200) async tableReorder( + @TenantContext() context: NcContext, @Param('tableId') tableId: string, @Body() body: { order: number }, ) { - return this.tablesService.reorderTable({ + return this.tablesService.reorderTable(context, { tableId, order: body.order, }); diff --git a/packages/nocodb/src/controllers/users/users.controller.ts b/packages/nocodb/src/controllers/users/users.controller.ts index 9ea6c9655b..2204aedec7 100644 --- a/packages/nocodb/src/controllers/users/users.controller.ts +++ b/packages/nocodb/src/controllers/users/users.controller.ts @@ -15,6 +15,8 @@ import { GlobalGuard } from '~/guards/global/global.guard'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { UsersService } from '~/services/users/users.service'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() export class UsersController { diff --git a/packages/nocodb/src/controllers/utils.controller.ts b/packages/nocodb/src/controllers/utils.controller.ts index 8725b0af18..757c3a2e7b 100644 --- a/packages/nocodb/src/controllers/utils.controller.ts +++ b/packages/nocodb/src/controllers/utils.controller.ts @@ -9,13 +9,13 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { UtilsService } from '~/services/utils.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { PublicApiLimiterGuard } from '~/guards/public-api-limiter.guard'; import { TelemetryService } from '~/services/telemetry.service'; +import { NcRequest } from '~/interface/config'; @Controller() export class UtilsController { @@ -49,7 +49,7 @@ export class UtilsController { scope: 'org', }) @HttpCode(200) - async testConnection(@Body() body: any, @Req() _req: Request) { + async testConnection(@Body() body: any, @Req() _req: NcRequest) { body.pool = { min: 0, max: 1, @@ -64,7 +64,7 @@ export class UtilsController { '/api/v2/meta/nocodb/info', '/api/v1/meta/nocodb/info', ]) - async appInfo(@Req() req: Request) { + async appInfo(@Req() req: NcRequest) { return await this.utilsService.appInfo({ req: { ncSiteUrl: (req as any).ncSiteUrl, diff --git a/packages/nocodb/src/controllers/view-columns.controller.ts b/packages/nocodb/src/controllers/view-columns.controller.ts index 7bb7167400..a9d0a06b86 100644 --- a/packages/nocodb/src/controllers/view-columns.controller.ts +++ b/packages/nocodb/src/controllers/view-columns.controller.ts @@ -22,7 +22,8 @@ import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { ViewColumnsService } from '~/services/view-columns.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; -import { NcRequest } from '~/interface/config'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -34,9 +35,12 @@ export class ViewColumnsController { '/api/v2/meta/views/:viewId/columns/', ]) @Acl('columnList') - async columnList(@Param('viewId') viewId: string) { + async columnList( + @TenantContext() context: NcContext, + @Param('viewId') viewId: string, + ) { return new PagedResponseImpl( - await this.viewColumnsService.columnList({ + await this.viewColumnsService.columnList(context, { viewId, }), ); @@ -49,11 +53,12 @@ export class ViewColumnsController { @HttpCode(200) @Acl('columnAdd') async columnAdd( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Body() body: ViewColumnReqType, @Req() req: NcRequest, ) { - const viewColumn = await this.viewColumnsService.columnAdd({ + const viewColumn = await this.viewColumnsService.columnAdd(context, { viewId, column: body, req, @@ -67,12 +72,13 @@ export class ViewColumnsController { ]) @Acl('viewColumnUpdate') async viewColumnUpdate( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Param('columnId') columnId: string, @Body() body: ViewColumnReqType, @Req() req: NcRequest, ) { - const result = await this.viewColumnsService.columnUpdate({ + const result = await this.viewColumnsService.columnUpdate(context, { viewId, columnId, column: body, @@ -84,6 +90,7 @@ export class ViewColumnsController { @Patch('/api/v3/meta/views/:viewId/columns') @Acl('columnUpdate') async viewColumnUpdateV3( + @TenantContext() context: NcContext, @Req() req, @Param('viewId') viewId: string, @Body() @@ -106,7 +113,7 @@ export class ViewColumnsController { >, ) { return new PagedResponseImpl( - await this.viewColumnsService.columnsUpdate({ + await this.viewColumnsService.columnsUpdate(context, { viewId, columns: body, req, @@ -116,12 +123,19 @@ export class ViewColumnsController { @Get('/api/v3/meta/views/:viewId/columns') @Acl('columnList') - async viewColumnListV3(@Req() req, @Param('viewId') viewId: string) { + async viewColumnListV3( + @TenantContext() context: NcContext, + @Req() req, + @Param('viewId') viewId: string, + ) { return { - [APIContext.VIEW_COLUMNS]: await this.viewColumnsService.viewColumnList({ - viewId, - req, - }), + [APIContext.VIEW_COLUMNS]: await this.viewColumnsService.viewColumnList( + context, + { + viewId, + req, + }, + ), }; } } diff --git a/packages/nocodb/src/controllers/views.controller.ts b/packages/nocodb/src/controllers/views.controller.ts index d7d4d7a112..4306ed78b9 100644 --- a/packages/nocodb/src/controllers/views.controller.ts +++ b/packages/nocodb/src/controllers/views.controller.ts @@ -11,13 +11,14 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { ViewUpdateReqType } from 'nocodb-sdk'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { GlobalGuard } from '~/guards/global/global.guard'; import { ViewsService } from '~/services/views.service'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -29,9 +30,13 @@ export class ViewsController { '/api/v2/meta/tables/:tableId/views', ]) @Acl('viewList') - async viewList(@Param('tableId') tableId: string, @Req() req: Request) { + async viewList( + @TenantContext() context: NcContext, + @Param('tableId') tableId: string, + @Req() req: NcRequest, + ) { return new PagedResponseImpl( - await this.viewsService.viewList({ + await this.viewsService.viewList(context, { tableId, user: req.user, }), @@ -41,11 +46,12 @@ export class ViewsController { @Patch(['/api/v1/db/meta/views/:viewId', '/api/v2/meta/views/:viewId']) @Acl('viewUpdate') async viewUpdate( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Body() body: ViewUpdateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - const result = await this.viewsService.viewUpdate({ + const result = await this.viewsService.viewUpdate(context, { viewId, view: body, user: req.user, @@ -56,8 +62,12 @@ export class ViewsController { @Delete(['/api/v1/db/meta/views/:viewId', '/api/v2/meta/views/:viewId']) @Acl('viewDelete') - async viewDelete(@Param('viewId') viewId: string, @Req() req: Request) { - const result = await this.viewsService.viewDelete({ + async viewDelete( + @TenantContext() context: NcContext, + @Param('viewId') viewId: string, + @Req() req: NcRequest, + ) { + const result = await this.viewsService.viewDelete(context, { viewId, user: req.user, req, @@ -72,10 +82,11 @@ export class ViewsController { @HttpCode(200) @Acl('showAllColumns') async showAllColumns( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Query('ignoreIds') ignoreIds: string[], ) { - return await this.viewsService.showAllColumns({ + return await this.viewsService.showAllColumns(context, { viewId, ignoreIds, }); @@ -87,10 +98,11 @@ export class ViewsController { @HttpCode(200) @Acl('hideAllColumns') async hideAllColumns( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Query('ignoreIds') ignoreIds: string[], ) { - return await this.viewsService.hideAllColumns({ + return await this.viewsService.hideAllColumns(context, { viewId, ignoreIds, }); @@ -102,8 +114,16 @@ export class ViewsController { ]) @HttpCode(200) @Acl('shareView') - async shareView(@Param('viewId') viewId: string, @Req() req: Request) { - return await this.viewsService.shareView({ viewId, user: req.user, req }); + async shareView( + @TenantContext() context: NcContext, + @Param('viewId') viewId: string, + @Req() req: NcRequest, + ) { + return await this.viewsService.shareView(context, { + viewId, + user: req.user, + req, + }); } @Get([ @@ -111,9 +131,12 @@ export class ViewsController { '/api/v2/meta/tables/:tableId/share', ]) @Acl('shareViewList') - async shareViewList(@Param('tableId') tableId: string) { + async shareViewList( + @TenantContext() context: NcContext, + @Param('tableId') tableId: string, + ) { return new PagedResponseImpl( - await this.viewsService.shareViewList({ + await this.viewsService.shareViewList(context, { tableId, }), ); @@ -125,11 +148,12 @@ export class ViewsController { ]) @Acl('shareViewUpdate') async shareViewUpdate( + @TenantContext() context: NcContext, @Param('viewId') viewId: string, @Body() body: ViewUpdateReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { - return await this.viewsService.shareViewUpdate({ + return await this.viewsService.shareViewUpdate(context, { viewId, sharedView: body, user: req.user, @@ -142,8 +166,12 @@ export class ViewsController { '/api/v2/meta/views/:viewId/share', ]) @Acl('shareViewDelete') - async shareViewDelete(@Param('viewId') viewId: string, @Req() req: Request) { - return await this.viewsService.shareViewDelete({ + async shareViewDelete( + @TenantContext() context: NcContext, + @Param('viewId') viewId: string, + @Req() req: NcRequest, + ) { + return await this.viewsService.shareViewDelete(context, { viewId, user: req.user, req, diff --git a/packages/nocodb/src/db/BaseModelSqlv2.ts b/packages/nocodb/src/db/BaseModelSqlv2.ts index caaa7fd475..64b1c9ebcb 100644 --- a/packages/nocodb/src/db/BaseModelSqlv2.ts +++ b/packages/nocodb/src/db/BaseModelSqlv2.ts @@ -41,6 +41,7 @@ import type { User, } from '~/models'; import type CustomKnex from '~/db/CustomKnex'; +import type { NcContext } from '~/interface/config'; import { Audit, BaseUser, @@ -84,8 +85,12 @@ const GROUP_COL = '__nc_group_id'; const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14); -export async function populatePk(model: Model, insertObj: any) { - await model.getColumns(); +export async function populatePk( + context: NcContext, + model: Model, + insertObj: any, +) { + await model.getColumns(context); for (const pkCol of model.primaryKeys) { if (!pkCol.meta?.ag || insertObj[pkCol.title]) continue; insertObj[pkCol.title] = @@ -108,13 +113,19 @@ function checkColumnRequired( return !fields || fields.includes(column.title); } -export async function getColumnName(column: Column, columns?: Column[]) { +export async function getColumnName( + context: NcContext, + column: Column, + columns?: Column[], +) { if ( !isCreatedOrLastModifiedTimeCol(column) && !isCreatedOrLastModifiedByCol(column) ) return column.column_name; - columns = columns || (await Column.list({ fk_model_id: column.fk_model_id })); + columns = + columns || + (await Column.list(context, { fk_model_id: column.fk_model_id })); switch (column.uidt) { case UITypes.CreatedTime: { @@ -176,6 +187,7 @@ class BaseModelSqlv2 { protected viewId: string; protected _proto: any; protected _columns = {}; + public context: NcContext; public static config: any = defaultLimitConfig; @@ -187,6 +199,7 @@ class BaseModelSqlv2 { dbDriver, model, viewId, + context, }: { [key: string]: any; model: Model; @@ -194,6 +207,7 @@ class BaseModelSqlv2 { this._dbDriver = dbDriver; this.model = model; this.viewId = viewId; + this.context = context; autoBind(this); } @@ -213,10 +227,12 @@ class BaseModelSqlv2 { ): Promise { const qb = this.dbDriver(this.tnPath); - const { ast, dependencyFields, parsedQuery } = await getAst({ + const { ast, dependencyFields, parsedQuery } = await getAst(this.context, { query, model: this.model, - view: ignoreView ? null : this.viewId && (await View.get(this.viewId)), + view: ignoreView + ? null + : this.viewId && (await View.get(this.context, this.viewId)), getHiddenColumn, throwErrorIfInvalidParams, }); @@ -236,7 +252,10 @@ class BaseModelSqlv2 { first: true, }); } catch (e) { - if (validateFormula || !haveFormulaColumn(await this.model.getColumns())) + if ( + validateFormula || + !haveFormulaColumn(await this.model.getColumns(this.context)) + ) throw e; logger.log(e); return this.readByPk(id, true); @@ -252,7 +271,7 @@ class BaseModelSqlv2 { public async exist(id?: any): Promise { const qb = this.dbDriver(this.tnPath); - await this.model.getColumns(); + await this.model.getColumns(this.context); const pks = this.model.primaryKeys; if (!pks.length) return false; @@ -275,12 +294,15 @@ class BaseModelSqlv2 { } = {}, validateFormula = false, ): Promise { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const { where, ...rest } = this._getListArgs(args as any); const qb = this.dbDriver(this.tnPath); await this.selectObject({ ...args, qb, validateFormula, columns }); - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); const sorts = extractSortsObject(rest?.sort, aliasColObjMap); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); @@ -353,7 +375,7 @@ class BaseModelSqlv2 { limitOverride, } = options; - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const { where, fields, ...rest } = this._getListArgs(args as any); @@ -370,7 +392,10 @@ class BaseModelSqlv2 { await this.shuffle({ qb }); } - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); let sorts = extractSortsObject( rest?.sort, aliasColObjMap, @@ -396,7 +421,9 @@ class BaseModelSqlv2 { : []), new Filter({ children: - (await Filter.rootFilterList({ viewId: this.viewId })) || [], + (await Filter.rootFilterList(this.context, { + viewId: this.viewId, + })) || [], is_group: true, }), new Filter({ @@ -418,7 +445,7 @@ class BaseModelSqlv2 { if (!sorts) sorts = args.sortArr?.length ? args.sortArr - : await Sort.list({ viewId: this.viewId }); + : await Sort.list(this.context, { viewId: this.viewId }); await sortV2(this, sorts, qb, undefined, throwErrorIfInvalidParams); } else { @@ -514,13 +541,16 @@ class BaseModelSqlv2 { ignoreViewFilterAndSort = false, throwErrorIfInvalidParams = false, ): Promise { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const { where } = this._getListArgs(args); const qb = this.dbDriver(this.tnPath); // qb.xwhere(where, await this.model.getAliasColMapping()); - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); const filterObj = extractFilterFromXwhere( where, aliasColObjMap, @@ -541,7 +571,9 @@ class BaseModelSqlv2 { : []), new Filter({ children: - (await Filter.rootFilterList({ viewId: this.viewId })) || [], + (await Filter.rootFilterList(this.context, { + viewId: this.viewId, + })) || [], is_group: true, }), new Filter({ @@ -613,7 +645,7 @@ class BaseModelSqlv2 { widgetFilterArr?: Filter[]; }, ) { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const { where, ...rest } = this._getListArgs(args as any); @@ -632,7 +664,10 @@ class BaseModelSqlv2 { await this.shuffle({ qb }); } - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( @@ -674,7 +709,7 @@ class BaseModelSqlv2 { args.column_name = args.column_name || ''; - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const groupByColumns: Record = {}; const selectors = []; @@ -694,8 +729,8 @@ class BaseModelSqlv2 { if ([UITypes.QrCode, UITypes.Barcode].includes(column.uidt)) column = new Column({ ...(await column - .getColOptions() - .then((col) => col.getValueColumn())), + .getColOptions(this.context) + .then((col) => col.getValueColumn(this.context))), title: column.title, id: column.id, }); @@ -715,7 +750,9 @@ class BaseModelSqlv2 { await genRollupSelectv2({ baseModelSqlv2: this, knex: this.dbDriver, - columnOptions: (await column.getColOptions()) as RollupColumn, + columnOptions: (await column.getColOptions( + this.context, + )) as RollupColumn, }) ).builder.as(column.id), ); @@ -765,7 +802,11 @@ class BaseModelSqlv2 { break; default: { - const columnName = await getColumnName(column, columns); + const columnName = await getColumnName( + this.context, + column, + columns, + ); selectors.push( this.dbDriver.raw('?? as ??', [columnName, column.id]), ); @@ -788,7 +829,10 @@ class BaseModelSqlv2 { await this.shuffle({ qb }); } - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); let sorts = extractSortsObject(rest?.sort, aliasColObjMap); @@ -800,7 +844,9 @@ class BaseModelSqlv2 { ? [ new Filter({ children: - (await Filter.rootFilterList({ viewId: this.viewId })) || [], + (await Filter.rootFilterList(this.context, { + viewId: this.viewId, + })) || [], is_group: true, }), ] @@ -823,7 +869,7 @@ class BaseModelSqlv2 { if (args.sortArr?.length) { sorts = args.sortArr; } else if (this.viewId) { - sorts = await Sort.list({ viewId: this.viewId }); + sorts = await Sort.list(this.context, { viewId: this.viewId }); } } @@ -841,9 +887,9 @@ class BaseModelSqlv2 { column.uidt as UITypes, ) ) { - const columnName = await getColumnName(column, columns); + const columnName = await getColumnName(this.context, column, columns); - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(this.context, { base_id: column.base_id, }); @@ -909,7 +955,7 @@ class BaseModelSqlv2 { const groupBySelectors = []; const getAlias = getAliasGenerator('__nc_gb'); - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); // todo: refactor and avoid duplicate code await Promise.all( @@ -925,8 +971,8 @@ class BaseModelSqlv2 { if ([UITypes.QrCode, UITypes.Barcode].includes(column.uidt)) column = new Column({ ...(await column - .getColOptions() - .then((col) => col.getValueColumn())), + .getColOptions(this.context) + .then((col) => col.getValueColumn(this.context))), title: column.title, id: column.id, }); @@ -947,7 +993,9 @@ class BaseModelSqlv2 { knex: this.dbDriver, // column, // alias, - columnOptions: (await column.getColOptions()) as RollupColumn, + columnOptions: (await column.getColOptions( + this.context, + )) as RollupColumn, }) ).builder.as(column.id), ); @@ -996,7 +1044,11 @@ class BaseModelSqlv2 { break; default: { - const columnName = await getColumnName(column, columns); + const columnName = await getColumnName( + this.context, + column, + columns, + ); selectors.push( this.dbDriver.raw('?? as ??', [columnName, column.id]), ); @@ -1011,7 +1063,10 @@ class BaseModelSqlv2 { qb.count(`${this.model.primaryKey?.column_name || '*'} as count`); qb.select(...selectors); - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( @@ -1021,7 +1076,9 @@ class BaseModelSqlv2 { ? [ new Filter({ children: - (await Filter.rootFilterList({ viewId: this.viewId })) || [], + (await Filter.rootFilterList(this.context, { + viewId: this.viewId, + })) || [], is_group: true, }), ] @@ -1060,23 +1117,27 @@ class BaseModelSqlv2 { const { where, sort, ...rest } = this._getListArgs(args as any); // todo: get only required fields - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); const chilCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn(); - const childTable = await chilCol.getModel(); + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getChildColumn(this.context); + const childTable = await chilCol.getModel(this.context); const parentCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn(); - const parentTable = await parentCol.getModel(); - const childModel = await Model.getBaseModelSQL({ + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getParentColumn(this.context); + const parentTable = await parentCol.getModel(this.context); + const childModel = await Model.getBaseModelSQL(this.context, { model: childTable, dbDriver: this.dbDriver, }); - await parentTable.getColumns(); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1116,10 +1177,10 @@ class BaseModelSqlv2 { const children = await this.execAndParse( childQb, - await childTable.getColumns(), + await childTable.getColumns(this.context), ); const proto = await ( - await Model.getBaseModelSQL({ + await Model.getBaseModelSQL(this.context, { id: childTable.id, dbDriver: this.dbDriver, }) @@ -1143,24 +1204,31 @@ class BaseModelSqlv2 { selectAllRecords = false, ) { const { where, sort, ...rest } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; // const tn = this.model.tn; // const cn = (await relColOptions.getChildColumn()).title; - const mmTable = await relColOptions.getMMModel(); + const mmTable = await relColOptions.getMMModel(this.context); const vtn = this.getTnPath(mmTable); - const vcn = (await relColOptions.getMMChildColumn()).column_name; - const vrcn = (await relColOptions.getMMParentColumn()).column_name; - const rcn = (await relColOptions.getParentColumn()).column_name; - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getParentColumn()).getModel(); - const parentTable = await (await relColOptions.getChildColumn()).getModel(); - await parentTable.getColumns(); - const childModel = await Model.getBaseModelSQL({ + const vcn = (await relColOptions.getMMChildColumn(this.context)) + .column_name; + const vrcn = (await relColOptions.getMMParentColumn(this.context)) + .column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const parentTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); + await parentTable.getColumns(this.context); + const childModel = await Model.getBaseModelSQL(this.context, { dbDriver: this.dbDriver, model: childTable, }); @@ -1199,9 +1267,15 @@ class BaseModelSqlv2 { } qb.offset(selectAllRecords ? 0 : +rest?.offset || 0); - const children = await this.execAndParse(qb, await childTable.getColumns()); + const children = await this.execAndParse( + qb, + await childTable.getColumns(this.context), + ); const proto = await ( - await Model.getBaseModelSQL({ id: rtnId, dbDriver: this.dbDriver }) + await Model.getBaseModelSQL(this.context, { + id: rtnId, + dbDriver: this.dbDriver, + }) ).getProto(); return children.map((c) => { @@ -1213,18 +1287,22 @@ class BaseModelSqlv2 { async multipleHmListCount({ colId, ids }) { try { // const { cn } = this.hasManyRelations.find(({ tn }) => tn === child) || {}; - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); const chilCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn(); - const childTable = await chilCol.getModel(); + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getChildColumn(this.context); + const childTable = await chilCol.getModel(this.context); const parentCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn(); - const parentTable = await parentCol.getModel(); - await parentTable.getColumns(); + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getParentColumn(this.context); + const parentTable = await parentCol.getModel(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1265,23 +1343,27 @@ class BaseModelSqlv2 { const { where, sort, ...rest } = this._getListArgs(args as any); // todo: get only required fields - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); const chilCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn(); - const childTable = await chilCol.getModel(); + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getChildColumn(this.context); + const childTable = await chilCol.getModel(this.context); const parentCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn(); - const parentTable = await parentCol.getModel(); - const childModel = await Model.getBaseModelSQL({ + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getParentColumn(this.context); + const parentTable = await parentCol.getModel(this.context); + const childModel = await Model.getBaseModelSQL(this.context, { model: childTable, dbDriver: this.dbDriver, }); - await parentTable.getColumns(); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1314,11 +1396,11 @@ class BaseModelSqlv2 { const children = await this.execAndParse( qb, - await childTable.getColumns(), + await childTable.getColumns(this.context), ); const proto = await ( - await Model.getBaseModelSQL({ + await Model.getBaseModelSQL(this.context, { id: childTable.id, dbDriver: this.dbDriver, }) @@ -1337,18 +1419,22 @@ class BaseModelSqlv2 { try { // const { cn } = this.hasManyRelations.find(({ tn }) => tn === child) || {}; const { where } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); const chilCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn(); - const childTable = await chilCol.getModel(); + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getChildColumn(this.context); + const childTable = await chilCol.getModel(this.context); const parentCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn(); - const parentTable = await parentCol.getModel(); - await parentTable.getColumns(); + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getParentColumn(this.context); + const parentTable = await parentCol.getModel(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1361,7 +1447,7 @@ class BaseModelSqlv2 { .select(parentCol.column_name) .where(_wherePk(parentTable.primaryKeys, id)), ); - const aliasColObjMap = await childTable.getAliasColObjMap(); + const aliasColObjMap = await childTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( @@ -1396,15 +1482,16 @@ class BaseModelSqlv2 { // skip duplicate id const parentIds = [...new Set(_parentIds)]; const { where, sort, ...rest } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; // const tn = this.model.tn; - // const cn = (await relColOptions.getChildColumn()).title; - const mmTable = await relColOptions.getMMModel(); + // const cn = (await relColOptions.getChildColumn(this.context)).title; + const mmTable = await relColOptions.getMMModel(this.context); // if mm table is not present then return if (!mmTable) { @@ -1412,14 +1499,20 @@ class BaseModelSqlv2 { } const vtn = this.getTnPath(mmTable); - const vcn = (await relColOptions.getMMChildColumn()).column_name; - const vrcn = (await relColOptions.getMMParentColumn()).column_name; - const rcn = (await relColOptions.getParentColumn()).column_name; - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getParentColumn()).getModel(); - const parentTable = await (await relColOptions.getChildColumn()).getModel(); - await parentTable.getColumns(); - const childModel = await Model.getBaseModelSQL({ + const vcn = (await relColOptions.getMMChildColumn(this.context)) + .column_name; + const vrcn = (await relColOptions.getMMParentColumn(this.context)) + .column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const parentTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); + await parentTable.getColumns(this.context); + const childModel = await Model.getBaseModelSQL(this.context, { dbDriver: this.dbDriver, model: childTable, }); @@ -1465,11 +1558,11 @@ class BaseModelSqlv2 { const children = await this.execAndParse( finalQb, - await childTable.getColumns(), + await childTable.getColumns(this.context), ); const proto = await ( - await Model.getBaseModelSQL({ + await Model.getBaseModelSQL(this.context, { id: rtnId, dbDriver: this.dbDriver, }) @@ -1490,24 +1583,29 @@ class BaseModelSqlv2 { args, ): Promise { const { where } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const mmTable = await relColOptions.getMMModel(); + const mmTable = await relColOptions.getMMModel(this.context); const vtn = this.getTnPath(mmTable); - const vcn = (await relColOptions.getMMChildColumn()).column_name; - const vrcn = (await relColOptions.getMMParentColumn()).column_name; - const rcn = (await relColOptions.getParentColumn()).column_name; - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getParentColumn()).getModel(); - - const childView = await relColOptions.getChildView(); + const vcn = (await relColOptions.getMMChildColumn(this.context)) + .column_name; + const vrcn = (await relColOptions.getMMParentColumn(this.context)) + .column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + + const childView = await relColOptions.getChildView(this.context); let listArgs: any = {}; if (childView) { - const { dependencyFields } = await getAst({ + const { dependencyFields } = await getAst(this.context, { model: childTable, query: {}, view: childView, @@ -1523,8 +1621,10 @@ class BaseModelSqlv2 { } catch (e) {} } - const parentTable = await (await relColOptions.getChildColumn()).getModel(); - await parentTable.getColumns(); + const parentTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1548,7 +1648,7 @@ class BaseModelSqlv2 { ).orWhereNull(rcn); }); - const aliasColObjMap = await childTable.getAliasColObjMap(); + const aliasColObjMap = await childTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await this.getCustomConditionsAndApply({ @@ -1561,7 +1661,7 @@ class BaseModelSqlv2 { }); return ( - await this.execAndParse(qb, await childTable.getColumns(), { + await this.execAndParse(qb, await childTable.getColumns(this.context), { raw: true, first: true, }) @@ -1569,21 +1669,28 @@ class BaseModelSqlv2 { } public async multipleMmListCount({ colId, parentIds }) { - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const mmTable = await relColOptions.getMMModel(); + const mmTable = await relColOptions.getMMModel(this.context); const vtn = this.getTnPath(mmTable); - const vcn = (await relColOptions.getMMChildColumn()).column_name; - const vrcn = (await relColOptions.getMMParentColumn()).column_name; - const rcn = (await relColOptions.getParentColumn()).column_name; - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getParentColumn()).getModel(); - const parentTable = await (await relColOptions.getChildColumn()).getModel(); - await parentTable.getColumns(); + const vcn = (await relColOptions.getMMChildColumn(this.context)) + .column_name; + const vrcn = (await relColOptions.getMMParentColumn(this.context)) + .column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const parentTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1627,22 +1734,29 @@ class BaseModelSqlv2 { public async mmListCount({ colId, parentId }, args) { const { where } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const mmTable = await relColOptions.getMMModel(); + const mmTable = await relColOptions.getMMModel(this.context); const vtn = this.getTnPath(mmTable); - const vcn = (await relColOptions.getMMChildColumn()).column_name; - const vrcn = (await relColOptions.getMMParentColumn()).column_name; - const rcn = (await relColOptions.getParentColumn()).column_name; - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getParentColumn()).getModel(); + const vcn = (await relColOptions.getMMChildColumn(this.context)) + .column_name; + const vrcn = (await relColOptions.getMMParentColumn(this.context)) + .column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); - const parentTable = await (await relColOptions.getChildColumn()).getModel(); - await parentTable.getColumns(); + const parentTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1662,7 +1776,7 @@ class BaseModelSqlv2 { // .where(parentTable.primaryKey.cn, id) .where(_wherePk(parentTable.primaryKeys, parentId)), ); - const aliasColObjMap = await childTable.getAliasColObjMap(); + const aliasColObjMap = await childTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await conditionV2( @@ -1686,27 +1800,32 @@ class BaseModelSqlv2 { args, ): Promise { const { where, ...rest } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const mmTable = await relColOptions.getMMModel(); + const mmTable = await relColOptions.getMMModel(this.context); const vtn = this.getTnPath(mmTable); - const vcn = (await relColOptions.getMMChildColumn()).column_name; - const vrcn = (await relColOptions.getMMParentColumn()).column_name; - const rcn = (await relColOptions.getParentColumn()).column_name; - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getParentColumn()).getModel(); - const childModel = await Model.getBaseModelSQL({ + const vcn = (await relColOptions.getMMChildColumn(this.context)) + .column_name; + const vrcn = (await relColOptions.getMMParentColumn(this.context)) + .column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const childModel = await Model.getBaseModelSQL(this.context, { dbDriver: this.dbDriver, model: childTable, }); - const childView = await relColOptions.getChildView(); + const childView = await relColOptions.getChildView(this.context); let listArgs: any = {}; if (childView) { - const { dependencyFields } = await getAst({ + const { dependencyFields } = await getAst(this.context, { model: childTable, query: {}, view: childView, @@ -1715,8 +1834,10 @@ class BaseModelSqlv2 { listArgs = dependencyFields; } - const parentTable = await (await relColOptions.getChildColumn()).getModel(); - await parentTable.getColumns(); + const parentTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1751,7 +1872,7 @@ class BaseModelSqlv2 { viewId: childView?.id, }); - const aliasColObjMap = await childTable.getAliasColObjMap(); + const aliasColObjMap = await childTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await this.getCustomConditionsAndApply({ @@ -1774,7 +1895,10 @@ class BaseModelSqlv2 { applyPaginate(qb, rest); const proto = await childModel.getProto(); - const data = await this.execAndParse(qb, await childTable.getColumns()); + const data = await this.execAndParse( + qb, + await childTable.getColumns(this.context), + ); return data.map((c) => { c.__proto__ = proto; return c; @@ -1787,25 +1911,28 @@ class BaseModelSqlv2 { args, ): Promise { const { where, ...rest } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; - - const cn = (await relColOptions.getChildColumn()).column_name; - const rcn = (await relColOptions.getParentColumn()).column_name; - const childTable = await (await relColOptions.getChildColumn()).getModel(); + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; + + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); const parentTable = await ( - await relColOptions.getParentColumn() - ).getModel(); - const childModel = await Model.getBaseModelSQL({ + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const childModel = await Model.getBaseModelSQL(this.context, { dbDriver: this.dbDriver, model: childTable, }); - await parentTable.getColumns(); + await parentTable.getColumns(this.context); - const childView = await relColOptions.getChildView(); + const childView = await relColOptions.getChildView(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -1829,7 +1956,7 @@ class BaseModelSqlv2 { await childModel.selectObject({ qb }); - const aliasColObjMap = await childTable.getAliasColObjMap(); + const aliasColObjMap = await childTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await this.getCustomConditionsAndApply({ column: relColumn, @@ -1850,7 +1977,10 @@ class BaseModelSqlv2 { applyPaginate(qb, rest); const proto = await childModel.getProto(); - const data = await this.execAndParse(qb, await childTable.getColumns()); + const data = await this.execAndParse( + qb, + await childTable.getColumns(this.context), + ); return data.map((c) => { c.__proto__ = proto; @@ -1864,28 +1994,31 @@ class BaseModelSqlv2 { args, ): Promise { const { where } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const cn = (await relColOptions.getChildColumn()).column_name; - const rcn = (await relColOptions.getParentColumn()).column_name; - const childTable = await (await relColOptions.getChildColumn()).getModel(); + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); const parentTable = await ( - await relColOptions.getParentColumn() - ).getModel(); + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); - const childView = await relColOptions.getChildView(); + const childView = await relColOptions.getChildView(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); const tn = childTn; const rtn = parentTn; - await parentTable.getColumns(); + await parentTable.getColumns(this.context); const qb = this.dbDriver(tn) .count(`*`, { as: 'count' }) @@ -1899,7 +2032,7 @@ class BaseModelSqlv2 { ).orWhereNull(cn); }); - const aliasColObjMap = await childTable.getAliasColObjMap(); + const aliasColObjMap = await childTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await this.getCustomConditionsAndApply({ @@ -1921,31 +2054,34 @@ class BaseModelSqlv2 { args, ): Promise { const { where, ...rest } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const rcn = (await relColOptions.getParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; const parentTable = await ( - await relColOptions.getParentColumn() - ).getModel(); - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getChildColumn()).getModel(); - const parentModel = await Model.getBaseModelSQL({ + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); + const parentModel = await Model.getBaseModelSQL(this.context, { dbDriver: this.dbDriver, model: parentTable, }); - const childModel = await Model.getBaseModelSQL({ + const childModel = await Model.getBaseModelSQL(this.context, { dbDriver: this.dbDriver, model: childTable, }); - const childView = await relColOptions.getChildView(); + const childView = await relColOptions.getChildView(this.context); let listArgs: any = {}; if (childView) { - const { dependencyFields } = await getAst({ + const { dependencyFields } = await getAst(this.context, { model: childTable, query: {}, view: childView, @@ -1956,7 +2092,7 @@ class BaseModelSqlv2 { const rtn = this.getTnPath(parentTable); const tn = this.getTnPath(childTable); - await childTable.getColumns(); + await childTable.getColumns(this.context); // one-to-one relation is combination of both hm and bt to identify table which have // foreign key column(similar to bt) we are adding a boolean flag `bt` under meta @@ -1982,7 +2118,7 @@ class BaseModelSqlv2 { viewId: childView?.id, }); - const aliasColObjMap = await parentTable.getAliasColObjMap(); + const aliasColObjMap = await parentTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await this.getCustomConditionsAndApply({ @@ -2009,7 +2145,7 @@ class BaseModelSqlv2 { const proto = await (isBt ? parentModel : childModel).getProto(); const data = await this.execAndParse( qb, - await (isBt ? parentTable : childTable).getColumns(), + await (isBt ? parentTable : childTable).getColumns(this.context), ); return data.map((c) => { @@ -2024,25 +2160,28 @@ class BaseModelSqlv2 { args, ): Promise { const { where } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const rcn = (await relColOptions.getParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; const parentTable = await ( - await relColOptions.getParentColumn() - ).getModel(); - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getChildColumn()).getModel(); + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); const rtn = parentTn; const tn = childTn; - await childTable.getColumns(); + await childTable.getColumns(this.context); const qb = this.dbDriver(rtn) .where((qb) => { @@ -2057,10 +2196,10 @@ class BaseModelSqlv2 { }) .count(`*`, { as: 'count' }); - const aliasColObjMap = await parentTable.getAliasColObjMap(); + const aliasColObjMap = await parentTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); - const targetView = await relColOptions.getChildView(); + const targetView = await relColOptions.getChildView(this.context); await this.getCustomConditionsAndApply({ column: relColumn, @@ -2081,27 +2220,30 @@ class BaseModelSqlv2 { args, ): Promise { const { where } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const rcn = (await relColOptions.getParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; const parentTable = await ( - await relColOptions.getParentColumn() - ).getModel(); - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getChildColumn()).getModel(); + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); - const childView = await relColOptions.getChildView(); + const childView = await relColOptions.getChildView(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); const rtn = parentTn; const tn = childTn; - await childTable.getColumns(); + await childTable.getColumns(this.context); // one-to-one relation is combination of both hm and bt to identify table which have // foreign key column(similar to bt) we are adding a boolean flag `bt` under meta @@ -2119,7 +2261,7 @@ class BaseModelSqlv2 { }) .count(`*`, { as: 'count' }); - const aliasColObjMap = await parentTable.getAliasColObjMap(); + const aliasColObjMap = await parentTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); await this.getCustomConditionsAndApply({ @@ -2141,19 +2283,22 @@ class BaseModelSqlv2 { args, ): Promise { const { where, ...rest } = this._getListArgs(args as any); - const relColumn = (await this.model.getColumns()).find( + const relColumn = (await this.model.getColumns(this.context)).find( (c) => c.id === colId, ); - const relColOptions = - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn; + const relColOptions = (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; - const rcn = (await relColOptions.getParentColumn()).column_name; + const rcn = (await relColOptions.getParentColumn(this.context)).column_name; const parentTable = await ( - await relColOptions.getParentColumn() - ).getModel(); - const cn = (await relColOptions.getChildColumn()).column_name; - const childTable = await (await relColOptions.getChildColumn()).getModel(); - const parentModel = await Model.getBaseModelSQL({ + await relColOptions.getParentColumn(this.context) + ).getModel(this.context); + const cn = (await relColOptions.getChildColumn(this.context)).column_name; + const childTable = await ( + await relColOptions.getChildColumn(this.context) + ).getModel(this.context); + const parentModel = await Model.getBaseModelSQL(this.context, { dbDriver: this.dbDriver, model: parentTable, }); @@ -2163,7 +2308,7 @@ class BaseModelSqlv2 { const rtn = parentTn; const tn = childTn; - await childTable.getColumns(); + await childTable.getColumns(this.context); const qb = this.dbDriver(rtn).where((qb) => { qb.whereNotIn( @@ -2182,10 +2327,10 @@ class BaseModelSqlv2 { await parentModel.selectObject({ qb }); - const aliasColObjMap = await parentTable.getAliasColObjMap(); + const aliasColObjMap = await parentTable.getAliasColObjMap(this.context); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); - const targetView = await relColOptions.getChildView(); + const targetView = await relColOptions.getChildView(this.context); await this.getCustomConditionsAndApply({ column: relColumn, view: targetView, @@ -2208,7 +2353,10 @@ class BaseModelSqlv2 { applyPaginate(qb, rest); const proto = await parentModel.getProto(); - const data = await this.execAndParse(qb, await parentTable.getColumns()); + const data = await this.execAndParse( + qb, + await parentTable.getColumns(this.context), + ); return data.map((c) => { c.__proto__ = proto; @@ -2229,7 +2377,7 @@ class BaseModelSqlv2 { qb; sort: string; }) { - const childAliasColMap = await table.getAliasColObjMap(); + const childAliasColMap = await table.getAliasColObjMap(this.context); const filter = extractFilterFromXwhere(where, childAliasColMap); await conditionV2( @@ -2239,7 +2387,9 @@ class BaseModelSqlv2 { ? [ new Filter({ children: - (await Filter.rootFilterList({ viewId: view.id })) || [], + (await Filter.rootFilterList(this.context, { + viewId: view.id, + })) || [], is_group: true, }), ] @@ -2259,7 +2409,7 @@ class BaseModelSqlv2 { validateFormula = false, aliasToColumnBuilder = {}, ) { - const formula = await column.getColOptions(); + const formula = await column.getColOptions(this.context); if (formula.error) throw new Error(`Formula error: ${formula.error}`); const qb = await formulaQueryBuilderv2( this, @@ -2280,15 +2430,17 @@ class BaseModelSqlv2 { } const proto: any = { __columnAliases: {} }; - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); await Promise.all( columns.map(async (column) => { switch (column.uidt) { case UITypes.Lookup: { // @ts-ignore - const colOptions: LookupColumn = await column.getColOptions(); - const relCol = await Column.get({ + const colOptions: LookupColumn = await column.getColOptions( + this.context, + ); + const relCol = await Column.get(this.context, { colId: colOptions.fk_relation_column_id, }); const relColTitle = @@ -2298,8 +2450,11 @@ class BaseModelSqlv2 { proto.__columnAliases[column.title] = { path: [ relColTitle, - (await Column.get({ colId: colOptions.fk_lookup_column_id })) - ?.title, + ( + await Column.get(this.context, { + colId: colOptions.fk_lookup_column_id, + }) + )?.title, ], }; } @@ -2308,8 +2463,9 @@ class BaseModelSqlv2 { case UITypes.LinkToAnotherRecord: { this._columns[column.title] = column; - const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn; + const colOptions = (await column.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; if (colOptions?.type === 'hm') { const listLoader = new DataLoader( @@ -2396,12 +2552,13 @@ class BaseModelSqlv2 { }; } else if (colOptions.type === 'bt') { // @ts-ignore - const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn; - const pCol = await Column.get({ + const colOptions = (await column.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; + const pCol = await Column.get(this.context, { colId: colOptions.fk_parent_column_id, }); - const cCol = await Column.get({ + const cCol = await Column.get(this.context, { colId: colOptions.fk_child_column_id, }); @@ -2436,7 +2593,7 @@ class BaseModelSqlv2 { }); const data = await ( - await Model.getBaseModelSQL({ + await Model.getBaseModelSQL(this.context, { id: pCol.fk_model_id, dbDriver: this.dbDriver, }) @@ -2487,12 +2644,13 @@ class BaseModelSqlv2 { if (isBt) { // @ts-ignore - const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn; - const pCol = await Column.get({ + const colOptions = (await column.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; + const pCol = await Column.get(this.context, { colId: colOptions.fk_parent_column_id, }); - const cCol = await Column.get({ + const cCol = await Column.get(this.context, { colId: colOptions.fk_child_column_id, }); @@ -2527,7 +2685,7 @@ class BaseModelSqlv2 { }); const data = await ( - await Model.getBaseModelSQL({ + await Model.getBaseModelSQL(this.context, { id: pCol.fk_model_id, dbDriver: this.dbDriver, }) @@ -2690,22 +2848,24 @@ class BaseModelSqlv2 { let fields: string[]; if (fieldsSet?.size) { - viewOrTableColumns = _columns || (await this.model.getColumns()); + viewOrTableColumns = + _columns || (await this.model.getColumns(this.context)); } else { - view = await View.get(viewId); - const viewColumns = viewId && (await View.getColumns(viewId)); + view = await View.get(this.context, viewId); + const viewColumns = + viewId && (await View.getColumns(this.context, viewId)); fields = Array.isArray(_fields) ? _fields : _fields?.split(','); - // const columns = _columns ?? (await this.model.getColumns()); + // const columns = _columns ?? (await this.model.getColumns(this.context)); // for (const column of columns) { viewOrTableColumns = - viewColumns || _columns || (await this.model.getColumns()); + viewColumns || _columns || (await this.model.getColumns(this.context)); } for (const viewOrTableColumn of viewOrTableColumns) { const column = viewOrTableColumn instanceof Column ? viewOrTableColumn - : await Column.get({ + : await Column.get(this.context, { colId: (viewOrTableColumn as GridViewColumn).fk_column_id, }); // hide if column marked as hidden in view @@ -2730,8 +2890,9 @@ class BaseModelSqlv2 { case UITypes.DateTime: { const columnName = await getColumnName( + this.context, column, - _columns || (await this.model.getColumns()), + _columns || (await this.model.getColumns(this.context)), ); if (this.isMySQL) { // MySQL stores timestamp in UTC but display in timezone @@ -2784,8 +2945,10 @@ class BaseModelSqlv2 { case UITypes.Lookup: break; case UITypes.QrCode: { - const qrCodeColumn = await column.getColOptions(); - const qrValueColumn = await Column.get({ + const qrCodeColumn = await column.getColOptions( + this.context, + ); + const qrValueColumn = await Column.get(this.context, { colId: qrCodeColumn.fk_qr_value_column_id, }); @@ -2819,8 +2982,10 @@ class BaseModelSqlv2 { break; } case UITypes.Barcode: { - const barcodeColumn = await column.getColOptions(); - const barcodeValueColumn = await Column.get({ + const barcodeColumn = await column.getColOptions( + this.context, + ); + const barcodeValueColumn = await Column.get(this.context, { colId: barcodeColumn.fk_barcode_value_column_id, }); @@ -2884,7 +3049,9 @@ class BaseModelSqlv2 { knex: this.dbDriver, // column, alias, - columnOptions: (await column.getColOptions()) as RollupColumn, + columnOptions: (await column.getColOptions( + this.context, + )) as RollupColumn, }) ).builder.as(column.id), ); @@ -2892,8 +3059,9 @@ class BaseModelSqlv2 { case UITypes.CreatedBy: case UITypes.LastModifiedBy: { const columnName = await getColumnName( + this.context, column, - _columns || (await this.model.getColumns()), + _columns || (await this.model.getColumns(this.context)), ); res[sanitize(column.id || columnName)] = sanitize( @@ -2926,7 +3094,7 @@ class BaseModelSqlv2 { async insert(data, trx?, cookie?, _disableOptimization = false) { try { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); // exclude auto increment columns in body for (const col of columns) { @@ -2940,10 +3108,11 @@ class BaseModelSqlv2 { } } - await populatePk(this.model, data); + await populatePk(this.context, this.model, data); // todo: filter based on view const insertObj = await this.model.mapAliasToColumn( + this.context, data, this.clientMeta, this.dbDriver, @@ -3057,7 +3226,7 @@ class BaseModelSqlv2 { async delByPk(id, _trx?, cookie?) { let trx: Knex.Transaction = _trx; try { - const source = await Source.get(this.model.source_id); + const source = await Source.get(this.context, this.model.source_id); // retrieve data for handling params in hook const data = await this.readRecord({ idOrRecord: id, @@ -3074,13 +3243,16 @@ class BaseModelSqlv2 { if (column.uidt !== UITypes.LinkToAnotherRecord) continue; const colOptions = - await column.getColOptions(); + await column.getColOptions(this.context); switch (colOptions.type) { case 'mm': { - const mmTable = await Model.get(colOptions.fk_mm_model_id); - const mmParentColumn = await Column.get({ + const mmTable = await Model.get( + this.context, + colOptions.fk_mm_model_id, + ); + const mmParentColumn = await Column.get(this.context, { colId: colOptions.fk_mm_child_column_id, }); @@ -3094,12 +3266,14 @@ class BaseModelSqlv2 { case 'hm': { // skip if it's an mm table column - const relatedTable = await colOptions.getRelatedTable(); + const relatedTable = await colOptions.getRelatedTable( + this.context, + ); if (relatedTable.mm) { break; } - const childColumn = await Column.get({ + const childColumn = await Column.get(this.context, { colId: colOptions.fk_child_column_id, }); @@ -3141,19 +3315,20 @@ class BaseModelSqlv2 { async hasLTARData(rowId, model: Model): Promise { const res = []; - const LTARColumns = (await model.getColumns()).filter( + const LTARColumns = (await model.getColumns(this.context)).filter( (c) => c.uidt === UITypes.LinkToAnotherRecord, ); let i = 0; for (const column of LTARColumns) { - const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn; - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const colOptions = (await column.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn; + const childColumn = await colOptions.getChildColumn(this.context); + const parentColumn = await colOptions.getParentColumn(this.context); + const childModel = await childColumn.getModel(this.context); + await childModel.getColumns(this.context); + const parentModel = await parentColumn.getModel(this.context); + await parentModel.getColumns(this.context); let cnt = 0; if (colOptions.type === RelationTypes.HAS_MANY) { cnt = +( @@ -3166,8 +3341,8 @@ class BaseModelSqlv2 { ) ).cnt; } else if (colOptions.type === RelationTypes.MANY_TO_MANY) { - const mmModel = await colOptions.getMMModel(); - const mmChildColumn = await colOptions.getMMChildColumn(); + const mmModel = await colOptions.getMMModel(this.context); + const mmChildColumn = await colOptions.getMMChildColumn(this.context); cnt = +( await this.execAndParse( this.dbDriver(this.getTnPath(mmModel.table_name)) @@ -3196,9 +3371,10 @@ class BaseModelSqlv2 { async updateByPk(id, data, trx?, cookie?, _disableOptimization = false) { try { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const updateObj = await this.model.mapAliasToColumn( + this.context, data, this.clientMeta, this.dbDriver, @@ -3243,7 +3419,7 @@ class BaseModelSqlv2 { } async _wherePk(id, skipGetColumns = false, skipPkValidation = false) { - if (!skipGetColumns) await this.model.getColumns(); + if (!skipGetColumns) await this.model.getColumns(this.context); return _wherePk(this.model.primaryKeys, id, skipPkValidation); } @@ -3337,12 +3513,13 @@ class BaseModelSqlv2 { async nestedInsert(data, _trx = null, cookie?) { // const driver = trx ? trx : await this.dbDriver.transaction(); try { - const source = await Source.get(this.model.source_id); - await populatePk(this.model, data); + const source = await Source.get(this.context, this.model.source_id); + await populatePk(this.context, this.model, data); - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const insertObj = await this.model.mapAliasToColumn( + this.context, data, this.clientMeta, this.dbDriver, @@ -3521,7 +3698,9 @@ class BaseModelSqlv2 { const preInsertOps: (() => Promise)[] = []; for (const col of nestedCols) { if (col.title in data) { - const colOptions = await col.getColOptions(); + const colOptions = await col.getColOptions( + this.context, + ); // parse data if it's JSON string let nestedData; @@ -3537,8 +3716,8 @@ class BaseModelSqlv2 { case RelationTypes.BELONGS_TO: { if (typeof nestedData !== 'object') continue; - const childCol = await colOptions.getChildColumn(); - const parentCol = await colOptions.getParentColumn(); + const childCol = await colOptions.getChildColumn(this.context); + const parentCol = await colOptions.getParentColumn(this.context); insertObj[childCol.column_name] = nestedData?.[parentCol.title]; } break; @@ -3546,9 +3725,9 @@ class BaseModelSqlv2 { { const isBt = col.meta?.bt; - const childCol = await colOptions.getChildColumn(); - const childModel = await childCol.getModel(); - await childModel.getColumns(); + const childCol = await colOptions.getChildColumn(this.context); + const childModel = await childCol.getModel(this.context); + await childModel.getColumns(this.context); if (isBt) { // if array then extract value from first element @@ -3566,8 +3745,10 @@ class BaseModelSqlv2 { }); if (typeof nestedData !== 'object') continue; - const childCol = await colOptions.getChildColumn(); - const parentCol = await colOptions.getParentColumn(); + const childCol = await colOptions.getChildColumn(this.context); + const parentCol = await colOptions.getParentColumn( + this.context, + ); insertObj[childCol.column_name] = nestedData?.[parentCol.title]; } else { postInsertOps.push(async (rowId) => { @@ -3587,9 +3768,9 @@ class BaseModelSqlv2 { case RelationTypes.HAS_MANY: { if (!Array.isArray(nestedData)) continue; - const childCol = await colOptions.getChildColumn(); - const childModel = await childCol.getModel(); - await childModel.getColumns(); + const childCol = await colOptions.getChildColumn(this.context); + const childModel = await childCol.getModel(this.context); + await childModel.getColumns(this.context); postInsertOps.push(async (rowId) => { return this.dbDriver(this.getTnPath(childModel.table_name)) @@ -3608,12 +3789,16 @@ class BaseModelSqlv2 { if (!Array.isArray(nestedData)) continue; postInsertOps.push(async (rowId) => { const parentModel = await colOptions - .getParentColumn() - .then((c) => c.getModel()); - await parentModel.getColumns(); - const parentMMCol = await colOptions.getMMParentColumn(); - const childMMCol = await colOptions.getMMChildColumn(); - const mmModel = await colOptions.getMMModel(); + .getParentColumn(this.context) + .then((c) => c.getModel(this.context)); + await parentModel.getColumns(this.context); + const parentMMCol = await colOptions.getMMParentColumn( + this.context, + ); + const childMMCol = await colOptions.getMMChildColumn( + this.context, + ); + const mmModel = await colOptions.getMMModel(this.context); const rows = nestedData.map((r) => ({ [parentMMCol.column_name]: r[parentModel.primaryKey.title], @@ -3660,7 +3845,7 @@ class BaseModelSqlv2 { let agPkCol: Column; if (!raw) { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const nestedCols = columns.filter((c) => isLinksOrLTAR(c)); @@ -3949,7 +4134,7 @@ class BaseModelSqlv2 { ) { let transaction; try { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); // validate update data if (!raw) { @@ -3963,6 +4148,7 @@ class BaseModelSqlv2 { : await Promise.all( datas.map((d) => this.model.mapAliasToColumn( + this.context, d, this.clientMeta, this.dbDriver, @@ -4103,9 +4289,10 @@ class BaseModelSqlv2 { try { let count = 0; - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const updateData = await this.model.mapAliasToColumn( + this.context, data, this.clientMeta, this.dbDriver, @@ -4122,7 +4309,10 @@ class BaseModelSqlv2 { } else { const { where } = this._getListArgs(args); const qb = this.dbDriver(this.tnPath); - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); const filterObj = extractFilterFromXwhere(where, aliasColObjMap, true); const conditionObj = [ @@ -4142,7 +4332,9 @@ class BaseModelSqlv2 { conditionObj.push( new Filter({ children: - (await Filter.rootFilterList({ viewId: args.viewId })) || [], + (await Filter.rootFilterList(this.context, { + viewId: args.viewId, + })) || [], is_group: true, }), ); @@ -4187,13 +4379,14 @@ class BaseModelSqlv2 { isSingleRecordDeletion?: boolean; } = {}, ) { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); let transaction; try { const deleteIds = await Promise.all( ids.map((d) => this.model.mapAliasToColumn( + this.context, d, this.clientMeta, this.dbDriver, @@ -4261,19 +4454,22 @@ class BaseModelSqlv2 { ids: any[], ) => Promise)[] = []; - const base = await Source.get(this.model.source_id); + const base = await Source.get(this.context, this.model.source_id); for (const column of this.model.columns) { if (column.uidt !== UITypes.LinkToAnotherRecord) continue; const colOptions = - await column.getColOptions(); + await column.getColOptions(this.context); switch (colOptions.type) { case 'mm': { - const mmTable = await Model.get(colOptions.fk_mm_model_id); - const mmParentColumn = await Column.get({ + const mmTable = await Model.get( + this.context, + colOptions.fk_mm_model_id, + ); + const mmParentColumn = await Column.get(this.context, { colId: colOptions.fk_mm_child_column_id, }); @@ -4287,12 +4483,14 @@ class BaseModelSqlv2 { case 'hm': { // skip if it's an mm table column - const relatedTable = await colOptions.getRelatedTable(); + const relatedTable = await colOptions.getRelatedTable( + this.context, + ); if (relatedTable.mm) { break; } - const childColumn = await Column.get({ + const childColumn = await Column.get(this.context, { colId: colOptions.fk_child_column_id, }); @@ -4348,10 +4546,13 @@ class BaseModelSqlv2 { ) { let trx: Knex.Transaction; try { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const { where } = this._getListArgs(args); const qb = this.dbDriver(this.tnPath); - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); const filterObj = extractFilterFromXwhere(where, aliasColObjMap, true); await conditionV2( @@ -4380,26 +4581,26 @@ class BaseModelSqlv2 { if (column.uidt !== UITypes.LinkToAnotherRecord) continue; const colOptions = - await column.getColOptions(); + await column.getColOptions(this.context); if (colOptions.type === 'bt') { continue; } - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const parentTable = await parentColumn.getModel(); - const childTable = await childColumn.getModel(); - await childTable.getColumns(); - await parentTable.getColumns(); + const childColumn = await colOptions.getChildColumn(this.context); + const parentColumn = await colOptions.getParentColumn(this.context); + const parentTable = await parentColumn.getModel(this.context); + const childTable = await childColumn.getModel(this.context); + await childTable.getColumns(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); switch (colOptions.type) { case 'mm': { - const vChildCol = await colOptions.getMMChildColumn(); - const vTable = await colOptions.getMMModel(); + const vChildCol = await colOptions.getMMChildColumn(this.context); + const vTable = await colOptions.getMMModel(this.context); const vTn = this.getTnPath(vTable); @@ -4417,12 +4618,14 @@ class BaseModelSqlv2 { case 'hm': { // skip if it's an mm table column - const relatedTable = await colOptions.getRelatedTable(); + const relatedTable = await colOptions.getRelatedTable( + this.context, + ); if (relatedTable.mm) { break; } - const childColumn = await Column.get({ + const childColumn = await Column.get(this.context, { colId: colOptions.fk_child_column_id, }); @@ -4446,7 +4649,7 @@ class BaseModelSqlv2 { } } - const source = await Source.get(this.model.source_id); + const source = await Source.get(this.context, this.model.source_id); trx = await this.dbDriver.transaction(); @@ -4487,6 +4690,9 @@ class BaseModelSqlv2 { await this.handleHooks('after.insert', null, data, req); const id = this._extractPksValues(data); await Audit.insert({ + fk_workspace_id: this.model.fk_workspace_id, + base_id: this.model.base_id, + source_id: this.model.source_id, fk_model_id: this.model.id, row_id: id, op_type: AuditOperationTypes.DATA, @@ -4514,6 +4720,9 @@ class BaseModelSqlv2 { } await Audit.insert({ + fk_workspace_id: this.model.fk_workspace_id, + base_id: this.model.base_id, + source_id: this.model.source_id, fk_model_id: this.model.id, op_type: AuditOperationTypes.DATA, op_sub_type: AuditOperationSubTypes.BULK_UPDATE, @@ -4541,6 +4750,9 @@ class BaseModelSqlv2 { } await Audit.insert({ + fk_workspace_id: this.model.fk_workspace_id, + base_id: this.model.base_id, + source_id: this.model.source_id, fk_model_id: this.model.id, op_type: AuditOperationTypes.DATA, op_sub_type: AuditOperationSubTypes.BULK_DELETE, @@ -4559,6 +4771,9 @@ class BaseModelSqlv2 { await this.handleHooks('after.bulkInsert', null, data, req); await Audit.insert({ + fk_workspace_id: this.model.fk_workspace_id, + base_id: this.model.base_id, + source_id: this.model.source_id, fk_model_id: this.model.id, op_type: AuditOperationTypes.DATA, op_sub_type: AuditOperationSubTypes.BULK_INSERT, @@ -4596,7 +4811,7 @@ class BaseModelSqlv2 { let desc = `Record with ID ${id} has been updated in Table ${this.model.title}.`; let details = ''; if (updateObj) { - updateObj = await this.model.mapColumnToAlias(updateObj); + updateObj = await this.model.mapColumnToAlias(this.context, updateObj); for (const k of Object.keys(updateObj)) { const prevValue = typeof prevData[k] === 'object' @@ -4614,6 +4829,9 @@ class BaseModelSqlv2 { } } await Audit.insert({ + fk_workspace_id: this.model.fk_workspace_id, + base_id: this.model.base_id, + source_id: this.model.source_id, fk_model_id: this.model.id, row_id: id, op_type: AuditOperationTypes.DATA, @@ -4642,6 +4860,9 @@ class BaseModelSqlv2 { public async afterDelete(data: any, _trx: any, req): Promise { const id = this._extractPksValues(data); await Audit.insert({ + fk_workspace_id: this.model.fk_workspace_id, + base_id: this.model.base_id, + source_id: this.model.source_id, fk_model_id: this.model.id, row_id: id, op_type: AuditOperationTypes.DATA, @@ -4658,6 +4879,7 @@ class BaseModelSqlv2 { protected async handleHooks(hookName, prevData, newData, req): Promise { Noco.eventEmitter.emit(HANDLE_WEBHOOK, { + context: this.context, hookName, prevData, newData, @@ -4699,7 +4921,7 @@ class BaseModelSqlv2 { data: Record, columns?: Column[], ): Promise { - const cols = columns || (await this.model.getColumns()); + const cols = columns || (await this.model.getColumns(this.context)); // let cols = Object.keys(this.columns); for (let i = 0; i < cols.length; ++i) { const column = this.model.columns[i]; @@ -4793,7 +5015,7 @@ class BaseModelSqlv2 { } const options = await column - .getColOptions<{ options: SelectOption[] }>() + .getColOptions<{ options: SelectOption[] }>(this.context) .then( (selectOptionsMeta) => selectOptionsMeta?.options?.map((opt) => opt.title) || [], @@ -4827,7 +5049,7 @@ class BaseModelSqlv2 { childId: string; cookie?: any; }) { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const column = columns.find((c) => c.id === colId); if ( @@ -4836,14 +5058,16 @@ class BaseModelSqlv2 { ) NcError.fieldNotFound(colId); - const colOptions = await column.getColOptions(); + const colOptions = await column.getColOptions( + this.context, + ); - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const parentTable = await parentColumn.getModel(); - const childTable = await childColumn.getModel(); - await childTable.getColumns(); - await parentTable.getColumns(); + const childColumn = await colOptions.getChildColumn(this.context); + const parentColumn = await colOptions.getParentColumn(this.context); + const parentTable = await parentColumn.getModel(this.context); + const childTable = await childColumn.getModel(this.context); + await childTable.getColumns(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -4857,9 +5081,9 @@ class BaseModelSqlv2 { switch (colOptions.type) { case RelationTypes.MANY_TO_MANY: { - const vChildCol = await colOptions.getMMChildColumn(); - const vParentCol = await colOptions.getMMParentColumn(); - const vTable = await colOptions.getMMModel(); + const vChildCol = await colOptions.getMMChildColumn(this.context); + const vParentCol = await colOptions.getMMParentColumn(this.context); + const vTable = await colOptions.getMMModel(this.context); const vTn = this.getTnPath(vTable); @@ -5023,6 +5247,9 @@ class BaseModelSqlv2 { public async afterAddChild(rowId, childId, req): Promise { await Audit.insert({ + fk_workspace_id: this.model.fk_workspace_id, + base_id: this.model.base_id, + source_id: this.model.source_id, fk_model_id: this.model.id, op_type: AuditOperationTypes.DATA, op_sub_type: AuditOperationSubTypes.LINK_RECORD, @@ -5047,7 +5274,7 @@ class BaseModelSqlv2 { childId: string; cookie?: any; }) { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const column = columns.find((c) => c.id === colId); if ( @@ -5056,14 +5283,16 @@ class BaseModelSqlv2 { ) NcError.fieldNotFound(colId); - const colOptions = await column.getColOptions(); + const colOptions = await column.getColOptions( + this.context, + ); - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const parentTable = await parentColumn.getModel(); - const childTable = await childColumn.getModel(); - await childTable.getColumns(); - await parentTable.getColumns(); + const childColumn = await colOptions.getChildColumn(this.context); + const parentColumn = await colOptions.getParentColumn(this.context); + const parentTable = await parentColumn.getModel(this.context); + const childTable = await childColumn.getModel(this.context); + await childTable.getColumns(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -5078,9 +5307,9 @@ class BaseModelSqlv2 { switch (colOptions.type) { case RelationTypes.MANY_TO_MANY: { - const vChildCol = await colOptions.getMMChildColumn(); - const vParentCol = await colOptions.getMMParentColumn(); - const vTable = await colOptions.getMMModel(); + const vChildCol = await colOptions.getMMChildColumn(this.context); + const vParentCol = await colOptions.getMMParentColumn(this.context); + const vTable = await colOptions.getMMModel(this.context); const vTn = this.getTnPath(vTable); @@ -5191,6 +5420,9 @@ class BaseModelSqlv2 { public async afterRemoveChild(rowId, childId, req): Promise { await Audit.insert({ + fk_workspace_id: this.model.fk_workspace_id, + base_id: this.model.base_id, + source_id: this.model.source_id, fk_model_id: this.model.id, op_type: AuditOperationTypes.DATA, op_sub_type: AuditOperationSubTypes.UNLINK_RECORD, @@ -5218,7 +5450,7 @@ class BaseModelSqlv2 { > { try { const { where, ...rest } = this._getListArgs(args as any); - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const column = columns?.find((col) => col.id === args.groupColumnId); if (!column) NcError.fieldNotFound(args.groupColumnId); @@ -5232,7 +5464,7 @@ class BaseModelSqlv2 { } else if (column.uidt === UITypes.SingleSelect) { const colOptions = await column.getColOptions<{ options: SelectOption[]; - }>(); + }>(this.context); groupingValues = new Set( (colOptions?.options ?? []).map((opt) => opt.title), ); @@ -5257,7 +5489,10 @@ class BaseModelSqlv2 { await this.selectObject({ qb, extractPkAndPv: true }); // todo: refactor and move to a method (applyFilterAndSort) - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); let sorts = extractSortsObject(args?.sort, aliasColObjMap); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); // todo: replace with view id @@ -5267,7 +5502,9 @@ class BaseModelSqlv2 { [ new Filter({ children: - (await Filter.rootFilterList({ viewId: this.viewId })) || [], + (await Filter.rootFilterList(this.context, { + viewId: this.viewId, + })) || [], is_group: true, }), new Filter({ @@ -5287,7 +5524,7 @@ class BaseModelSqlv2 { if (!sorts) sorts = args.sortArr?.length ? args.sortArr - : await Sort.list({ viewId: this.viewId }); + : await Sort.list(this.context, { viewId: this.viewId }); if (sorts?.['length']) await sortV2(this, sorts, qb); } else { @@ -5379,7 +5616,7 @@ class BaseModelSqlv2 { ignoreViewFilterAndSort?: boolean; } & XcFilter, ) { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const column = columns?.find((col) => col.id === args.groupColumnId); if (!column) NcError.fieldNotFound(args.groupColumnId); @@ -5391,7 +5628,10 @@ class BaseModelSqlv2 { .groupBy(column.column_name); // todo: refactor and move to a common method (applyFilterAndSort) - const aliasColObjMap = await this.model.getAliasColObjMap(columns); + const aliasColObjMap = await this.model.getAliasColObjMap( + this.context, + columns, + ); const filterObj = extractFilterFromXwhere(args.where, aliasColObjMap); // todo: replace with view id @@ -5401,7 +5641,9 @@ class BaseModelSqlv2 { [ new Filter({ children: - (await Filter.rootFilterList({ viewId: this.viewId })) || [], + (await Filter.rootFilterList(this.context, { + viewId: this.viewId, + })) || [], is_group: true, }), new Filter({ @@ -5500,7 +5742,7 @@ class BaseModelSqlv2 { let data = await this.execAndGetRows(query); if (!this.model?.columns) { - await this.model.getColumns(); + await this.model.getColumns(this.context); } // update attachment fields @@ -5584,18 +5826,18 @@ class BaseModelSqlv2 { for (const k of Object.keys(btData[col.id])) { const btAlias = idToAliasMap[k]; if (!btAlias) { - idToAliasPromiseMap[k] = Column.get({ colId: k }).then( - (col) => { - return col.title; - }, - ); + idToAliasPromiseMap[k] = Column.get(this.context, { + colId: k, + }).then((col) => { + return col.title; + }); } } } else { // Has Many BT const btAlias = idToAliasMap[col.id]; if (!btAlias) { - idToAliasPromiseMap[col.id] = Column.get({ + idToAliasPromiseMap[col.id] = Column.get(this.context, { colId: col.id, }).then((col) => { return col.title; @@ -5685,7 +5927,7 @@ class BaseModelSqlv2 { // process user columns that are present in data if (userColumns.length) { - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(this.context, { base_id: this.model.base_id, }); @@ -5815,8 +6057,10 @@ class BaseModelSqlv2 { if (column.uidt !== UITypes.Lookup) { return column; } - const colOptions = await column.getColOptions(); - return this.getNestedColumn(await colOptions?.getLookupColumn()); + const colOptions = await column.getColOptions(this.context); + return this.getNestedColumn( + await colOptions?.getLookupColumn(this.context), + ); } public async convertAttachmentType( @@ -6022,7 +6266,7 @@ class BaseModelSqlv2 { colId: string; rowId: string; }) { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const column = columns.find((c) => c.id === colId); if (!column || !isLinksOrLTAR(column)) NcError.fieldNotFound(colId); @@ -6041,14 +6285,16 @@ class BaseModelSqlv2 { if (!_childIds.length) return; - const colOptions = await column.getColOptions(); + const colOptions = await column.getColOptions( + this.context, + ); - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const parentTable = await parentColumn.getModel(); - const childTable = await childColumn.getModel(); - await childTable.getColumns(); - await parentTable.getColumns(); + const childColumn = await colOptions.getChildColumn(this.context); + const parentColumn = await colOptions.getParentColumn(this.context); + const parentTable = await parentColumn.getModel(this.context); + const childTable = await childColumn.getModel(this.context); + await childTable.getColumns(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -6088,9 +6334,9 @@ class BaseModelSqlv2 { switch (relationType) { case RelationTypes.MANY_TO_MANY: { - const vChildCol = await colOptions.getMMChildColumn(); - const vParentCol = await colOptions.getMMParentColumn(); - const vTable = await colOptions.getMMModel(); + const vChildCol = await colOptions.getMMChildColumn(this.context); + const vParentCol = await colOptions.getMMParentColumn(this.context); + const vTable = await colOptions.getMMModel(this.context); const vTn = this.getTnPath(vTable); @@ -6327,7 +6573,7 @@ class BaseModelSqlv2 { colId: string; rowId: string; }) { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const column = columns.find((c) => c.id === colId); if (!column || !isLinksOrLTAR(column)) NcError.fieldNotFound(colId); @@ -6346,14 +6592,16 @@ class BaseModelSqlv2 { if (!childIds.length) return; - const colOptions = await column.getColOptions(); + const colOptions = await column.getColOptions( + this.context, + ); - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const parentTable = await parentColumn.getModel(); - const childTable = await childColumn.getModel(); - await childTable.getColumns(); - await parentTable.getColumns(); + const childColumn = await colOptions.getChildColumn(this.context); + const parentColumn = await colOptions.getParentColumn(this.context); + const parentTable = await parentColumn.getModel(this.context); + const childTable = await childColumn.getModel(this.context); + await childTable.getColumns(this.context); + await parentTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -6361,9 +6609,9 @@ class BaseModelSqlv2 { switch (colOptions.type) { case RelationTypes.MANY_TO_MANY: { - const vChildCol = await colOptions.getMMChildColumn(); - const vParentCol = await colOptions.getMMParentColumn(); - const vTable = await colOptions.getMMModel(); + const vChildCol = await colOptions.getMMChildColumn(this.context); + const vParentCol = await colOptions.getMMParentColumn(this.context); + const vTable = await colOptions.getMMModel(this.context); // validate Ids { @@ -6601,7 +6849,7 @@ class BaseModelSqlv2 { args: { limit?; offset?; fieldSet?: Set } = {}, ) { try { - const columns = await this.model.getColumns(); + const columns = await this.model.getColumns(this.context); const { where, sort } = this._getListArgs(args as any); // todo: get only required fields @@ -6620,19 +6868,23 @@ class BaseModelSqlv2 { } const parentCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getParentColumn(); - const parentTable = await parentCol.getModel(); + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getParentColumn(this.context); + const parentTable = await parentCol.getModel(this.context); const chilCol = await ( - (await relColumn.getColOptions()) as LinkToAnotherRecordColumn - ).getChildColumn(); - const childTable = await chilCol.getModel(); + (await relColumn.getColOptions( + this.context, + )) as LinkToAnotherRecordColumn + ).getChildColumn(this.context); + const childTable = await chilCol.getModel(this.context); - const parentModel = await Model.getBaseModelSQL({ + const parentModel = await Model.getBaseModelSQL(this.context, { model: parentTable, dbDriver: this.dbDriver, }); - await childTable.getColumns(); + await childTable.getColumns(this.context); const childTn = this.getTnPath(childTable); const parentTn = this.getTnPath(parentTable); @@ -6651,7 +6903,7 @@ class BaseModelSqlv2 { const parent = await this.execAndParse( qb, - await parentTable.getColumns(), + await parentTable.getColumns(this.context), { first: true, }, @@ -6679,7 +6931,7 @@ class BaseModelSqlv2 { model?: Model; knex?: XKnex; }) { - const columns = await model.getColumns(); + const columns = await model.getColumns(this.context); const updateObject = {}; @@ -6788,7 +7040,7 @@ class BaseModelSqlv2 { } catch (e) {} } - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(this.context, { base_id: this.model.base_id, include_ws_deleted: false, }); @@ -6904,7 +7156,11 @@ class BaseModelSqlv2 { public now() { return dayjs() .utc() - .format(this.isMySQL ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD HH:mm:ssZ'); + .format( + this.isMySQL || this.isMssql + ? 'YYYY-MM-DD HH:mm:ss' + : 'YYYY-MM-DD HH:mm:ssZ', + ); } async getCustomConditionsAndApply(_params: { diff --git a/packages/nocodb/src/db/conditionV2.ts b/packages/nocodb/src/db/conditionV2.ts index 9a9764a1cc..118f446c9b 100644 --- a/packages/nocodb/src/db/conditionV2.ts +++ b/packages/nocodb/src/db/conditionV2.ts @@ -74,6 +74,8 @@ const parseConditionV2 = async ( ) => { const knex = baseModelSqlv2.dbDriver; + const context = baseModelSqlv2.context; + let filter: Filter; if (!Array.isArray(_filter)) { if (!(_filter instanceof Filter)) filter = new Filter(_filter as Filter); @@ -101,7 +103,7 @@ const parseConditionV2 = async ( }); }; } else if (filter.is_group) { - const children = await filter.getChildren(); + const children = await filter.getChildren(context); const qbs = await Promise.all( (children || []).map((child) => @@ -134,13 +136,16 @@ const parseConditionV2 = async ( ) { (filter as any).groupby = true; - const column = await getRefColumnIfAlias(await filter.getColumn()); + const column = await getRefColumnIfAlias( + context, + await filter.getColumn(context), + ); if ( column.uidt === UITypes.Lookup || column.uidt === UITypes.LinkToAnotherRecord ) { - const model = await column.getModel(); + const model = await column.getModel(context); const lkQb = await generateLookupSelectQuery({ baseModelSqlv2, alias: alias, @@ -159,12 +164,15 @@ const parseConditionV2 = async ( // if qrCode or Barcode replace it with value column if ([UITypes.QrCode, UITypes.Barcode].includes(column.uidt)) filter.fk_column_id = await column - .getColOptions() + .getColOptions(context) .then((col) => col.fk_column_id); } } - const column = await getRefColumnIfAlias(await filter.getColumn()); + const column = await getRefColumnIfAlias( + context, + await filter.getColumn(context), + ); if (!column) { if (throwErrorIfInvalid) { NcError.fieldNotFound(filter.fk_column_id); @@ -172,14 +180,15 @@ const parseConditionV2 = async ( return; } if (column.uidt === UITypes.LinkToAnotherRecord) { - const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn; - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const colOptions = (await column.getColOptions( + context, + )) as LinkToAnotherRecordColumn; + const childColumn = await colOptions.getChildColumn(context); + const parentColumn = await colOptions.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); let relationType = colOptions.type; @@ -325,9 +334,9 @@ const parseConditionV2 = async ( } else qbP.whereIn(childColumn.column_name, selectQb); }; } else if (relationType === RelationTypes.MANY_TO_MANY) { - const mmModel = await colOptions.getMMModel(); - const mmParentColumn = await colOptions.getMMParentColumn(); - const mmChildColumn = await colOptions.getMMChildColumn(); + const mmModel = await colOptions.getMMModel(context); + const mmParentColumn = await colOptions.getMMParentColumn(context); + const mmChildColumn = await colOptions.getMMChildColumn(context); if ( ['blank', 'notblank', 'checked', 'notchecked'].includes( @@ -428,7 +437,7 @@ const parseConditionV2 = async ( baseModelSqlv2, knex, alias, - columnOptions: (await column.getColOptions()) as RollupColumn, + columnOptions: (await column.getColOptions(context)) as RollupColumn, }) ).builder; return parseConditionV2( @@ -445,8 +454,8 @@ const parseConditionV2 = async ( builder, ); } else if (column.uidt === UITypes.Formula && !customWhereClause) { - const model = await column.getModel(); - const formula = await column.getColOptions(); + const model = await column.getModel(context); + const formula = await column.getColOptions(context); const builder = ( await formulaQueryBuilderv2( baseModelSqlv2, @@ -479,9 +488,9 @@ const parseConditionV2 = async ( ['like', 'nlike'].includes(filter.comparison_op) ) { // get column name for CreatedBy, LastModifiedBy - column.column_name = await getColumnName(column); + column.column_name = await getColumnName(context, column); - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(context, { base_id: column.base_id, }); return (qb: Knex.QueryBuilder) => { @@ -573,7 +582,7 @@ const parseConditionV2 = async ( const _val = customWhereClause ? customWhereClause : filter.value; // get column name for CreateTime, LastModifiedTime - column.column_name = await getColumnName(column); + column.column_name = await getColumnName(context, column); return (qb: Knex.QueryBuilder) => { let [field, val] = [_field, _val]; @@ -1240,21 +1249,23 @@ async function generateLookupCondition( aliasCount = { count: 0 }, throwErrorIfInvalid = false, ): Promise { - const colOptions = await col.getColOptions(); - const relationColumn = await colOptions.getRelationColumn(); + const context = baseModelSqlv2.context; + + const colOptions = await col.getColOptions(context); + const relationColumn = await colOptions.getRelationColumn(context); const relationColumnOptions = - await relationColumn.getColOptions(); + await relationColumn.getColOptions(context); // const relationModel = await relationColumn.getModel(); - const lookupColumn = await colOptions.getLookupColumn(); + const lookupColumn = await colOptions.getLookupColumn(context); const alias = getAlias(aliasCount); let qb; { - const childColumn = await relationColumnOptions.getChildColumn(); - const parentColumn = await relationColumnOptions.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relationColumnOptions.getChildColumn(context); + const parentColumn = await relationColumnOptions.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); let relationType = relationColumnOptions.type; @@ -1330,9 +1341,13 @@ async function generateLookupCondition( else qbP.whereIn(childColumn.column_name, qb); }; } else if (relationType === RelationTypes.MANY_TO_MANY) { - const mmModel = await relationColumnOptions.getMMModel(); - const mmParentColumn = await relationColumnOptions.getMMParentColumn(); - const mmChildColumn = await relationColumnOptions.getMMChildColumn(); + const mmModel = await relationColumnOptions.getMMModel(context); + const mmParentColumn = await relationColumnOptions.getMMParentColumn( + context, + ); + const mmChildColumn = await relationColumnOptions.getMMChildColumn( + context, + ); const childAlias = `__nc${aliasCount.count++}`; @@ -1391,6 +1406,8 @@ async function nestedConditionJoin( aliasCount: { count: number }, throwErrorIfInvalid = false, ) { + const context = baseModelSqlv2.context; + if ( lookupColumn.uidt === UITypes.Lookup || lookupColumn.uidt === UITypes.LinkToAnotherRecord @@ -1398,19 +1415,19 @@ async function nestedConditionJoin( const relationColumn = lookupColumn.uidt === UITypes.Lookup ? await ( - await lookupColumn.getColOptions() - ).getRelationColumn() + await lookupColumn.getColOptions(context) + ).getRelationColumn(context) : lookupColumn; const relationColOptions = - await relationColumn.getColOptions(); + await relationColumn.getColOptions(context); const relAlias = `__nc${aliasCount.count++}`; - const childColumn = await relationColOptions.getChildColumn(); - const parentColumn = await relationColOptions.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relationColOptions.getChildColumn(context); + const parentColumn = await relationColOptions.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); { switch (relationColOptions.type) { case RelationTypes.HAS_MANY: @@ -1439,9 +1456,13 @@ async function nestedConditionJoin( break; case 'mm': { - const mmModel = await relationColOptions.getMMModel(); - const mmParentColumn = await relationColOptions.getMMParentColumn(); - const mmChildColumn = await relationColOptions.getMMChildColumn(); + const mmModel = await relationColOptions.getMMModel(context); + const mmParentColumn = await relationColOptions.getMMParentColumn( + context, + ); + const mmChildColumn = await relationColOptions.getMMChildColumn( + context, + ); const assocAlias = `__nc${aliasCount.count++}`; @@ -1470,8 +1491,8 @@ async function nestedConditionJoin( baseModelSqlv2, filter, await ( - await lookupColumn.getColOptions() - ).getLookupColumn(), + await lookupColumn.getColOptions(context) + ).getLookupColumn(context), qb, knex, relAlias, @@ -1542,7 +1563,7 @@ async function nestedConditionJoin( baseModelSqlv2, new Filter({ ...filter, - fk_model_id: (await lookupColumn.getModel()).id, + fk_model_id: (await lookupColumn.getModel(context)).id, fk_column_id: lookupColumn?.id, }), aliasCount, diff --git a/packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts b/packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts index a6e57e777d..ab8e3dd882 100644 --- a/packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts +++ b/packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts @@ -70,7 +70,9 @@ async function _formulaQueryBuilder( ) { const knex = baseModelSqlv2.dbDriver; - const columns = await model.getColumns(); + const context = baseModelSqlv2.context; + + const columns = await model.getColumns(context); let tree = parsedTree; if (!tree) { @@ -92,15 +94,15 @@ async function _formulaQueryBuilder( | 'sqlite' | 'snowflake', getMeta: async (modelId) => { - const model = await Model.get(modelId); - await model.getColumns(); + const model = await Model.get(context, modelId); + await model.getColumns(context); return model; }, }); // populate and save parsedTree to column if not exist if (column) { - FormulaColumn.update(column.id, { parsed_tree: tree }).then( + FormulaColumn.update(context, column.id, { parsed_tree: tree }).then( () => { // ignore }, @@ -121,7 +123,9 @@ async function _formulaQueryBuilder( case UITypes.Formula: { aliasToColumn[col.id] = async () => { - const formulOption = await col.getColOptions(); + const formulOption = await col.getColOptions( + context, + ); const { builder } = await _formulaQueryBuilder( baseModelSqlv2, formulOption.formula, @@ -144,19 +148,21 @@ async function _formulaQueryBuilder( let selectQb; let isArray = false; const alias = `__nc_formula${aliasCount++}`; - const lookup = await col.getColOptions(); + const lookup = await col.getColOptions(context); { - const relationCol = await lookup.getRelationColumn(); + const relationCol = await lookup.getRelationColumn(context); const relation = - await relationCol.getColOptions(); + await relationCol.getColOptions( + context, + ); // if (relation.type !== RelationTypes.BELONGS_TO) continue; - const childColumn = await relation.getChildColumn(); - const parentColumn = await relation.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relation.getChildColumn(context); + const parentColumn = await relation.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); let relationType = relation.type; @@ -203,9 +209,13 @@ async function _formulaQueryBuilder( case RelationTypes.MANY_TO_MANY: { isArray = true; - const mmModel = await relation.getMMModel(); - const mmParentColumn = await relation.getMMParentColumn(); - const mmChildColumn = await relation.getMMChildColumn(); + const mmModel = await relation.getMMModel(context); + const mmParentColumn = await relation.getMMParentColumn( + context, + ); + const mmChildColumn = await relation.getMMChildColumn( + context, + ); const assocAlias = `__nc${aliasCount++}`; selectQb = knex( @@ -235,25 +245,27 @@ async function _formulaQueryBuilder( break; } - let lookupColumn = await lookup.getLookupColumn(); + let lookupColumn = await lookup.getLookupColumn(context); let prevAlias = alias; while (lookupColumn.uidt === UITypes.Lookup) { const nestedAlias = `__nc_formula${aliasCount++}`; const nestedLookup = - await lookupColumn.getColOptions(); - const relationCol = await nestedLookup.getRelationColumn(); + await lookupColumn.getColOptions(context); + const relationCol = await nestedLookup.getRelationColumn(context); const relation = - await relationCol.getColOptions(); + await relationCol.getColOptions( + context, + ); // if any of the relation in nested lookup is // not belongs to then ignore the sort option // if (relation.type !== RelationTypes.BELONGS_TO) continue; - const childColumn = await relation.getChildColumn(); - const parentColumn = await relation.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relation.getChildColumn(context); + const parentColumn = await relation.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); let relationType = relation.type; @@ -291,9 +303,13 @@ async function _formulaQueryBuilder( break; case RelationTypes.MANY_TO_MANY: { isArray = true; - const mmModel = await relation.getMMModel(); - const mmParentColumn = await relation.getMMParentColumn(); - const mmChildColumn = await relation.getMMChildColumn(); + const mmModel = await relation.getMMModel(context); + const mmParentColumn = await relation.getMMParentColumn( + context, + ); + const mmChildColumn = await relation.getMMChildColumn( + context, + ); const assocAlias = `__nc${aliasCount++}`; @@ -323,7 +339,7 @@ async function _formulaQueryBuilder( `${prevAlias}.${childColumn.title}` );*/ - lookupColumn = await nestedLookup.getLookupColumn(); + lookupColumn = await nestedLookup.getLookupColumn(context); prevAlias = nestedAlias; } @@ -336,8 +352,9 @@ async function _formulaQueryBuilder( baseModelSqlv2, knex, alias: prevAlias, - columnOptions: - (await lookupColumn.getColOptions()) as RollupColumn, + columnOptions: (await lookupColumn.getColOptions( + context, + )) as RollupColumn, }) ).builder; // selectQb.select(builder); @@ -363,17 +380,22 @@ async function _formulaQueryBuilder( { const nestedAlias = `__nc_formula${aliasCount++}`; const relation = - await lookupColumn.getColOptions(); + await lookupColumn.getColOptions( + context, + ); // if (relation.type !== RelationTypes.BELONGS_TO) continue; - const colOptions = - (await lookupColumn.getColOptions()) as LinkToAnotherRecordColumn; - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const colOptions = (await lookupColumn.getColOptions( + context, + )) as LinkToAnotherRecordColumn; + const childColumn = await colOptions.getChildColumn(context); + const parentColumn = await colOptions.getParentColumn( + context, + ); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); let cn; let relationType = relation.type; @@ -421,10 +443,13 @@ async function _formulaQueryBuilder( case RelationTypes.MANY_TO_MANY: { isArray = true; - const mmModel = await relation.getMMModel(); - const mmParentColumn = - await relation.getMMParentColumn(); - const mmChildColumn = await relation.getMMChildColumn(); + const mmModel = await relation.getMMModel(context); + const mmParentColumn = await relation.getMMParentColumn( + context, + ); + const mmChildColumn = await relation.getMMChildColumn( + context, + ); const assocAlias = `__nc${aliasCount++}`; @@ -481,8 +506,8 @@ async function _formulaQueryBuilder( case UITypes.Formula: { const formulaOption = - await lookupColumn.getColOptions(); - const lookupModel = await lookupColumn.getModel(); + await lookupColumn.getColOptions(context); + const lookupModel = await lookupColumn.getModel(context); const { builder } = await _formulaQueryBuilder( baseModelSqlv2, formulaOption.formula, @@ -546,7 +571,7 @@ async function _formulaQueryBuilder( const qb = await genRollupSelectv2({ baseModelSqlv2, knex, - columnOptions: (await col.getColOptions()) as RollupColumn, + columnOptions: (await col.getColOptions(context)) as RollupColumn, alias: tableAlias, }); return { builder: knex.raw(qb.builder).wrap('(', ')') }; @@ -555,17 +580,20 @@ async function _formulaQueryBuilder( case UITypes.LinkToAnotherRecord: aliasToColumn[col.id] = async (): Promise => { const alias = `__nc_formula_ll`; - const relation = await col.getColOptions(); + const relation = await col.getColOptions( + context, + ); // if (relation.type !== RelationTypes.BELONGS_TO) continue; - const colOptions = - (await col.getColOptions()) as LinkToAnotherRecordColumn; - const childColumn = await colOptions.getChildColumn(); - const parentColumn = await colOptions.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const colOptions = (await col.getColOptions( + context, + )) as LinkToAnotherRecordColumn; + const childColumn = await colOptions.getChildColumn(context); + const parentColumn = await colOptions.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); let relationType = relation.type; @@ -641,9 +669,9 @@ async function _formulaQueryBuilder( // todo: provide unique alias - const mmModel = await relation.getMMModel(); - const mmParentColumn = await relation.getMMParentColumn(); - const mmChildColumn = await relation.getMMChildColumn(); + const mmModel = await relation.getMMModel(context); + const mmParentColumn = await relation.getMMParentColumn(context); + const mmChildColumn = await relation.getMMChildColumn(context); const qb = knex( knex.raw(`?? as ??`, [ @@ -693,7 +721,7 @@ async function _formulaQueryBuilder( case UITypes.LastModifiedTime: case UITypes.DateTime: { - const refCol = await getRefColumnIfAlias(col); + const refCol = await getRefColumnIfAlias(context, col); if (refCol.id in aliasToColumn) { aliasToColumn[col.id] = aliasToColumn[refCol.id]; @@ -749,8 +777,8 @@ async function _formulaQueryBuilder( case UITypes.CreatedBy: case UITypes.LastModifiedBy: { - const base = await Base.get(model.base_id); - const baseUsers = await BaseUser.getUsersList({ + const base = await Base.get(context, model.base_id); + const baseUsers = await BaseUser.getUsersList(context, { base_id: base.id, }); @@ -902,6 +930,7 @@ async function _formulaQueryBuilder( if (calleeName === 'CONCAT') { if (knex.clientType() !== 'sqlite3') { query = await convertDateFormatForConcat( + context, arg, columnIdToUidt, query, @@ -1126,12 +1155,14 @@ async function _formulaQueryBuilder( if (pt.left.fnName === 'CONCAT' && knex.clientType() === 'sqlite3') { // handle date format left = await convertDateFormatForConcat( + context, pt.left?.arguments?.[0], columnIdToUidt, left, knex.clientType(), ); right = await convertDateFormatForConcat( + context, pt.right?.arguments?.[0], columnIdToUidt, right, @@ -1228,6 +1259,9 @@ export default async function formulaQueryBuilderv2( parsedTree?: any, ) { const knex = baseModelSqlv2.dbDriver; + + const context = baseModelSqlv2.context; + // register jsep curly hook once only jsep.plugins.register(jsepCurlyHook); let qb; @@ -1242,7 +1276,7 @@ export default async function formulaQueryBuilderv2( tableAlias, parsedTree ?? (await column - ?.getColOptions() + ?.getColOptions(context) .then((formula) => formula?.getParsedTree())), ); @@ -1260,10 +1294,10 @@ export default async function formulaQueryBuilderv2( // if column is provided, i.e. formula has been created if (column) { - const formula = await column.getColOptions(); + const formula = await column.getColOptions(context); // clean the previous formula error if the formula works this time if (formula.error) { - await FormulaColumn.update(column.id, { + await FormulaColumn.update(context, column.id, { error: null, }); } @@ -1274,7 +1308,7 @@ export default async function formulaQueryBuilderv2( console.error(e); if (column) { // add formula error to show in UI - await FormulaColumn.update(column.id, { + await FormulaColumn.update(context, column.id, { error: e.message, }); // update cache to reflect the error in UI diff --git a/packages/nocodb/src/db/genRollupSelectv2.ts b/packages/nocodb/src/db/genRollupSelectv2.ts index b90a98df06..16965c5ed0 100644 --- a/packages/nocodb/src/db/genRollupSelectv2.ts +++ b/packages/nocodb/src/db/genRollupSelectv2.ts @@ -21,14 +21,16 @@ export default async function ({ alias?: string; columnOptions: RollupColumn | LinksColumn; }): Promise<{ builder: Knex.QueryBuilder | any }> { - const relationColumn = await columnOptions.getRelationColumn(); + const context = baseModelSqlv2.context; + + const relationColumn = await columnOptions.getRelationColumn(context); const relationColumnOption: LinkToAnotherRecordColumn = - (await relationColumn.getColOptions()) as LinkToAnotherRecordColumn; - const rollupColumn = await columnOptions.getRollupColumn(); - const childCol = await relationColumnOption.getChildColumn(); - const childModel = await childCol?.getModel(); - const parentCol = await relationColumnOption.getParentColumn(); - const parentModel = await parentCol?.getModel(); + (await relationColumn.getColOptions(context)) as LinkToAnotherRecordColumn; + const rollupColumn = await columnOptions.getRollupColumn(context); + const childCol = await relationColumnOption.getChildColumn(context); + const childModel = await childCol?.getModel(context); + const parentCol = await relationColumnOption.getParentColumn(context); + const parentModel = await parentCol?.getModel(context); const refTableAlias = `__nc_rollup`; switch (relationColumnOption.type) { @@ -83,9 +85,9 @@ export default async function ({ } case RelationTypes.MANY_TO_MANY: { - const mmModel = await relationColumnOption.getMMModel(); - const mmChildCol = await relationColumnOption.getMMChildColumn(); - const mmParentCol = await relationColumnOption.getMMParentColumn(); + const mmModel = await relationColumnOption.getMMModel(context); + const mmChildCol = await relationColumnOption.getMMChildColumn(context); + const mmParentCol = await relationColumnOption.getMMParentColumn(context); if (!mmModel) { return this.dbDriver.raw(`?`, [ diff --git a/packages/nocodb/src/db/generateLookupSelectQuery.ts b/packages/nocodb/src/db/generateLookupSelectQuery.ts index bec70ff99a..e06de66cb8 100644 --- a/packages/nocodb/src/db/generateLookupSelectQuery.ts +++ b/packages/nocodb/src/db/generateLookupSelectQuery.ts @@ -10,6 +10,7 @@ import type { QrCodeColumn, RollupColumn, } from '~/models'; +import type { NcContext } from '~/interface/config'; import { Model } from '~/models'; import formulaQueryBuilderv2 from '~/db/formulav2/formulaQueryBuilderv2'; import genRollupSelectv2 from '~/db/genRollupSelectv2'; @@ -19,12 +20,13 @@ import { NcError } from '~/helpers/catchError'; const LOOKUP_VAL_SEPARATOR = '___'; export async function getDisplayValueOfRefTable( + context: NcContext, relationCol: Column, ) { return await relationCol - .getColOptions() - .then((colOpt) => colOpt.getRelatedTable()) - .then((model) => model.getColumns()) + .getColOptions(context) + .then((colOpt) => colOpt.getRelatedTable(context)) + .then((model) => model.getColumns(context)) .then((cols) => cols.find((col) => col.pv)); } @@ -48,6 +50,8 @@ export default async function generateLookupSelectQuery({ }): Promise { const knex = baseModelSqlv2.dbDriver; + const context = baseModelSqlv2.context; + const rootAlias = alias; { @@ -57,18 +61,18 @@ export default async function generateLookupSelectQuery({ let isBtLookup = true; if (column.uidt === UITypes.Lookup) { - lookupColOpt = await column.getColOptions(); + lookupColOpt = await column.getColOptions(context); } else if (column.uidt !== UITypes.LinkToAnotherRecord) { NcError.badRequest('Invalid field type'); } - await column.getColOptions(); + await column.getColOptions(context); { const relationCol = lookupColOpt - ? await lookupColOpt.getRelationColumn() + ? await lookupColOpt.getRelationColumn(context) : column; const relation = - await relationCol.getColOptions(); + await relationCol.getColOptions(context); let relationType = relation.type; @@ -79,12 +83,12 @@ export default async function generateLookupSelectQuery({ } if (relationType === RelationTypes.BELONGS_TO) { - const childColumn = await relation.getChildColumn(); - const parentColumn = await relation.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relation.getChildColumn(context); + const parentColumn = await relation.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); selectQb = knex( knex.raw(`?? as ??`, [ @@ -101,12 +105,12 @@ export default async function generateLookupSelectQuery({ ); } else if (relationType === RelationTypes.HAS_MANY) { isBtLookup = false; - const childColumn = await relation.getChildColumn(); - const parentColumn = await relation.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relation.getChildColumn(context); + const parentColumn = await relation.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); selectQb = knex( knex.raw(`?? as ??`, [ @@ -123,12 +127,12 @@ export default async function generateLookupSelectQuery({ ); } else if (relationType === RelationTypes.MANY_TO_MANY) { isBtLookup = false; - const childColumn = await relation.getChildColumn(); - const parentColumn = await relation.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relation.getChildColumn(context); + const parentColumn = await relation.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); selectQb = knex( knex.raw(`?? as ??`, [ @@ -139,9 +143,9 @@ export default async function generateLookupSelectQuery({ const mmTableAlias = getAlias(); - const mmModel = await relation.getMMModel(); - const mmChildCol = await relation.getMMChildColumn(); - const mmParentCol = await relation.getMMParentColumn(); + const mmModel = await relation.getMMModel(context); + const mmChildCol = await relation.getMMChildColumn(context); + const mmParentCol = await relation.getMMParentColumn(context); selectQb .innerJoin( @@ -162,14 +166,14 @@ export default async function generateLookupSelectQuery({ } } let lookupColumn = lookupColOpt - ? await lookupColOpt.getLookupColumn() - : await getDisplayValueOfRefTable(column); + ? await lookupColOpt.getLookupColumn(context) + : await getDisplayValueOfRefTable(context, column); // if lookup column is qr code or barcode extract the referencing column if ([UITypes.QrCode, UITypes.Barcode].includes(lookupColumn.uidt)) { lookupColumn = await lookupColumn - .getColOptions() - .then((barcode) => barcode.getValueColumn()); + .getColOptions(context) + .then((barcode) => barcode.getValueColumn(context)); } let prevAlias = alias; @@ -183,14 +187,16 @@ export default async function generateLookupSelectQuery({ let nestedLookupColOpt: LookupColumn; if (lookupColumn.uidt === UITypes.Lookup) { - nestedLookupColOpt = await lookupColumn.getColOptions(); - relationCol = await nestedLookupColOpt.getRelationColumn(); + nestedLookupColOpt = await lookupColumn.getColOptions( + context, + ); + relationCol = await nestedLookupColOpt.getRelationColumn(context); } else { relationCol = lookupColumn; } const relation = - await relationCol.getColOptions(); + await relationCol.getColOptions(context); let relationType = relation.type; @@ -203,12 +209,12 @@ export default async function generateLookupSelectQuery({ // if any of the relation in nested lookupColOpt is // not belongs to then throw error as we don't support if (relationType === RelationTypes.BELONGS_TO) { - const childColumn = await relation.getChildColumn(); - const parentColumn = await relation.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relation.getChildColumn(context); + const parentColumn = await relation.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); selectQb.join( knex.raw(`?? as ??`, [ @@ -220,12 +226,12 @@ export default async function generateLookupSelectQuery({ ); } else if (relationType === RelationTypes.HAS_MANY) { isBtLookup = false; - const childColumn = await relation.getChildColumn(); - const parentColumn = await relation.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relation.getChildColumn(context); + const parentColumn = await relation.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); selectQb.join( knex.raw(`?? as ??`, [ @@ -237,18 +243,18 @@ export default async function generateLookupSelectQuery({ ); } else if (relationType === RelationTypes.MANY_TO_MANY) { isBtLookup = false; - const childColumn = await relation.getChildColumn(); - const parentColumn = await relation.getParentColumn(); - const childModel = await childColumn.getModel(); - await childModel.getColumns(); - const parentModel = await parentColumn.getModel(); - await parentModel.getColumns(); + const childColumn = await relation.getChildColumn(context); + const parentColumn = await relation.getParentColumn(context); + const childModel = await childColumn.getModel(context); + await childModel.getColumns(context); + const parentModel = await parentColumn.getModel(context); + await parentModel.getColumns(context); const mmTableAlias = getAlias(); - const mmModel = await relation.getMMModel(); - const mmChildCol = await relation.getMMChildColumn(); - const mmParentCol = await relation.getMMParentColumn(); + const mmModel = await relation.getMMModel(context); + const mmChildCol = await relation.getMMChildColumn(context); + const mmParentCol = await relation.getMMParentColumn(context); selectQb .innerJoin( @@ -278,15 +284,15 @@ export default async function generateLookupSelectQuery({ } if (lookupColumn.uidt === UITypes.Lookup) - lookupColumn = await nestedLookupColOpt.getLookupColumn(); - else lookupColumn = await getDisplayValueOfRefTable(relationCol); + lookupColumn = await nestedLookupColOpt.getLookupColumn(context); + else lookupColumn = await getDisplayValueOfRefTable(context, relationCol); prevAlias = nestedAlias; } { // get basemodel and model of lookup column - const model = await lookupColumn.getModel(); - const baseModelSqlv2 = await Model.getBaseModelSQL({ + const model = await lookupColumn.getModel(context); + const baseModelSqlv2 = await Model.getBaseModelSQL(context, { model, dbDriver: knex, }); @@ -304,8 +310,9 @@ export default async function generateLookupSelectQuery({ await genRollupSelectv2({ baseModelSqlv2, knex, - columnOptions: - (await lookupColumn.getColOptions()) as RollupColumn, + columnOptions: (await lookupColumn.getColOptions( + context, + )) as RollupColumn, alias: prevAlias, }) ).builder; @@ -318,12 +325,12 @@ export default async function generateLookupSelectQuery({ await formulaQueryBuilderv2( baseModelSqlv2, ( - await lookupColumn.getColOptions() + await lookupColumn.getColOptions(context) ).formula, lookupColumn.id, model, lookupColumn, - await model.getAliasColMapping(), + await model.getAliasColMapping(context), prevAlias, ) ).builder; diff --git a/packages/nocodb/src/db/sortV2.ts b/packages/nocodb/src/db/sortV2.ts index 8b5bac7863..290b29294d 100644 --- a/packages/nocodb/src/db/sortV2.ts +++ b/packages/nocodb/src/db/sortV2.ts @@ -19,6 +19,8 @@ export default async function sortV2( ) { const knex = baseModelSqlv2.dbDriver; + const context = baseModelSqlv2.context; + if (!sortList?.length) { return; } @@ -30,14 +32,17 @@ export default async function sortV2( } else { sort = new Sort(_sort); } - const column = await getRefColumnIfAlias(await sort.getColumn()); + const column = await getRefColumnIfAlias( + context, + await sort.getColumn(context), + ); if (!column) { if (throwErrorIfInvalid) { NcError.fieldNotFound(sort.fk_column_id); } continue; } - const model = await column.getModel(); + const model = await column.getModel(context); const nulls = sort.direction === 'desc' ? 'LAST' : 'FIRST'; @@ -49,7 +54,9 @@ export default async function sortV2( await genRollupSelectv2({ baseModelSqlv2, knex, - columnOptions: (await column.getColOptions()) as RollupColumn, + columnOptions: (await column.getColOptions( + context, + )) as RollupColumn, alias, }) ).builder; @@ -63,7 +70,7 @@ export default async function sortV2( await formulaQueryBuilderv2( baseModelSqlv2, ( - await column.getColOptions() + await column.getColOptions(context) ).formula, null, model, @@ -144,8 +151,8 @@ export default async function sortV2( case UITypes.User: case UITypes.CreatedBy: case UITypes.LastModifiedBy: { - const base = await Base.get(model.base_id); - const baseUsers = await BaseUser.getUsersList({ + const base = await Base.get(context, model.base_id); + const baseUsers = await BaseUser.getUsersList(context, { base_id: base.id, }); diff --git a/packages/nocodb/src/db/sql-mgr/v2/ProjectMgrv2.ts b/packages/nocodb/src/db/sql-mgr/v2/ProjectMgrv2.ts index 83e28522d1..b0228d7536 100644 --- a/packages/nocodb/src/db/sql-mgr/v2/ProjectMgrv2.ts +++ b/packages/nocodb/src/db/sql-mgr/v2/ProjectMgrv2.ts @@ -3,6 +3,7 @@ import SqlMgrv2Trans from './SqlMgrv2Trans'; import type { MetaService } from '~/meta/meta.service'; // import type NcMetaIO from '~/meta/NcMetaIO'; import type Source from '~/models/Source'; +import type { NcContext } from '~/interface/config'; export default class ProjectMgrv2 { private static sqlMgrMap: { @@ -10,24 +11,26 @@ export default class ProjectMgrv2 { } = {}; public static getSqlMgr( + context: NcContext, base: { id: string }, ncMeta: MetaService = null, ): SqlMgrv2 { - if (ncMeta) return new SqlMgrv2(base, ncMeta); + if (ncMeta) return new SqlMgrv2(context, base, ncMeta); if (!this.sqlMgrMap[base.id]) { - this.sqlMgrMap[base.id] = new SqlMgrv2(base); + this.sqlMgrMap[base.id] = new SqlMgrv2(context, base); } return this.sqlMgrMap[base.id]; } public static async getSqlMgrTrans( + context: NcContext, base: { id: string }, // todo: tobe changed ncMeta: any, source: Source, ): Promise { - const sqlMgr = new SqlMgrv2Trans(base, ncMeta, source); + const sqlMgr = new SqlMgrv2Trans(context, base, ncMeta, source); await sqlMgr.startTransaction(source); return sqlMgr; } diff --git a/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts b/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts index 9c0232c275..4b2f4d2102 100644 --- a/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts +++ b/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2.ts @@ -3,6 +3,7 @@ // import {XKnex} from "../sql-data-mapper"; import type { MetaService } from '~/meta/meta.service'; import type Source from '~/models/Source'; +import type { NcContext } from '~/interface/config'; import SqlClientFactory from '~/db/sql-client/lib/SqlClientFactory'; import KnexMigratorv2 from '~/db/sql-migrator/lib/KnexMigratorv2'; import Debug from '~/db/util/Debug'; @@ -11,6 +12,8 @@ import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; const log = new Debug('SqlMgr'); export default class SqlMgrv2 { + public context: NcContext; + protected _migrator: KnexMigratorv2; protected ncMeta?: MetaService; // @ts-ignore @@ -22,12 +25,13 @@ export default class SqlMgrv2 { * @param {String} args.toolDbPath - path to sqlite file that sql mgr will use * @memberof SqlMgr */ - constructor(args: { id: string }, ncMeta = null) { + constructor(context: NcContext, args: { id: string }, ncMeta = null) { const func = 'constructor'; log.api(`${func}:args:`, args); // this.metaDb = args.metaDb; - this._migrator = new KnexMigratorv2(args); + this._migrator = new KnexMigratorv2(context, args); this.ncMeta = ncMeta; + this.context = context; } public async migrator(_base: Source) { diff --git a/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2Trans.ts b/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2Trans.ts index 5c15957d18..a99a7fcdff 100644 --- a/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2Trans.ts +++ b/packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2Trans.ts @@ -3,6 +3,7 @@ import SqlMgrv2 from './SqlMgrv2'; import type { Knex } from 'knex'; import type { XKnex } from '../../CustomKnex'; import type Source from '~/models/Source'; +import type { NcContext } from '~/interface/config'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; export default class SqlMgrv2Trans extends SqlMgrv2 { @@ -19,8 +20,13 @@ export default class SqlMgrv2Trans extends SqlMgrv2 { * @memberof SqlMgr */ // todo: tobe changed - constructor(args: { id: string }, ncMeta: any, source: Source) { - super(args); + constructor( + context: NcContext, + args: { id: string }, + ncMeta: any, + source: Source, + ) { + super(context, args); this.baseId = args.id; this.ncMeta = ncMeta; this.source = source; @@ -28,6 +34,7 @@ export default class SqlMgrv2Trans extends SqlMgrv2 { public async migrator() { return new KnexMigratorv2Tans( + this.context, { id: this.baseId }, await this.getSqlClient(this.source), this.ncMeta, diff --git a/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2.ts b/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2.ts index f9f7d99a36..d4fc962c83 100644 --- a/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2.ts +++ b/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2.ts @@ -9,6 +9,7 @@ import Result from '../../util/Result'; import type Source from '~/models/Source'; import type { XKnex } from '~/db/CustomKnex'; import type { Knex } from 'knex'; +import type { NcContext } from '~/interface/config'; import SqlClientFactory from '~/db/sql-client/lib/SqlClientFactory'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; import Noco from '~/Noco'; @@ -26,6 +27,8 @@ const NC_MIGRATION = 'nc_migrations'; * @extends {SqlMigrator} */ export default class KnexMigratorv2 { + public context: NcContext; + //extends SqlMigrator { private baseId: string; private toolDir = process.cwd(); @@ -34,8 +37,9 @@ export default class KnexMigratorv2 { * Creates an instance of KnexMigrator. * @memberof KnexMigrator */ - constructor(base: { id: string }) { + constructor(context: NcContext, base: { id: string }) { this.baseId = base.id; + this.context = context; } protected get metaDb(): XKnex { @@ -43,7 +47,7 @@ export default class KnexMigratorv2 { } private async getProject(): Promise { - return Base.getWithInfo(this.baseId); + return Base.getWithInfo(this.context, this.baseId); } emit(data, _args?) { diff --git a/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2Tans.ts b/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2Tans.ts index 6e62bfea00..409689f38f 100644 --- a/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2Tans.ts +++ b/packages/nocodb/src/db/sql-migrator/lib/KnexMigratorv2Tans.ts @@ -12,6 +12,7 @@ import type MysqlClient from '~/db/sql-client/lib/mysql/MysqlClient'; import type OracleClient from '~/db/sql-client/lib/oracle/OracleClient'; import type PGClient from '~/db/sql-client/lib/pg/PgClient'; import type SqliteClient from '~/db/sql-client/lib/sqlite/SqliteClient'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; @@ -20,8 +21,13 @@ export default class KnexMigratorv2Tans extends KnexMigratorv2 { // todo: tobe changed protected ncMeta: any; // NcMetaIO; - constructor(base: { id: string }, sqlClient = null, ncMeta = Noco.ncMeta) { - super(base); + constructor( + context: NcContext, + base: { id: string }, + sqlClient = null, + ncMeta = Noco.ncMeta, + ) { + super(context, base); this.sqlClient = sqlClient; this.ncMeta = ncMeta; } diff --git a/packages/nocodb/src/decorators/tenant-context.decorator.ts b/packages/nocodb/src/decorators/tenant-context.decorator.ts new file mode 100644 index 0000000000..1b43c8eaef --- /dev/null +++ b/packages/nocodb/src/decorators/tenant-context.decorator.ts @@ -0,0 +1,10 @@ +import { createParamDecorator } from '@nestjs/common'; +import type { ExecutionContext } from '@nestjs/common'; +import type { NcRequest } from '~/interface/config'; + +export const TenantContext = createParamDecorator( + (data: unknown, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + return request.context; + }, +); diff --git a/packages/nocodb/src/helpers/NcPluginMgrv2.ts b/packages/nocodb/src/helpers/NcPluginMgrv2.ts index 717ee663c4..6abd44b949 100644 --- a/packages/nocodb/src/helpers/NcPluginMgrv2.ts +++ b/packages/nocodb/src/helpers/NcPluginMgrv2.ts @@ -30,7 +30,7 @@ import VultrPluginConfig from '~/plugins/vultr'; import SESPluginConfig from '~/plugins/ses'; import Noco from '~/Noco'; import Local from '~/plugins/storage/Local'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; import Plugin from '~/models/Plugin'; const defaultPlugins = [ @@ -67,24 +67,34 @@ class NcPluginMgrv2 { public static async init(ncMeta = Noco.ncMeta): Promise { /* Populate rows into nc_plugins table if not present */ for (const plugin of defaultPlugins) { - const pluginConfig = await ncMeta.metaGet(null, null, MetaTable.PLUGIN, { - title: plugin.title, - }); + const pluginConfig = await ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.PLUGIN, + { + title: plugin.title, + }, + ); if (!pluginConfig) { - await ncMeta.metaInsert2(null, null, MetaTable.PLUGIN, { - title: plugin.title, - version: plugin.version, - logo: plugin.logo, - description: plugin.description, - tags: plugin.tags, - category: plugin.category, - input_schema: JSON.stringify(plugin.inputs), - }); + await ncMeta.metaInsert2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.PLUGIN, + { + title: plugin.title, + version: plugin.version, + logo: plugin.logo, + description: plugin.description, + tags: plugin.tags, + category: plugin.category, + input_schema: JSON.stringify(plugin.inputs), + }, + ); } else if (pluginConfig.version !== plugin.version) { await ncMeta.metaUpdate( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.PLUGIN, { title: plugin.title, @@ -152,10 +162,15 @@ class NcPluginMgrv2 { public static async storageAdapter( ncMeta = Noco.ncMeta, ): Promise { - const pluginData = await ncMeta.metaGet2(null, null, MetaTable.PLUGIN, { - category: PluginCategory.STORAGE, - active: true, - }); + const pluginData = await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.PLUGIN, + { + category: PluginCategory.STORAGE, + active: true, + }, + ); if (!pluginData) return new Local(); @@ -177,10 +192,15 @@ class NcPluginMgrv2 { isUserInvite = true, ncMeta = Noco.ncMeta, ): Promise { - const pluginData = await ncMeta.metaGet2(null, null, MetaTable.PLUGIN, { - category: PluginCategory.EMAIL, - active: true, - }); + const pluginData = await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.PLUGIN, + { + category: PluginCategory.EMAIL, + active: true, + }, + ); if (!pluginData) { // return null to show the invite link in UI @@ -207,10 +227,15 @@ class NcPluginMgrv2 { title: string, ncMeta = Noco.ncMeta, ): Promise { - const pluginData = await ncMeta.metaGet2(null, null, MetaTable.PLUGIN, { - title, - active: true, - }); + const pluginData = await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.PLUGIN, + { + title, + active: true, + }, + ); if (!pluginData) throw new Error('Plugin not configured / active'); diff --git a/packages/nocodb/src/helpers/catchError.ts b/packages/nocodb/src/helpers/catchError.ts index 334c2c9da3..242e83864e 100644 --- a/packages/nocodb/src/helpers/catchError.ts +++ b/packages/nocodb/src/helpers/catchError.ts @@ -498,6 +498,10 @@ const errorHelpers: { }, code: 404, }, + [NcErrorType.GENERIC_NOT_FOUND]: { + message: (resource: string, id: string) => `${resource} '${id}' not found`, + code: 404, + }, [NcErrorType.ERROR_DUPLICATE_RECORD]: { message: (...ids: string[]) => { const isMultiple = Array.isArray(ids) && ids.length > 1; @@ -665,6 +669,13 @@ export class NcError { }); } + static genericNotFound(resource: string, id: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.GENERIC_NOT_FOUND, { + params: [resource, id], + ...args, + }); + } + static duplicateRecord(id: string | string[], args?: NcErrorArgs) { throw new NcBaseErrorv2(NcErrorType.ERROR_DUPLICATE_RECORD, { params: id, diff --git a/packages/nocodb/src/helpers/columnHelpers.ts b/packages/nocodb/src/helpers/columnHelpers.ts index 44fa16c4fa..f790b4f4e6 100644 --- a/packages/nocodb/src/helpers/columnHelpers.ts +++ b/packages/nocodb/src/helpers/columnHelpers.ts @@ -16,6 +16,7 @@ import type { import type LinkToAnotherRecordColumn from '~/models/LinkToAnotherRecordColumn'; import type LookupColumn from '~/models/LookupColumn'; import type Model from '~/models/Model'; +import type { NcContext } from '~/interface/config'; import type { RollupColumn, View } from '~/models'; import { GridViewColumn } from '~/models'; import validateParams from '~/helpers/validateParams'; @@ -29,6 +30,7 @@ export const randomID = customAlphabet( ); export async function createHmAndBtColumn( + context: NcContext, child: Model, parent: Model, childColumn: Column, @@ -45,10 +47,10 @@ export async function createHmAndBtColumn( // save bt column { const title = getUniqueColumnAliasName( - await child.getColumns(), + await child.getColumns(context), (type === 'bt' && alias) || `${parent.title}`, ); - await Column.insert({ + await Column.insert(context, { title, fk_model_id: child.id, @@ -71,7 +73,7 @@ export async function createHmAndBtColumn( // save hm column { const title = getUniqueColumnAliasName( - await parent.getColumns(), + await parent.getColumns(context), (type === 'hm' && alias) || pluralize(child.title), ); const meta = { @@ -80,7 +82,7 @@ export async function createHmAndBtColumn( singular: columnMeta?.singular || singularize(child.title), }; - await Column.insert({ + await Column.insert(context, { title, fk_model_id: parent.id, uidt: isLinks ? UITypes.Links : UITypes.LinkToAnotherRecord, @@ -114,6 +116,7 @@ export async function createHmAndBtColumn( * @param {any} [colExtra] - Additional column parameters. */ export async function createOOColumn( + context: NcContext, child: Model, parent: Model, childColumn: Column, @@ -129,10 +132,10 @@ export async function createOOColumn( // save bt column { const title = getUniqueColumnAliasName( - await child.getColumns(), + await child.getColumns(context), `${parent.title}`, ); - await Column.insert({ + await Column.insert(context, { title, fk_model_id: child.id, // ref_db_alias @@ -160,7 +163,7 @@ export async function createOOColumn( // save hm column { const title = getUniqueColumnAliasName( - await parent.getColumns(), + await parent.getColumns(context), alias || child.title, ); const meta = { @@ -169,7 +172,7 @@ export async function createOOColumn( singular: columnMeta?.singular || singularize(child.title), }; - await Column.insert({ + await Column.insert(context, { title, fk_model_id: parent.id, uidt: UITypes.LinkToAnotherRecord, @@ -188,7 +191,10 @@ export async function createOOColumn( } } -export async function validateRollupPayload(payload: ColumnReqType | Column) { +export async function validateRollupPayload( + context: NcContext, + payload: ColumnReqType | Column, +) { validateParams( [ 'title', @@ -200,10 +206,10 @@ export async function validateRollupPayload(payload: ColumnReqType | Column) { ); const relation = await ( - await Column.get({ + await Column.get(context, { colId: (payload as RollupColumnReqType).fk_relation_column_id, }) - ).getColOptions(); + ).getColOptions(context); if (!relation) { throw new Error('Relation column not found'); @@ -212,21 +218,21 @@ export async function validateRollupPayload(payload: ColumnReqType | Column) { let relatedColumn: Column; switch (relation.type) { case 'hm': - relatedColumn = await Column.get({ + relatedColumn = await Column.get(context, { colId: relation.fk_child_column_id, }); break; case 'mm': case 'bt': - relatedColumn = await Column.get({ + relatedColumn = await Column.get(context, { colId: relation.fk_parent_column_id, }); break; } - const relatedTable = await relatedColumn.getModel(); + const relatedTable = await relatedColumn.getModel(context); if ( - !(await relatedTable.getColumns()).find( + !(await relatedTable.getColumns(context)).find( (c) => c.id === (payload as RollupColumnReqType).fk_rollup_column_id, ) ) @@ -246,6 +252,7 @@ export async function validateRollupPayload(payload: ColumnReqType | Column) { } export async function validateLookupPayload( + context: NcContext, payload: ColumnReqType, columnId?: string, ) { @@ -262,20 +269,20 @@ export async function validateLookupPayload( // check if lookup column is same as column itself if (columnId === lkCol.fk_lookup_column_id) throw new Error('Circular lookup reference not allowed'); - lkCol = await Column.get({ colId: lkCol.fk_lookup_column_id }).then( - (c: Column) => { - if (c.uidt === 'Lookup') { - return c.getColOptions(); - } - return null; - }, - ); + lkCol = await Column.get(context, { + colId: lkCol.fk_lookup_column_id, + }).then((c: Column) => { + if (c.uidt === 'Lookup') { + return c.getColOptions(context); + } + return null; + }); } } - const column = await Column.get({ + const column = await Column.get(context, { colId: (payload as LookupColumnReqType).fk_relation_column_id, }); - const relation = await column.getColOptions(); + const relation = await column.getColOptions(context); if (!relation) { throw new Error('Relation column not found'); @@ -284,18 +291,18 @@ export async function validateLookupPayload( let relatedColumn: Column; switch (relation.type) { case 'hm': - relatedColumn = await Column.get({ + relatedColumn = await Column.get(context, { colId: relation.fk_child_column_id, }); break; case 'mm': case 'bt': - relatedColumn = await Column.get({ + relatedColumn = await Column.get(context, { colId: relation.fk_parent_column_id, }); break; case 'oo': - relatedColumn = await Column.get({ + relatedColumn = await Column.get(context, { colId: column.meta?.bt ? relation.fk_parent_column_id : relation.fk_child_column_id, @@ -303,9 +310,9 @@ export async function validateLookupPayload( break; } - const relatedTable = await relatedColumn.getModel(); + const relatedTable = await relatedColumn.getModel(context); if ( - !(await relatedTable.getColumns()).find( + !(await relatedTable.getColumns(context)).find( (c) => c.id === (payload as LookupColumnReqType).fk_lookup_column_id, ) ) @@ -336,34 +343,37 @@ export const generateFkName = (parent: TableType, child: TableType) => { }; export async function populateRollupForLTAR({ + context, column, columnMeta, alias, }: { + context: NcContext; column: Column; columnMeta?: any; alias?: string; }) { - const model = await column.getModel(); + const model = await column.getModel(context); - const views = await model.getViews(); + const views = await model.getViews(context); const relatedModel = await column - .getColOptions() - .then((colOpt) => colOpt.getRelatedTable()); - await relatedModel.getColumns(); + .getColOptions(context) + .then((colOpt) => colOpt.getRelatedTable(context)); + await relatedModel.getColumns(context); const pkId = - relatedModel.primaryKey?.id || (await relatedModel.getColumns())[0]?.id; + relatedModel.primaryKey?.id || + (await relatedModel.getColumns(context))[0]?.id; const meta = { plural: columnMeta?.plural || pluralize(relatedModel.title), singular: columnMeta?.singular || singularize(relatedModel.title), }; - await Column.insert({ + await Column.insert(context, { uidt: UITypes.Links, title: getUniqueColumnAliasName( - await model.getColumns(), + await model.getColumns(context), alias || `${relatedModel.title} Count`, ), fk_rollup_column_id: pkId, @@ -373,10 +383,10 @@ export async function populateRollupForLTAR({ meta, }); - const viewCol = await GridViewColumn.list(views[0].id).then((cols) => + const viewCol = await GridViewColumn.list(context, views[0].id).then((cols) => cols.find((c) => c.fk_column_id === column.id), ); - await GridViewColumn.update(viewCol.id, { show: false }); + await GridViewColumn.update(context, viewCol.id, { show: false }); } export const sanitizeColumnName = (name: string, sourceType?: DriverClient) => { @@ -399,6 +409,7 @@ export const sanitizeColumnName = (name: string, sourceType?: DriverClient) => { // if column is an alias column then return the original column // for example CreatedTime is an alias column for CreatedTime system column export const getRefColumnIfAlias = async ( + context: NcContext, column: Column, columns?: Column[], ) => { @@ -415,8 +426,9 @@ export const getRefColumnIfAlias = async ( return column; return ( - (columns || (await Column.list({ fk_model_id: column.fk_model_id }))).find( - (c) => c.system && c.uidt === column.uidt, - ) || column + ( + columns || + (await Column.list(context, { fk_model_id: column.fk_model_id })) + ).find((c) => c.system && c.uidt === column.uidt) || column ); }; diff --git a/packages/nocodb/src/helpers/dataHelpers.ts b/packages/nocodb/src/helpers/dataHelpers.ts index 72a068e745..6eb82bd3a3 100644 --- a/packages/nocodb/src/helpers/dataHelpers.ts +++ b/packages/nocodb/src/helpers/dataHelpers.ts @@ -5,6 +5,7 @@ import papaparse from 'papaparse'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; import type LinkToAnotherRecordColumn from '~/models/LinkToAnotherRecordColumn'; import type LookupColumn from '~/models/LookupColumn'; +import type { NcContext } from '~/interface/config'; import { NcError } from '~/helpers/catchError'; import getAst from '~/helpers/getAst'; import { Model, View } from '~/models'; @@ -25,14 +26,17 @@ export interface OldPathParams { viewName?: string; } -export async function getViewAndModelByAliasOrId(param: { - baseName: string; - tableName: string; - viewName?: string; -}) { - const base = await Base.getWithInfoByTitleOrId(param.baseName); +export async function getViewAndModelByAliasOrId( + context: NcContext, + param: { + baseName: string; + tableName: string; + viewName?: string; + }, +) { + const base = await Base.getWithInfoByTitleOrId(context, param.baseName); - const model = await Model.getByAliasOrId({ + const model = await Model.getByAliasOrId(context, { base_id: base.id, aliasOrId: param.tableName, }); @@ -41,7 +45,7 @@ export async function getViewAndModelByAliasOrId(param: { const view = param.viewName && - (await View.getByTitleOrId({ + (await View.getByTitleOrId(context, { titleOrId: param.viewName, fk_model_id: model.id, })); @@ -49,11 +53,11 @@ export async function getViewAndModelByAliasOrId(param: { return { model, view }; } -export async function extractXlsxData(view: View, req) { - const source = await Source.get(view.source_id); +export async function extractXlsxData(context: NcContext, view: View, req) { + const source = await Source.get(context, view.source_id); - await view.getModelWithInfo(); - await view.getColumns(); + await view.getModelWithInfo(context); + await view.getColumns(context); view.model.columns = view.columns .filter((c) => c.show) @@ -63,13 +67,13 @@ export async function extractXlsxData(view: View, req) { ) .filter((column) => !isSystemColumn(column) || view.show_system_fields); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: view.model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { offset, dbRows, elapsed } = await getDbRows({ + const { offset, dbRows, elapsed } = await getDbRows(context, { baseModel, view, siteUrl: (req as any).ncSiteUrl, @@ -83,12 +87,12 @@ export async function extractXlsxData(view: View, req) { return { offset, dbRows, elapsed, data }; } -export async function extractCsvData(view: View, req) { - const source = await Source.get(view.source_id); +export async function extractCsvData(context: NcContext, view: View, req) { + const source = await Source.get(context, view.source_id); const fields = req.query.fields; - await view.getModelWithInfo(); - await view.getColumns(); + await view.getModelWithInfo(context); + await view.getColumns(context); view.model.columns = view.columns .filter((c) => c.show) @@ -98,13 +102,13 @@ export async function extractCsvData(view: View, req) { ) .filter((column) => !isSystemColumn(column) || view.show_system_fields); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: view.model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { offset, dbRows, elapsed } = await getDbRows({ + const { offset, dbRows, elapsed } = await getDbRows(context, { baseModel, view, query: req.query, @@ -136,15 +140,18 @@ export async function extractCsvData(view: View, req) { return { offset, dbRows, elapsed, data }; } -export async function serializeCellValue({ - value, - column, - siteUrl, -}: { - column?: Column; - value: any; - siteUrl: string; -}) { +export async function serializeCellValue( + context: NcContext, + { + value, + column, + siteUrl, + }: { + column?: Column; + value: any; + siteUrl: string; + }, +) { if (!column) { return value; } @@ -187,12 +194,12 @@ export async function serializeCellValue({ } case UITypes.Lookup: { - const colOptions = await column.getColOptions(); - const lookupColumn = await colOptions.getLookupColumn(); + const colOptions = await column.getColOptions(context); + const lookupColumn = await colOptions.getLookupColumn(context); return ( await Promise.all( [...(Array.isArray(value) ? value : [value])].map(async (v) => - serializeCellValue({ + serializeCellValue(context, { value: v, column: lookupColumn, siteUrl, @@ -205,9 +212,9 @@ export async function serializeCellValue({ case UITypes.LinkToAnotherRecord: { const colOptions = - await column.getColOptions(); - const relatedModel = await colOptions.getRelatedTable(); - await relatedModel.getColumns(); + await column.getColOptions(context); + const relatedModel = await colOptions.getRelatedTable(context); + await relatedModel.getColumns(context); return [...(Array.isArray(value) ? value : [value])] .map((v) => { return v[relatedModel.displayValue?.title]; @@ -224,10 +231,11 @@ export async function serializeCellValue({ } export async function getColumnByIdOrName( + context: NcContext, columnNameOrId: string, model: Model, ) { - const column = (await model.getColumns()).find( + const column = (await model.getColumns(context)).find( (c) => c.title === columnNameOrId || c.id === columnNameOrId || @@ -239,12 +247,15 @@ export async function getColumnByIdOrName( return column; } -export async function getDbRows(param: { - baseModel: BaseModelSqlv2; - view: View; - query: any; - siteUrl: string; -}) { +export async function getDbRows( + context: NcContext, + param: { + baseModel: BaseModelSqlv2; + view: View; + query: any; + siteUrl: string; + }, +) { const { baseModel, view, query = {}, siteUrl } = param; let offset = +query.offset || 0; const limit = 100; @@ -269,7 +280,7 @@ export async function getDbRows(param: { temp = process.hrtime(startTime), elapsed = temp[0] * 1000 + temp[1] / 1000000 ) { - const { ast, dependencyFields } = await getAst({ + const { ast, dependencyFields } = await getAst(context, { query: query, includePkByDefault: false, model: view.model, @@ -292,7 +303,7 @@ export async function getDbRows(param: { for (const column of view.model.columns) { if (isSystemColumn(column) && !view.show_system_fields) continue; - dbRow[column.title] = await serializeCellValue({ + dbRow[column.title] = await serializeCellValue(context, { value: row[column.title], column, siteUrl, diff --git a/packages/nocodb/src/helpers/exportImportHelpers.ts b/packages/nocodb/src/helpers/exportImportHelpers.ts index 6b6a87e6c1..d81257b66c 100644 --- a/packages/nocodb/src/helpers/exportImportHelpers.ts +++ b/packages/nocodb/src/helpers/exportImportHelpers.ts @@ -1,16 +1,18 @@ import type { Source } from '~/models'; +import type { NcContext } from '~/interface/config'; export async function generateBaseIdMap( + context: NcContext, source: Source, idMap: Map, ) { idMap.set(source.base_id, source.base_id); idMap.set(source.id, `${source.base_id}::${source.id}`); - const models = await source.getModels(); + const models = await source.getModels(context); for (const md of models) { idMap.set(md.id, `${source.base_id}::${source.id}::${md.id}`); - await md.getColumns(); + await md.getColumns(context); for (const column of md.columns) { idMap.set(column.id, `${idMap.get(md.id)}::${column.id}`); } diff --git a/packages/nocodb/src/helpers/extractProps.ts b/packages/nocodb/src/helpers/extractProps.ts index f90dc209e4..03f155aeff 100644 --- a/packages/nocodb/src/helpers/extractProps.ts +++ b/packages/nocodb/src/helpers/extractProps.ts @@ -6,7 +6,7 @@ export function extractProps>( ): Partial { // todo: throw error if no props found return props.reduce((o, key) => { - if (key in body) o[key] = body[key]; + if (key in body && body[key] !== undefined) o[key] = body[key]; return o; }, {}); } diff --git a/packages/nocodb/src/helpers/formulaFnHelper.ts b/packages/nocodb/src/helpers/formulaFnHelper.ts index 9c7a1d0b08..b9aa72cdb4 100644 --- a/packages/nocodb/src/helpers/formulaFnHelper.ts +++ b/packages/nocodb/src/helpers/formulaFnHelper.ts @@ -1,5 +1,6 @@ import { UITypes } from 'nocodb-sdk'; import { convertDateFormat } from './convertDateFormat'; +import type { NcContext } from '~/interface/config'; import Column from '~/models/Column'; export function getWeekdayByText(v: string) { @@ -27,6 +28,7 @@ export function getWeekdayByIndex(idx: number): string { } export async function convertDateFormatForConcat( + context: NcContext, o, columnIdToUidt, query, @@ -38,7 +40,7 @@ export async function convertDateFormatForConcat( columnIdToUidt[o.name] === UITypes.Date ) { const meta = ( - await Column.get({ + await Column.get(context, { colId: o.name, }) ).meta; diff --git a/packages/nocodb/src/helpers/formulaHelpers.ts b/packages/nocodb/src/helpers/formulaHelpers.ts index 10333c7f88..76a52ef515 100644 --- a/packages/nocodb/src/helpers/formulaHelpers.ts +++ b/packages/nocodb/src/helpers/formulaHelpers.ts @@ -2,9 +2,11 @@ import jsep from 'jsep'; import { UITypes } from 'nocodb-sdk'; import type FormulaColumn from '../models/FormulaColumn'; import type { Column } from '~/models'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; export async function getFormulasReferredTheColumn( + context: NcContext, { column, columns, @@ -29,7 +31,7 @@ export async function getFormulasReferredTheColumn( const columns = await columnsPromise; if (c.uidt !== UITypes.Formula) return columns; - const formula = await c.getColOptions(ncMeta); + const formula = await c.getColOptions(context, ncMeta); if (fn(jsep(formula.formula))) { columns.push(c); diff --git a/packages/nocodb/src/helpers/getAst.ts b/packages/nocodb/src/helpers/getAst.ts index 156c99e847..7ab5214104 100644 --- a/packages/nocodb/src/helpers/getAst.ts +++ b/packages/nocodb/src/helpers/getAst.ts @@ -12,6 +12,7 @@ import type { LookupColumn, Model, } from '~/models'; +import type { NcContext } from '~/interface/config'; import { NcError } from '~/helpers/catchError'; import { CalendarRange, @@ -21,32 +22,35 @@ import { View, } from '~/models'; -const getAst = async ({ - query, - extractOnlyPrimaries = false, - includePkByDefault = true, - model, - view, - dependencyFields = { - ...(query || {}), - nested: { ...(query?.nested || {}) }, - fieldsSet: new Set(), +const getAst = async ( + context: NcContext, + { + query, + extractOnlyPrimaries = false, + includePkByDefault = true, + model, + view, + dependencyFields = { + ...(query || {}), + nested: { ...(query?.nested || {}) }, + fieldsSet: new Set(), + }, + getHiddenColumn = query?.['getHiddenColumn'], + throwErrorIfInvalidParams = false, + extractOnlyRangeFields = false, + }: { + query?: RequestQuery; + extractOnlyPrimaries?: boolean; + includePkByDefault?: boolean; + model: Model; + view?: View; + dependencyFields?: DependantFields; + getHiddenColumn?: boolean; + throwErrorIfInvalidParams?: boolean; + // Used for calendar view + extractOnlyRangeFields?: boolean; }, - getHiddenColumn = query?.['getHiddenColumn'], - throwErrorIfInvalidParams = false, - extractOnlyRangeFields = false, -}: { - query?: RequestQuery; - extractOnlyPrimaries?: boolean; - includePkByDefault?: boolean; - model: Model; - view?: View; - dependencyFields?: DependantFields; - getHiddenColumn?: boolean; - throwErrorIfInvalidParams?: boolean; - // Used for calendar view - extractOnlyRangeFields?: boolean; -}) => { +) => { // set default values of dependencyFields and nested dependencyFields.nested = dependencyFields.nested || {}; dependencyFields.fieldsSet = dependencyFields.fieldsSet || new Set(); @@ -54,15 +58,15 @@ const getAst = async ({ let coverImageId; let dependencyFieldsForCalenderView; if (view && view.type === ViewTypes.GALLERY) { - const gallery = await GalleryView.get(view.id); + const gallery = await GalleryView.get(context, view.id); coverImageId = gallery.fk_cover_image_col_id; } else if (view && view.type === ViewTypes.KANBAN) { - const kanban = await KanbanView.get(view.id); + const kanban = await KanbanView.get(context, view.id); coverImageId = kanban.fk_cover_image_col_id; } else if (view && view.type === ViewTypes.CALENDAR) { // const calendar = await CalendarView.get(view.id); // coverImageId = calendar.fk_cover_image_col_id; - const calenderRanges = await CalendarRange.read(view.id); + const calenderRanges = await CalendarRange.read(context, view.id); if (calenderRanges) { dependencyFieldsForCalenderView = calenderRanges.ranges .flatMap((obj) => @@ -72,7 +76,7 @@ const getAst = async ({ } } - if (!model.columns?.length) await model.getColumns(); + if (!model.columns?.length) await model.getColumns(context); // extract only pk and pv if (extractOnlyPrimaries) { @@ -83,10 +87,12 @@ const getAst = async ({ ...(model.displayValue ? { [model.displayValue.title]: 1 } : {}), }; await Promise.all( - model.primaryKeys.map((c) => extractDependencies(c, dependencyFields)), + model.primaryKeys.map((c) => + extractDependencies(context, c, dependencyFields), + ), ); - await extractDependencies(model.displayValue, dependencyFields); + await extractDependencies(context, model.displayValue, dependencyFields); return { ast, dependencyFields, parsedQuery: dependencyFields }; } @@ -102,6 +108,7 @@ const getAst = async ({ await Promise.all( (dependencyFieldsForCalenderView || []).map((f) => extractDependencies( + context, model.columns.find((c) => c.id === f), dependencyFields, ), @@ -115,8 +122,8 @@ const getAst = async ({ if (fields && fields !== '*') { fields = Array.isArray(fields) ? fields : fields.split(','); if (throwErrorIfInvalidParams) { - const colAliasMap = await model.getColAliasMapping(); - const aliasColMap = await model.getAliasColObjMap(); + const colAliasMap = await model.getColAliasMapping(context); + const aliasColMap = await model.getAliasColObjMap(context); const invalidFields = fields.filter( (f) => !colAliasMap[f] && !aliasColMap[f], ); @@ -130,7 +137,7 @@ const getAst = async ({ let allowedCols = null; if (view) { - allowedCols = (await View.getColumns(view.id)).reduce( + allowedCols = (await View.getColumns(context, view.id)).reduce( (o, c) => ({ ...o, [c.fk_column_id]: c.show || (c instanceof GridViewColumn && c.group_by), @@ -154,10 +161,10 @@ const getAst = async ({ if (nestedFields && nestedFields !== '*') { if (col.uidt === UITypes.LinkToAnotherRecord) { const model = await col - .getColOptions() - .then((colOpt) => colOpt.getRelatedTable()); + .getColOptions(context) + .then((colOpt) => colOpt.getRelatedTable(context)); - const { ast } = await getAst({ + const { ast } = await getAst(context, { model, query: query?.nested?.[col.title], dependencyFields: (dependencyFields.nested[col.title] = @@ -180,11 +187,11 @@ const getAst = async ({ } } else if (col.uidt === UITypes.LinkToAnotherRecord) { const model = await col - .getColOptions() - .then((colOpt) => colOpt.getRelatedTable()); + .getColOptions(context) + .then((colOpt) => colOpt.getRelatedTable(context)); value = ( - await getAst({ + await getAst(context, { model, query: query?.nested?.[col.title], extractOnlyPrimaries: nestedFields !== '*', @@ -221,7 +228,8 @@ const getAst = async ({ isRequested = value; } - if (isRequested || col.pk) await extractDependencies(col, dependencyFields); + if (isRequested || col.pk) + await extractDependencies(context, col, dependencyFields); return { ...(await obj), @@ -233,6 +241,7 @@ const getAst = async ({ }; const extractDependencies = async ( + context: NcContext, column: Column, dependencyFields: DependantFields = { nested: {}, @@ -241,10 +250,10 @@ const extractDependencies = async ( ) => { switch (column.uidt) { case UITypes.Lookup: - await extractLookupDependencies(column, dependencyFields); + await extractLookupDependencies(context, column, dependencyFields); break; case UITypes.LinkToAnotherRecord: - await extractRelationDependencies(column, dependencyFields); + await extractRelationDependencies(context, column, dependencyFields); break; default: dependencyFields.fieldsSet.add(column.title); @@ -253,17 +262,19 @@ const extractDependencies = async ( }; const extractLookupDependencies = async ( + context: NcContext, lookUpColumn: Column, dependencyFields: DependantFields = { nested: {}, fieldsSet: new Set(), }, ) => { - const lookupColumnOpts = await lookUpColumn.getColOptions(); - const relationColumn = await lookupColumnOpts.getRelationColumn(); - await extractRelationDependencies(relationColumn, dependencyFields); + const lookupColumnOpts = await lookUpColumn.getColOptions(context); + const relationColumn = await lookupColumnOpts.getRelationColumn(context); + await extractRelationDependencies(context, relationColumn, dependencyFields); await extractDependencies( - await lookupColumnOpts.getLookupColumn(), + context, + await lookupColumnOpts.getLookupColumn(context), (dependencyFields.nested[relationColumn.title] = dependencyFields.nested[ relationColumn.title ] || { @@ -274,34 +285,43 @@ const extractLookupDependencies = async ( }; const extractRelationDependencies = async ( + context: NcContext, relationColumn: Column, dependencyFields: DependantFields = { nested: {}, fieldsSet: new Set(), }, ) => { - const relationColumnOpts = await relationColumn.getColOptions(); + const relationColumnOpts = await relationColumn.getColOptions(context); switch (relationColumnOpts.type) { case RelationTypes.HAS_MANY: dependencyFields.fieldsSet.add( - await relationColumnOpts.getParentColumn().then((col) => col.title), + await relationColumnOpts + .getParentColumn(context) + .then((col) => col.title), ); break; case RelationTypes.BELONGS_TO: case RelationTypes.MANY_TO_MANY: dependencyFields.fieldsSet.add( - await relationColumnOpts.getChildColumn().then((col) => col.title), + await relationColumnOpts + .getChildColumn(context) + .then((col) => col.title), ); break; case RelationTypes.ONE_TO_ONE: if (relationColumn.meta?.bt) { dependencyFields.fieldsSet.add( - await relationColumnOpts.getChildColumn().then((col) => col.title), + await relationColumnOpts + .getChildColumn(context) + .then((col) => col.title), ); } else { dependencyFields.fieldsSet.add( - await relationColumnOpts.getParentColumn().then((col) => col.title), + await relationColumnOpts + .getParentColumn(context) + .then((col) => col.title), ); } break; diff --git a/packages/nocodb/src/helpers/initAdminFromEnv.ts b/packages/nocodb/src/helpers/initAdminFromEnv.ts index d627a99bcb..b45113a78a 100644 --- a/packages/nocodb/src/helpers/initAdminFromEnv.ts +++ b/packages/nocodb/src/helpers/initAdminFromEnv.ts @@ -8,7 +8,7 @@ import isEmail from 'validator/lib/isEmail'; import NocoCache from '~/cache/NocoCache'; import Noco from '~/Noco'; import { BaseUser, User } from '~/models'; -import { CacheScope, MetaTable } from '~/utils/globals'; +import { CacheScope, MetaTable, RootScopes } from '~/utils/globals'; import { randomTokenString } from '~/services/users/helpers'; const rolesLevel = { owner: 0, creator: 1, editor: 2, commenter: 3, viewer: 4 }; @@ -91,7 +91,11 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) { ); const email_verification_token = uuidv4(); // TODO improve this - const superUsers = await ncMeta.metaList2(null, null, MetaTable.USERS); + const superUsers = await ncMeta.metaList2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + ); let superUserPresent = false; @@ -113,14 +117,9 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) { if (existingUserWithNewEmail?.id) { // get all base access belongs to the existing account // and migrate to the admin account - const existingUserProjects = await ncMeta.metaList2( - null, - null, - MetaTable.PROJECT_USERS, - { - condition: { fk_user_id: existingUserWithNewEmail.id }, - }, - ); + const existingUserProjects = await ncMeta + .knexConnection(MetaTable.PROJECT_USERS) + .where({ fk_user_id: existingUserWithNewEmail.id }); for (const existingUserProject of existingUserProjects) { const userProject = await BaseUser.get( @@ -137,6 +136,10 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) { rolesLevel[existingUserProject.roles] ) { await BaseUser.update( + { + workspace_id: existingUserProject.workspace_id, + base_id: existingUserProject.base_id, + }, userProject.base_id, user.id, existingUserProject.roles, @@ -163,8 +166,8 @@ export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) { // delete existing user await ncMeta.metaDelete( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.USERS, existingUserWithNewEmail.id, ); diff --git a/packages/nocodb/src/helpers/populateMeta.ts b/packages/nocodb/src/helpers/populateMeta.ts index 397c3f0192..1fe5e5df16 100644 --- a/packages/nocodb/src/helpers/populateMeta.ts +++ b/packages/nocodb/src/helpers/populateMeta.ts @@ -8,6 +8,7 @@ import type LinkToAnotherRecordColumn from '~/models/LinkToAnotherRecordColumn'; import type Source from '~/models/Source'; import type Base from '~/models/Base'; import type PGClient from '~/db/sql-client/lib/pg/PgClient'; +import type { NcContext } from '~/interface/config'; import mapDefaultDisplayValue from '~/helpers/mapDefaultDisplayValue'; import getColumnUiType from '~/helpers/getColumnUiType'; import getTableNameAlias, { getColumnNameAlias } from '~/helpers/getTableName'; @@ -46,16 +47,19 @@ export const IGNORE_TABLES = [ ]; async function isMMRelationExist( + context: NcContext, model: Model, assocModel: Model, belongsToCol: Column, ) { let isExist = false; const colChildOpt = - await belongsToCol.getColOptions(); - for (const col of await model.getColumns()) { + await belongsToCol.getColOptions(context); + for (const col of await model.getColumns(context)) { if (col.uidt === UITypes.LinkToAnotherRecord) { - const colOpt = await col.getColOptions(); + const colOpt = await col.getColOptions( + context, + ); if ( colOpt && colOpt.type === RelationTypes.MANY_TO_MANY && @@ -73,10 +77,11 @@ async function isMMRelationExist( // @ts-ignore export async function extractAndGenerateManyToManyRelations( + context: NcContext, modelsArr: Array, ) { for (const assocModel of modelsArr) { - await assocModel.getColumns(); + await assocModel.getColumns(context); // check if table is a Bridge table(or Associative Table) by checking // number of foreign keys and columns @@ -84,7 +89,9 @@ export async function extractAndGenerateManyToManyRelations( const belongsToCols: Column[] = []; for (const col of assocModel.columns) { if (col.uidt == UITypes.LinkToAnotherRecord) { - const colOpt = await col.getColOptions(); + const colOpt = await col.getColOptions( + context, + ); if (colOpt?.type === RelationTypes.BELONGS_TO) belongsToCols.push(col); } } @@ -99,26 +106,28 @@ export async function extractAndGenerateManyToManyRelations( belongsToCols.some((c) => c.colOptions?.fk_child_column_id === pk.id), ) ) { - const modelA = await belongsToCols[0].colOptions.getRelatedTable(); - const modelB = await belongsToCols[1].colOptions.getRelatedTable(); + const modelA = await belongsToCols[0].colOptions.getRelatedTable(context); + const modelB = await belongsToCols[1].colOptions.getRelatedTable(context); - await modelA.getColumns(); - await modelB.getColumns(); + await modelA.getColumns(context); + await modelB.getColumns(context); // check tableA already have the relation or not const isRelationAvailInA = await isMMRelationExist( + context, modelA, assocModel, belongsToCols[0], ); const isRelationAvailInB = await isMMRelationExist( + context, modelB, assocModel, belongsToCols[1], ); if (!isRelationAvailInA) { - await Column.insert({ + await Column.insert(context, { title: getUniqueColumnAliasName( modelA.columns, pluralize(modelB.title), @@ -140,7 +149,7 @@ export async function extractAndGenerateManyToManyRelations( }); } if (!isRelationAvailInB) { - await Column.insert({ + await Column.insert(context, { title: getUniqueColumnAliasName( modelB.columns, pluralize(modelA.title), @@ -162,17 +171,19 @@ export async function extractAndGenerateManyToManyRelations( }); } - await Model.markAsMmTable(assocModel.id, true); + await Model.markAsMmTable(context, assocModel.id, true); // mark has many relation associated with mm as system field in both table for (const btCol of [belongsToCols[0], belongsToCols[1]]) { const colOpt = await btCol.colOptions; - const model = await colOpt.getRelatedTable(); + const model = await colOpt.getRelatedTable(context); - for (const col of await model.getColumns()) { + for (const col of await model.getColumns(context)) { if (!isLinksOrLTAR(col.uidt)) continue; - const colOpt1 = await col.getColOptions(); + const colOpt1 = await col.getColOptions( + context, + ); if (!colOpt1 || colOpt1.type !== RelationTypes.HAS_MANY) continue; if ( @@ -181,17 +192,19 @@ export async function extractAndGenerateManyToManyRelations( ) continue; - await Column.markAsSystemField(col.id); + await Column.markAsSystemField(context, col.id); break; } } } else { - if (assocModel.mm) await Model.markAsMmTable(assocModel.id, false); + if (assocModel.mm) + await Model.markAsMmTable(context, assocModel.id, false); } } } export async function populateMeta( + context: NcContext, source: Source, base: Base, logger?: (message: string) => void, @@ -325,12 +338,17 @@ export async function populateMeta( // await Model.insert(base.id, base.id, meta); /* create nc_models and its rows if it doesn't exists */ - models2[table.table_name] = await Model.insert(base.id, source.id, { - table_name: table.tn || table.table_name, - title: table.title, - type: table.type || 'table', - order: table.order, - }); + models2[table.table_name] = await Model.insert( + context, + base.id, + source.id, + { + table_name: table.tn || table.table_name, + title: table.title, + type: table.type || 'table', + order: table.order, + }, + ); // table crud apis info.apiCount += 5; @@ -346,7 +364,7 @@ export async function populateMeta( } } - await Column.insert({ + await Column.insert(context, { uidt: column.uidt || getColumnUiType(source, column), fk_model_id: models2[table.tn].id, ...column, @@ -370,20 +388,20 @@ export async function populateMeta( const rel = column.hm || column.bt; - const rel_column_id = (await models2?.[rel.tn]?.getColumns())?.find( - (c) => c.column_name === rel.cn, - )?.id; + const rel_column_id = ( + await models2?.[rel.tn]?.getColumns(context) + )?.find((c) => c.column_name === rel.cn)?.id; const tnId = models2?.[rel.tn]?.id; const ref_rel_column_id = ( - await models2?.[rel.rtn]?.getColumns() + await models2?.[rel.rtn]?.getColumns(context) )?.find((c) => c.column_name === rel.rcn)?.id; const rtnId = models2?.[rel.rtn]?.id; try { - await Column.insert({ + await Column.insert(context, { base_id: base.id, db_alias: source.id, fk_model_id: models2[table.tn].id, @@ -419,7 +437,7 @@ export async function populateMeta( /* handle xc_tables update in parallel */ await NcHelp.executeOperations(tableMetasInsert, source.type); await NcHelp.executeOperations(virtualColumnsInsert, source.type); - await extractAndGenerateManyToManyRelations(Object.values(models2)); + await extractAndGenerateManyToManyRelations(context, Object.values(models2)); let views: Array<{ order: number; table_name: string; title: string }> = ( await sqlClient.viewList({ @@ -456,13 +474,18 @@ export async function populateMeta( mapDefaultDisplayValue(columns); /* create nc_models and its rows if it doesn't exists */ - models2[table.table_name] = await Model.insert(base.id, source.id, { - table_name: table.table_name, - title: getTableNameAlias(table.table_name, base.prefix, source), - // todo: sanitize - type: ModelTypes.VIEW, - order: table.order, - }); + models2[table.table_name] = await Model.insert( + context, + base.id, + source.id, + { + table_name: table.table_name, + title: getTableNameAlias(table.table_name, base.prefix, source), + // todo: sanitize + type: ModelTypes.VIEW, + order: table.order, + }, + ); let colOrder = 1; @@ -470,7 +493,7 @@ export async function populateMeta( info.apiCount += 2; for (const column of columns) { - await Column.insert({ + await Column.insert(context, { fk_model_id: models2[table.table_name].id, ...column, title: getColumnNameAlias(column.cn, source), @@ -484,13 +507,16 @@ export async function populateMeta( await NcHelp.executeOperations(viewMetasInsert, source.type); // fix pv column for created grid views - const models = await Model.list({ base_id: base.id, source_id: source.id }); + const models = await Model.list(context, { + base_id: base.id, + source_id: source.id, + }); for (const model of models) { - const views = await model.getViews(); + const views = await model.getViews(context); for (const view of views) { if (view.type === ViewTypes.GRID) { - await View.fixPVColumnForView(view.id); + await View.fixPVColumnForView(context, view.id); } } } @@ -506,14 +532,15 @@ export async function populateMeta( } export async function populateRollupColumnAndHideLTAR( + context: NcContext, source: Source, base: Base, ) { - for (const model of await Model.list({ + for (const model of await Model.list(context, { base_id: base.id, source_id: source.id, })) { - const columns = await model.getColumns(); + const columns = await model.getColumns(context); const hmAndMmLTARColumns = columns.filter( (c) => c.uidt === UITypes.LinkToAnotherRecord && @@ -521,20 +548,21 @@ export async function populateRollupColumnAndHideLTAR( !c.system, ); - const views = await model.getViews(); + const views = await model.getViews(context); for (const column of hmAndMmLTARColumns) { const relatedModel = await column - .getColOptions() - .then((colOpt) => colOpt.getRelatedTable()); - await relatedModel.getColumns(); + .getColOptions(context) + .then((colOpt) => colOpt.getRelatedTable(context)); + await relatedModel.getColumns(context); const pkId = - relatedModel.primaryKey?.id || (await relatedModel.getColumns())[0]?.id; + relatedModel.primaryKey?.id || + (await relatedModel.getColumns(context))[0]?.id; - await Column.insert({ + await Column.insert(context, { uidt: UITypes.Links, title: getUniqueColumnAliasName( - await model.getColumns(), + await model.getColumns(context), `${relatedModel.title}`, ), fk_rollup_column_id: pkId, @@ -547,10 +575,10 @@ export async function populateRollupColumnAndHideLTAR( }, }); - const viewCol = await GridViewColumn.list(views[0].id).then((cols) => - cols.find((c) => c.fk_column_id === column.id), + const viewCol = await GridViewColumn.list(context, views[0].id).then( + (cols) => cols.find((c) => c.fk_column_id === column.id), ); - await GridViewColumn.update(viewCol.id, { show: false }); + await GridViewColumn.update(context, viewCol.id, { show: false }); } } } diff --git a/packages/nocodb/src/helpers/populateSamplePayload.ts b/packages/nocodb/src/helpers/populateSamplePayload.ts index b2875cbeee..16b1d29616 100644 --- a/packages/nocodb/src/helpers/populateSamplePayload.ts +++ b/packages/nocodb/src/helpers/populateSamplePayload.ts @@ -5,9 +5,11 @@ import type { LookupColumn, SelectOption, } from '~/models'; +import type { NcContext } from '~/interface/config'; import { Column, Model, View } from '~/models'; export async function populateSamplePayload( + context: NcContext, viewOrModel: View | Model, includeNested = false, operation = 'insert', @@ -16,14 +18,15 @@ export async function populateSamplePayload( let columns: Column[] = []; let model: Model; if (viewOrModel instanceof View) { - const viewColumns = await viewOrModel.getColumns(); + const viewColumns = await viewOrModel.getColumns(context); for (const col of viewColumns) { - if (col.show) columns.push(await Column.get({ colId: col.fk_column_id })); + if (col.show) + columns.push(await Column.get(context, { colId: col.fk_column_id })); } - model = await viewOrModel.getModel(); - await model.getColumns(); + model = await viewOrModel.getModel(context); + await model.getColumns(context); } else if (viewOrModel instanceof Model) { - columns = await viewOrModel.getColumns(); + columns = await viewOrModel.getColumns(context); model = viewOrModel; } @@ -37,13 +40,14 @@ export async function populateSamplePayload( if (operation === 'delete' && model.primaryKey?.title !== column.title) continue; - out[column.title] = await getSampleColumnValue(column); + out[column.title] = await getSampleColumnValue(context, column); } return out; } export async function populateSamplePayloadV2( + context: NcContext, viewOrModel: View | Model, includeNested = false, operation = 'insert', @@ -53,18 +57,19 @@ export async function populateSamplePayloadV2( let columns: Column[] = []; let model: Model; if (viewOrModel instanceof View) { - const viewColumns = await viewOrModel.getColumns(); + const viewColumns = await viewOrModel.getColumns(context); for (const col of viewColumns) { - if (col.show) columns.push(await Column.get({ colId: col.fk_column_id })); + if (col.show) + columns.push(await Column.get(context, { colId: col.fk_column_id })); } - model = await viewOrModel.getModel(); - await model.getColumns(); + model = await viewOrModel.getModel(context); + await model.getColumns(context); } else if (viewOrModel instanceof Model) { - columns = await viewOrModel.getColumns(); + columns = await viewOrModel.getColumns(context); model = viewOrModel; } - await model.getViews(); + await model.getViews(context); const samplePayload = { type: `${scope}.after.${operation}`, @@ -84,7 +89,7 @@ export async function populateSamplePayloadV2( ) continue; - rows[column.title] = await getSampleColumnValue(column); + rows[column.title] = await getSampleColumnValue(context, column); } let prevRows; @@ -105,7 +110,10 @@ export async function populateSamplePayloadV2( return samplePayload; } -async function getSampleColumnValue(column: Column): Promise { +async function getSampleColumnValue( + context: NcContext, + column: Column, +): Promise { switch (column.uidt) { case UITypes.ID: { @@ -114,9 +122,12 @@ async function getSampleColumnValue(column: Column): Promise { break; case UITypes.LinkToAnotherRecord: { - const colOpt = await column.getColOptions(); + const colOpt = await column.getColOptions( + context, + ); const sampleVal = await populateSamplePayload( - await colOpt.getRelatedTable(), + context, + await colOpt.getRelatedTable(context), ); if (colOpt.type !== RelationTypes.BELONGS_TO) { return undefined; @@ -133,12 +144,13 @@ async function getSampleColumnValue(column: Column): Promise { break; case UITypes.Lookup: { - const colOpt = await column.getColOptions(); + const colOpt = await column.getColOptions(context); const relColOpt = await colOpt - .getRelationColumn() - .then((r) => r.getColOptions()); + .getRelationColumn(context) + .then((r) => r.getColOptions(context)); const sampleVal = await getSampleColumnValue( - await colOpt.getLookupColumn(), + context, + await colOpt.getLookupColumn(context), ); return relColOpt.type === RelationTypes.BELONGS_TO ? sampleVal @@ -174,7 +186,7 @@ async function getSampleColumnValue(column: Column): Promise { break; case UITypes.MultiSelect: { - const colOpt = await column.getColOptions(); + const colOpt = await column.getColOptions(context); return ( colOpt?.[0]?.title || column?.dtxp?.split(',')?.[0]?.replace(/^['"]|['"]$/g, '') @@ -183,7 +195,7 @@ async function getSampleColumnValue(column: Column): Promise { break; case UITypes.SingleSelect: { - const colOpt = await column.getColOptions(); + const colOpt = await column.getColOptions(context); return ( colOpt?.[0]?.title || column?.dtxp?.split(',')?.[0]?.replace(/^['"]|['"]$/g, '') diff --git a/packages/nocodb/src/helpers/syncMigration.ts b/packages/nocodb/src/helpers/syncMigration.ts index 3d4331b3af..2d7d02e311 100644 --- a/packages/nocodb/src/helpers/syncMigration.ts +++ b/packages/nocodb/src/helpers/syncMigration.ts @@ -5,7 +5,10 @@ export default async function syncMigration(base: Base): Promise { for (const source of await base.getSources()) { try { /* create sql-migrator */ - const migrator = new KnexMigratorv2(base); + const migrator = new KnexMigratorv2( + { workspace_id: base.fk_workspace_id, base_id: base.id }, + base, + ); await migrator.init(source); @@ -26,7 +29,10 @@ export async function syncBaseMigration( ): Promise { try { /* create sql-migrator */ - const migrator = new KnexMigratorv2(base); + const migrator = new KnexMigratorv2( + { workspace_id: base.fk_workspace_id, base_id: base.id }, + base, + ); await migrator.init(source); diff --git a/packages/nocodb/src/helpers/webhookHelpers.ts b/packages/nocodb/src/helpers/webhookHelpers.ts index 47b5a37f85..f14c88cdec 100644 --- a/packages/nocodb/src/helpers/webhookHelpers.ts +++ b/packages/nocodb/src/helpers/webhookHelpers.ts @@ -11,6 +11,7 @@ import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'; import NcPluginMgrv2 from './NcPluginMgrv2'; import type { HookLogType } from 'nocodb-sdk'; import type { Column, FormView, Hook, Model, View } from '~/models'; +import type { NcContext } from '~/interface/config'; import { Filter, HookLog, Source } from '~/models'; dayjs.extend(isBetween); @@ -40,6 +41,7 @@ export function parseBody(template: string, data: any): string { } export async function validateCondition( + context: NcContext, filters: Filter[], data: any, { @@ -58,14 +60,15 @@ export async function validateCondition( let res; if (filter.is_group) { res = await validateCondition( - filter.children || (await filter.getChildren()), + context, + filter.children || (await filter.getChildren(context)), data, { client, }, ); } else { - const column = await filter.getColumn(); + const column = await filter.getColumn(context); const field = column.title; let val = data[field]; if ( @@ -457,17 +460,20 @@ export function axiosRequestMake(_apiMeta, _user, data) { return req; } -export async function invokeWebhook(param: { - hook: Hook; - model: Model; - view: View; - prevData; - newData; - user; - testFilters?; - throwErrorOnFailure?: boolean; - testHook?: boolean; -}) { +export async function invokeWebhook( + context: NcContext, + param: { + hook: Hook; + model: Model; + view: View; + prevData; + newData; + user; + testFilters?; + throwErrorOnFailure?: boolean; + testHook?: boolean; + }, +) { const { hook, model, @@ -483,7 +489,7 @@ export async function invokeWebhook(param: { let hookLog: HookLogType; const startTime = process.hrtime(); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); let notification; try { notification = @@ -499,7 +505,7 @@ export async function invokeWebhook(param: { } if (hook.condition && !testHook) { - const filters = testFilters || (await hook.getFilters()); + const filters = testFilters || (await hook.getFilters(context)); if (isBulkOperation) { const filteredData = []; @@ -521,7 +527,8 @@ export async function invokeWebhook(param: { if ( await validateCondition( - testFilters || (await hook.getFilters()), + context, + testFilters || (await hook.getFilters(context)), data, { client: source?.type }, ) @@ -539,13 +546,16 @@ export async function invokeWebhook(param: { if ( prevData && filters.length && - (await validateCondition(filters, prevData, { client: source?.type })) + (await validateCondition(context, filters, prevData, { + client: source?.type, + })) ) { return; } if ( !(await validateCondition( - testFilters || (await hook.getFilters()), + context, + testFilters || (await hook.getFilters(context)), newData, { client: source?.type }, )) @@ -678,7 +688,7 @@ export async function invokeWebhook(param: { hookLog.execution_time = parseHrtimeToMilliSeconds( process.hrtime(startTime), ); - HookLog.insert({ ...hookLog, test_call: testHook }); + HookLog.insert(context, { ...hookLog, test_call: testHook }); } } } diff --git a/packages/nocodb/src/interface/Jobs.ts b/packages/nocodb/src/interface/Jobs.ts index 4722e64a5d..893bcc56d3 100644 --- a/packages/nocodb/src/interface/Jobs.ts +++ b/packages/nocodb/src/interface/Jobs.ts @@ -1,3 +1,4 @@ +import type { NcContext } from '~/interface/config'; export const JOBS_QUEUE = 'jobs'; export enum JobTypes { @@ -44,6 +45,7 @@ export enum InstanceCommands { } export interface HandleWebhookJobData { + context: NcContext; hookId: string; modelId: string; viewId: string; diff --git a/packages/nocodb/src/interface/config.ts b/packages/nocodb/src/interface/config.ts index ea1b5b443f..e863b351c8 100644 --- a/packages/nocodb/src/interface/config.ts +++ b/packages/nocodb/src/interface/config.ts @@ -1,10 +1,7 @@ import type { UserType } from 'nocodb-sdk'; -import type { ReqId } from 'pino-http'; -import type { Handler } from 'express'; +import type { Handler, Request } from 'express'; import type * as e from 'express'; import type { Knex } from 'knex'; -import type { User } from '~/models'; -import type { IncomingHttpHeaders } from 'http'; export interface Route { path: string; @@ -324,12 +321,23 @@ export interface AppConfig { dashboardPath: string; } -export interface NcRequest { - id?: ReqId; - user?: UserType | User; +export interface NcContext { + org_id?: string; + workspace_id: string; + base_id: string; +} + +export interface NcRequest extends Partial { + context: NcContext; ncWorkspaceId?: string; ncBaseId?: string; - headers?: Record | IncomingHttpHeaders; + user: UserType & { + base_roles?: Record; + workspace_roles?: Record; + provider?: string; + }; + ncSiteUrl: string; + dashboardUrl: string; clientIp?: string; query?: Record; } diff --git a/packages/nocodb/src/meta/meta.service.ts b/packages/nocodb/src/meta/meta.service.ts index bdbb378173..7caba68460 100644 --- a/packages/nocodb/src/meta/meta.service.ts +++ b/packages/nocodb/src/meta/meta.service.ts @@ -11,7 +11,7 @@ import XcMigrationSource from '~/meta/migrations/XcMigrationSource'; import XcMigrationSourcev2 from '~/meta/migrations/XcMigrationSourcev2'; import { XKnex } from '~/db/CustomKnex'; import { NcConfig } from '~/utils/nc-config'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes, RootScopeTables } from '~/utils/globals'; import { NcError } from '~/helpers/catchError'; dayjs.extend(utc); dayjs.extend(timezone); @@ -53,65 +53,53 @@ export class MetaService { return this.knexConnection; } + public contextCondition( + query: Knex.QueryBuilder, + workspace_id: string, + base_id: string, + target: string, + ) { + if (workspace_id === base_id) { + return; + } + + if (target !== MetaTable.PROJECT) { + query.where('base_id', base_id); + } else { + query.where('id', base_id); + } + } + /*** * Get single record from meta data - * @param base_id - Base id - * @param dbAlias - Database alias + * @param workspace_id - Workspace id + * @param base_id - Base alias * @param target - Table name * @param idOrCondition - If string, will get the record with the given id. If object, will get the record with the given condition. * @param fields - Fields to be selected */ public async metaGet( + workspace_id: string, base_id: string, - dbAlias: string, target: string, idOrCondition: string | { [p: string]: any }, fields?: string[], // xcCondition? ): Promise { - const query = this.connection(target); - - // if (xcCondition) { - // query.condition(xcCondition); - // } - - if (fields?.length) { - query.select(...fields); - } - - if (base_id !== null && base_id !== undefined) { - query.where('base_id', base_id); - } - if (dbAlias !== null && dbAlias !== undefined) { - query.where('db_alias', dbAlias); - } - - if (!idOrCondition) { - return query.first(); - } - - if (typeof idOrCondition !== 'object') { - query.where('id', idOrCondition); - } else { - query.where(idOrCondition); - } - - // console.log(query.toQuery()) - - return query.first(); + return this.metaGet2(workspace_id, base_id, target, idOrCondition, fields); } /*** * Insert record into meta data - * @param base_id - Base id + * @param fk_workspace_id - Base id * @param dbAlias - Database alias * @param target - Table name * @param data - Data to be inserted * @param ignoreIdGeneration - If true, will not generate id for the record */ public async metaInsert2( + workspace_id: string, base_id: string, - source_id: string, target: string, data: any, ignoreIdGeneration?: boolean, @@ -122,8 +110,31 @@ export class MetaService { ? {} : { id: data?.id || (await this.genNanoid(target)) }), }; - if (source_id !== null) insertObj.source_id = source_id; - if (base_id !== null) insertObj.base_id = base_id; + + if (workspace_id === base_id) { + if (!Object.values(RootScopes).includes(workspace_id as RootScopes)) { + NcError.metaError({ + message: 'Invalid scope', + sql: '', + }); + } + + if (!RootScopeTables[workspace_id].includes(target)) { + NcError.metaError({ + message: 'Table not accessible from this scope', + sql: '', + }); + } + } else { + if (!base_id) { + NcError.metaError({ + message: 'Base ID is required', + sql: '', + }); + } + + insertObj.base_id = base_id; + } await this.knexConnection(target).insert({ ...insertObj, @@ -135,15 +146,15 @@ export class MetaService { /*** * Insert multiple records into meta data - * @param base_id - Base id - * @param source_id - Source id + * @param workspace_id - Workspace id + * @param base_id - Source id * @param target - Table name * @param data - Data to be inserted * @param ignoreIdGeneration - If true, will not generate id for the record */ public async bulkMetaInsert( + workspace_id: string, base_id: string, - source_id: string, target: string, data: any | any[], ignoreIdGeneration?: boolean, @@ -160,8 +171,29 @@ export class MetaService { updated_at: at, }; - if (source_id !== null) commonProps.source_id = source_id; - if (base_id !== null) commonProps.base_id = base_id; + if (workspace_id === base_id) { + if (!Object.values(RootScopes).includes(workspace_id as RootScopes)) { + NcError.metaError({ + message: 'Invalid scope', + sql: '', + }); + } + + if (!RootScopeTables[workspace_id].includes(target)) { + NcError.metaError({ + message: 'Table not accessible from this scope', + sql: '', + }); + } + } else { + if (!base_id) { + NcError.metaError({ + message: 'Base ID is required', + sql: '', + }); + } + commonProps.base_id = base_id; + } for (const d of Array.isArray(data) ? data : [data]) { const id = d?.id || (await this.genNanoid(target)); @@ -226,71 +258,6 @@ export class MetaService { // using nanoid to avoid collision with existing ids when duplicating return `${prefix}${nanoidv2()}`; } - /*** - * Get paginated list of meta data - * @param baseId - Base id - * @param dbAlias - Database alias - * @param target - Table name - * @param args.condition - Condition to be applied - * @param args.limit - Limit of records - * @param args.offset - Offset of records - * @param args.xcCondition - Additional nested or complex condition to be added to the query. - * @param args.fields - Fields to be selected - * @param args.sort - Sort field and direction - * @returns {Promise<{list: any[]; count: number}>} - List of records and count - * */ - public async metaPaginatedList( - baseId: string, - dbAlias: string, - target: string, - args?: { - condition?: { [key: string]: any }; - limit?: number; - offset?: number; - xcCondition?: Condition; - fields?: string[]; - sort?: { field: string; desc?: boolean }; - }, - ): Promise<{ list: any[]; count: number }> { - const query = this.knexConnection(target); - const countQuery = this.knexConnection(target); - if (baseId !== null && baseId !== undefined) { - query.where('base_id', baseId); - countQuery.where('base_id', baseId); - } - if (dbAlias !== null && dbAlias !== undefined) { - query.where('db_alias', dbAlias); - countQuery.where('db_alias', dbAlias); - } - - if (args?.condition) { - query.where(args.condition); - countQuery.where(args.condition); - } - if (args?.limit) { - query.limit(args.limit); - } - if (args?.sort) { - query.orderBy(args.sort.field, args.sort.desc ? 'desc' : 'asc'); - } - if (args?.offset) { - query.offset(args.offset); - } - if (args?.xcCondition) { - (query as any) - .condition(args.xcCondition)(countQuery as any) - .condition(args.xcCondition); - } - - if (args?.fields?.length) { - query.select(...args.fields); - } - - return { - list: await query, - count: Object.values(await countQuery.count().first())?.[0] as any, - }; - } // private connection: XKnex; // todo: need to fix @@ -298,16 +265,16 @@ export class MetaService { /*** * Delete meta data + * @param workspace_id - Workspace id * @param base_id - Base id - * @param dbAlias - Database alias * @param target - Table name * @param idOrCondition - If string, will delete the record with the given id. If object, will delete the record with the given condition. * @param xcCondition - Additional nested or complex condition to be added to the query. * @param force - If true, will not check if a condition is present in the query builder and will execute the query as is. */ public async metaDelete( + workspace_id: string, base_id: string, - dbAlias: string, target: string, idOrCondition: string | { [p: string]: any }, xcCondition?: Condition, @@ -315,11 +282,27 @@ export class MetaService { ): Promise { const query = this.knexConnection(target); - if (base_id !== null && base_id !== undefined) { - query.where('base_id', base_id); - } - if (dbAlias !== null && dbAlias !== undefined) { - query.where('db_alias', dbAlias); + if (workspace_id === base_id) { + if (!Object.values(RootScopes).includes(workspace_id as RootScopes)) { + NcError.metaError({ + message: 'Invalid scope', + sql: '', + }); + } + + if (!RootScopeTables[workspace_id].includes(target)) { + NcError.metaError({ + message: 'Table not accessible from this scope', + sql: '', + }); + } + } else { + if (!base_id) { + NcError.metaError({ + message: 'Base ID is required', + sql: '', + }); + } } if (typeof idOrCondition !== 'object') { @@ -337,21 +320,53 @@ export class MetaService { this.checkConditionPresent(query, 'delete'); } + // Apply context condition + this.contextCondition(query, workspace_id, base_id, target); + + return query.del(); + } + + /*** + * Delete meta data with condition (USE WITH CAUTION) + * @param target - Table name + * @param idOrCondition - If string, will delete the record with the given id. If object, will delete the record with the given condition. + * @param xcCondition - Additional nested or complex condition to be added to the query. + */ + public async metaDeleteAll( + target: string, + idOrCondition: string | { [p: string]: any }, + xcCondition?: Condition, + ): Promise { + const query = this.knexConnection(target); + + if (typeof idOrCondition !== 'object') { + query.where('id', idOrCondition); + } else if (idOrCondition) { + query.where(idOrCondition); + } + + if (xcCondition) { + query.condition(xcCondition, {}); + } + + // Check if a condition is present in the query builder and throw an error if not. + this.checkConditionPresent(query, 'delete'); + return query.del(); } /*** * Get meta data + * @param workspace_id - Workspace id * @param base_id - Base id - * @param sourceId - Source id * @param target - Table name * @param idOrCondition - If string, will get the record with the given id. If object, will get the record with the given condition. * @param fields - Fields to be selected * @param xcCondition - Additional nested or complex condition to be added to the query. */ public async metaGet2( + workspace_id: string, base_id: string, - sourceId: string, target: string, idOrCondition: string | { [p: string]: any }, fields?: string[], @@ -367,11 +382,31 @@ export class MetaService { query.select(...fields); } - if (base_id !== null && base_id !== undefined) { - query.where('base_id', base_id); - } - if (sourceId !== null && sourceId !== undefined) { - query.where('source_id', sourceId); + if (workspace_id === RootScopes.BYPASS && base_id === RootScopes.BYPASS) { + // bypass + } else if (workspace_id === base_id) { + if (!Object.values(RootScopes).includes(workspace_id as RootScopes)) { + NcError.metaError({ + message: 'Invalid scope', + sql: '', + }); + } + + if (!RootScopeTables[workspace_id].includes(target)) { + NcError.metaError({ + message: 'Table not accessible from this scope', + sql: '', + }); + } + } else { + if (!base_id) { + NcError.metaError({ + message: 'Base ID is required', + sql: '', + }); + } + + this.contextCondition(query, workspace_id, base_id, target); } if (!idOrCondition) { @@ -404,72 +439,10 @@ export class MetaService { return (+(await query.first())?.order || 0) + 1; } - public async metaInsert( - base_id: string, - dbAlias: string, - target: string, - data: any, - ): Promise { - return this.knexConnection(target).insert({ - db_alias: dbAlias, - base_id, - ...data, - created_at: this.now(), - updated_at: this.now(), - }); - } - - public async metaList( - base_id: string, - _dbAlias: string, - target: string, - args?: { - condition?: { [p: string]: any }; - limit?: number; - offset?: number; - xcCondition?: Condition; - fields?: string[]; - orderBy?: { [key: string]: 'asc' | 'desc' }; - }, - ): Promise { - const query = this.knexConnection(target); - - if (base_id !== null && base_id !== undefined) { - query.where('base_id', base_id); - } - /* if (dbAlias !== null && dbAlias !== undefined) { - query.where('db_alias', dbAlias); - }*/ - - if (args?.condition) { - query.where(args.condition); - } - if (args?.limit) { - query.limit(args.limit); - } - if (args?.offset) { - query.offset(args.offset); - } - if (args?.xcCondition) { - (query as any).condition(args.xcCondition); - } - - if (args?.orderBy) { - for (const [col, dir] of Object.entries(args.orderBy)) { - query.orderBy(col, dir); - } - } - if (args?.fields?.length) { - query.select(...args.fields); - } - - return query; - } - /*** * Get list of meta data + * @param workspace_id - Workspace id * @param base_id - Base id - * @param dbAlias - Database alias * @param target - Table name * @param args.condition - Condition to be applied * @param args.limit - Limit of records @@ -480,8 +453,8 @@ export class MetaService { * @returns {Promise} - List of records * */ public async metaList2( + workspace_id: string, base_id: string, - dbAlias: string, target: string, args?: { condition?: { [p: string]: any }; @@ -494,11 +467,29 @@ export class MetaService { ): Promise { const query = this.knexConnection(target); - if (base_id !== null && base_id !== undefined) { - query.where('base_id', base_id); - } - if (dbAlias !== null && dbAlias !== undefined) { - query.where('source_id', dbAlias); + if (workspace_id === base_id) { + if (!Object.values(RootScopes).includes(workspace_id as RootScopes)) { + NcError.metaError({ + message: 'Invalid scope', + sql: '', + }); + } + + if (!RootScopeTables[workspace_id].includes(target)) { + NcError.metaError({ + message: 'Table not accessible from this scope', + sql: '', + }); + } + } else { + if (!base_id) { + NcError.metaError({ + message: 'Base ID is required', + sql: '', + }); + } + + this.contextCondition(query, workspace_id, base_id, target); } if (args?.condition) { @@ -528,8 +519,8 @@ export class MetaService { /*** * Get count of meta data + * @param workspace_id - Workspace id * @param base_id - Base id - * @param dbAlias - Database alias * @param target - Table name * @param args.condition - Condition to be applied * @param args.xcCondition - Additional nested or complex condition to be added to the query. @@ -537,8 +528,8 @@ export class MetaService { * @returns {Promise} - Count of records * */ public async metaCount( + workspace_id: string, base_id: string, - dbAlias: string, target: string, args?: { condition?: { [p: string]: any }; @@ -548,11 +539,31 @@ export class MetaService { ): Promise { const query = this.knexConnection(target); - if (base_id !== null && base_id !== undefined) { - query.where('base_id', base_id); - } - if (dbAlias !== null && dbAlias !== undefined) { - query.where('source_id', dbAlias); + if (workspace_id === RootScopes.BYPASS && base_id === RootScopes.BYPASS) { + // bypass + } else if (workspace_id === base_id) { + if (!Object.values(RootScopes).includes(workspace_id as RootScopes)) { + NcError.metaError({ + message: 'Invalid scope', + sql: '', + }); + } + + if (!RootScopeTables[workspace_id].includes(target)) { + NcError.metaError({ + message: 'Table not accessible from this scope', + sql: '', + }); + } + } else { + if (!base_id) { + NcError.metaError({ + message: 'Base ID is required', + sql: '', + }); + } + + this.contextCondition(query, workspace_id, base_id, target); } if (args?.condition) { @@ -570,8 +581,8 @@ export class MetaService { /*** * Update meta data + * @param workspace_id - Workspace id * @param base_id - Base id - * @param dbAlias - Database alias * @param target - Table name * @param data - Data to be updated * @param idOrCondition - If string, will update the record with the given id. If object, will update the record with the given condition. @@ -579,8 +590,8 @@ export class MetaService { * @param force - If true, will not check if a condition is present in the query builder and will execute the query as is. */ public async metaUpdate( + workspace_id: string, base_id: string, - dbAlias: string, target: string, data: any, idOrCondition?: string | { [p: string]: any }, @@ -588,11 +599,28 @@ export class MetaService { force = false, ): Promise { const query = this.knexConnection(target); - if (base_id !== null && base_id !== undefined) { - query.where('base_id', base_id); - } - if (dbAlias !== null && dbAlias !== undefined) { - query.where('db_alias', dbAlias); + + if (workspace_id === base_id) { + if (!Object.values(RootScopes).includes(workspace_id as RootScopes)) { + NcError.metaError({ + message: 'Invalid scope', + sql: '', + }); + } + + if (!RootScopeTables[workspace_id].includes(target)) { + NcError.metaError({ + message: 'Table not accessible from this scope', + sql: '', + }); + } + } else { + if (!base_id) { + NcError.metaError({ + message: 'Base ID is required', + sql: '', + }); + } } delete data.created_at; @@ -612,6 +640,9 @@ export class MetaService { this.checkConditionPresent(query, 'update'); } + // Apply context condition + this.contextCondition(query, workspace_id, base_id, target); + return await query; } @@ -696,10 +727,18 @@ export class MetaService { ); } + private isMssql(): boolean { + return this.connection.clientType() === 'mssql'; + } + public now(): any { return dayjs() .utc() - .format(this.isMySQL() ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD HH:mm:ssZ'); + .format( + this.isMySQL() || this.isMssql() + ? 'YYYY-MM-DD HH:mm:ss' + : 'YYYY-MM-DD HH:mm:ssZ', + ); } public async init(): Promise { @@ -719,7 +758,7 @@ export class MetaService { * * @param queryBuilder - The Knex QueryBuilder instance to check. */ - private checkConditionPresent( + protected checkConditionPresent( queryBuilder: Knex.QueryBuilder, operation: 'delete' | 'update', ) { diff --git a/packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts b/packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts index 75f1accbdd..8dd0fb24f9 100644 --- a/packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts +++ b/packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts @@ -36,6 +36,7 @@ import * as nc_046_comment_mentions from '~/meta/migrations/v2/nc_046_comment_me import * as nc_047_comment_migration from '~/meta/migrations/v2/nc_047_comment_migration'; import * as nc_048_view_links from '~/meta/migrations/v2/nc_048_view_links'; import * as nc_049_clear_notifications from '~/meta/migrations/v2/nc_049_clear_notifications'; +import * as nc_050_tenant_isolation from '~/meta/migrations/v2/nc_050_tenant_isolation'; // Create a custom migration source class export default class XcMigrationSourcev2 { @@ -83,6 +84,7 @@ export default class XcMigrationSourcev2 { 'nc_047_comment_migration', 'nc_048_view_links', 'nc_049_clear_notifications', + 'nc_050_tenant_isolation', ]); } @@ -168,6 +170,8 @@ export default class XcMigrationSourcev2 { return nc_048_view_links; case 'nc_049_clear_notifications': return nc_049_clear_notifications; + case 'nc_050_tenant_isolation': + return nc_050_tenant_isolation; } } } diff --git a/packages/nocodb/src/meta/migrations/v2/nc_050_tenant_isolation.ts b/packages/nocodb/src/meta/migrations/v2/nc_050_tenant_isolation.ts new file mode 100644 index 0000000000..270bfe174e --- /dev/null +++ b/packages/nocodb/src/meta/migrations/v2/nc_050_tenant_isolation.ts @@ -0,0 +1,409 @@ +import type { Knex } from 'knex'; +import { MetaTable } from '~/utils/globals'; + +/* + Add base_id to: + nc_calendar_view_range_v2: MetaTable.CALENDAR_VIEW_RANGE + nc_col_barcode_v2: MetaTable.COL_BARCODE + nc_col_formula_v2: MetaTable.COL_FORMULA + nc_col_lookup_v2: MetaTable.COL_LOOKUP + nc_col_qrcode_v2: MetaTable.COL_QRCODE + nc_col_relations_v2: MetaTable.COL_RELATIONS + nc_col_rollup_v2: MetaTable.COL_ROLLUP + nc_col_select_options_v2: MetaTable.COL_SELECT_OPTIONS +*/ + +const log = (message: string) => { + console.log(`nc_050_tenant_isolation: ${message}`); +}; + +let hrTime = process.hrtime(); + +const logExecutionTime = (message: string) => { + const [seconds, nanoseconds] = process.hrtime(hrTime); + const elapsedSeconds = seconds + nanoseconds / 1e9; + log(`${message} in ${elapsedSeconds}s`); +}; + +const migrateDataWithJoin = async ( + knex: Knex, + table: string, + column: string, + joinTable: string, + joinColumn: string, + destinationColumn: string, + sourceColumn: string, +) => { + const sourceType = knex.client.driverName; + + switch (sourceType) { + case 'pg': + await knex.raw(` + UPDATE ${table} + SET ${destinationColumn} = ${joinTable}.${sourceColumn} + FROM ${joinTable} + WHERE ${table}.${column} = ${joinTable}.${joinColumn} + `); + break; + case 'mysql': + case 'mysql2': + await knex.raw(` + UPDATE ${table} + JOIN ${joinTable} + ON ${table}.${column} = ${joinTable}.${joinColumn} + SET ${table}.${destinationColumn} = ${joinTable}.${sourceColumn} + `); + break; + case 'sqlite3': + await knex.raw(` + UPDATE ${table} + SET ${destinationColumn} = ( + SELECT ${joinTable}.${sourceColumn} + FROM ${joinTable} + WHERE ${table}.${column} = ${joinTable}.${joinColumn} + ) + `); + break; + case 'mssql': + await knex.raw(` + UPDATE ${table} + SET ${destinationColumn} = ${joinTable}.${sourceColumn} + FROM ${table} + JOIN ${joinTable} + ON ${table}.${column} = ${joinTable}.${joinColumn} + `); + break; + default: + throw new Error(`Unsupported database: ${sourceType}`); + } +}; + +const listIndexesOnColumn = async ( + knex: Knex, + table: string, + column: string, +) => { + const sourceType = knex.client.driverName; + + switch (sourceType) { + case 'pg': { + const indexes = await knex.raw( + ` + SELECT + t.relname AS table_name, + i.relname AS index_name, + a.attname AS column_name + FROM + pg_class t, + pg_class i, + pg_index ix, + pg_attribute a + WHERE + t.oid = ix.indrelid + AND i.oid = ix.indexrelid + AND a.attrelid = t.oid + AND a.attnum = ANY(ix.indkey) + AND t.relkind = 'r' + AND t.relname = ? + AND a.attname = ?; + `, + [table, column], + ); + + return indexes.rows.map((row: any) => row.index_name); + } + case 'mysql': + case 'mysql2': { + const indexes = await knex.raw( + ` + SELECT + INDEX_NAME + FROM + INFORMATION_SCHEMA.STATISTICS + WHERE + TABLE_SCHEMA = ? + AND TABLE_NAME = ? + AND COLUMN_NAME = ? + `, + [knex.client.database(), table, column], + ); + + return indexes[0].map((row: any) => row.INDEX_NAME); + } + case 'sqlite3': { + const indexes = await knex.raw( + ` + PRAGMA index_list(??) + `, + [table], + ); + + return indexes + .map((row: any) => row.name) + .filter( + (name: string) => + name.includes(column) || + (column === 'base_id' && name.includes('project_id')), + ); + } + case 'mssql': { + const indexes = await knex.raw( + ` + SELECT + i.name AS index_name + FROM + sys.indexes i + JOIN + sys.index_columns ic + ON + i.object_id = ic.object_id + AND i.index_id = ic.index_id + JOIN + sys.columns c + ON + ic.object_id = c.object_id + AND ic.column_id = c.column_id + WHERE + i.object_id = OBJECT_ID(?) + AND c.name = ? + `, + [table, column], + ); + + return indexes.map((row: any) => row.index_name); + } + + default: + throw new Error(`Unsupported database: ${sourceType}`); + } +}; + +const up = async (knex: Knex) => { + log('Migration started'); + + log('Adding missing base_id columns'); + + const addBaseId = [ + MetaTable.CALENDAR_VIEW_RANGE, + MetaTable.COL_BARCODE, + MetaTable.COL_FORMULA, + MetaTable.COL_LOOKUP, + MetaTable.COL_QRCODE, + MetaTable.COL_RELATIONS, + MetaTable.COL_ROLLUP, + MetaTable.COL_SELECT_OPTIONS, + ]; + + hrTime = process.hrtime(); + + for (const table of addBaseId) { + if (!(await knex.schema.hasColumn(table, 'base_id'))) { + await knex.schema.alterTable(table, (table) => { + table.string('base_id', 20); + }); + } + } + + logExecutionTime('Added missing base_id columns'); + + // Migrate data + + log('Migrating data'); + + /* + nc_calendar_view_range_v2 only fk_view_id is available - join with nc_views_v2 on id to get base_id + nc_col_barcode_v2 only fk_column_id is available - join with nc_columns_v2 on id to get base_id + nc_col_formula_v2 only fk_column_id is available - join with nc_columns_v2 on id to get base_id + nc_col_lookup_v2 only fk_column_id is available - join with nc_columns_v2 on id to get base_id + nc_col_qrcode_v2 only fk_column_id is available - join with nc_columns_v2 on id to get base_id + nc_col_relations_v2 only fk_column_id is available - join with nc_columns_v2 on id to get base_id + nc_col_rollup_v2 only fk_column_id is available - join with nc_columns_v2 on id to get base_id + nc_col_select_options_v2 only fk_column_id is available - join with nc_columns_v2 on id to get base_id + */ + + // Migrate base_id + + const migrateBaseId = [ + MetaTable.CALENDAR_VIEW_RANGE, + MetaTable.COL_BARCODE, + MetaTable.COL_FORMULA, + MetaTable.COL_LOOKUP, + MetaTable.COL_QRCODE, + MetaTable.COL_RELATIONS, + MetaTable.COL_ROLLUP, + MetaTable.COL_SELECT_OPTIONS, + ]; + + for (const table of migrateBaseId) { + hrTime = process.hrtime(); + + if (table === MetaTable.CALENDAR_VIEW_RANGE) { + await migrateDataWithJoin( + knex, + MetaTable.CALENDAR_VIEW_RANGE, + 'fk_view_id', + MetaTable.VIEWS, + 'id', + 'base_id', + 'base_id', + ); + } else { + await migrateDataWithJoin( + knex, + table, + 'fk_column_id', + MetaTable.COLUMNS, + 'id', + 'base_id', + 'base_id', + ); + } + + logExecutionTime(`Migrated base_id for ${table}`); + } + + // Drop existing base_id indexes + const dropBaseIdIndexes = [ + MetaTable.AUDIT, + MetaTable.BASES, + MetaTable.MODELS, + MetaTable.PROJECT_USERS, + MetaTable.SYNC_SOURCE, + MetaTable.EXTENSIONS, + ]; + + log('Dropping existing base_id indexes'); + + hrTime = process.hrtime(); + + for (const table of dropBaseIdIndexes) { + const indexes: string[] = await listIndexesOnColumn(knex, table, 'base_id'); + + for (const index of indexes) { + log(`Dropping index ${index} on ${table}.base_id`); + + await knex.schema.alterTable(table, (table) => { + table.dropIndex('base_id', index); + }); + } + } + + logExecutionTime('Dropped existing base_id indexes'); + + // Recreate existing source_id indexes as name might clash with base_id (old name for source_id) + const recreateSourceIdIndexes = [MetaTable.MODELS, MetaTable.SYNC_SOURCE]; + + log('Recreating existing source_id indexes'); + + hrTime = process.hrtime(); + + for (const tbl of recreateSourceIdIndexes) { + const indexes: string[] = await listIndexesOnColumn(knex, tbl, 'source_id'); + + // remove duplicate indexes + const uniqueIndexes = Array.from(new Set(indexes)); + + for (const index of uniqueIndexes) { + // Recreate only if index name will clash with base_id + if (index !== `${tbl}_base_id_index`) { + continue; + } + + log(`Recreating index ${index} on ${tbl}.source_id`); + + await knex.schema.alterTable(tbl, (table) => { + table.dropIndex('source_id', `${tbl}_base_id_index`); + table.index('source_id'); + }); + } + } + + logExecutionTime('Recreated existing source_id indexes'); + + // Add indexes + + const addIndexes = [ + // MetaTable.API_TOKENS, + MetaTable.AUDIT, + MetaTable.PROJECT_USERS, + MetaTable.CALENDAR_VIEW_COLUMNS, + MetaTable.CALENDAR_VIEW, + MetaTable.COLUMNS, + MetaTable.EXTENSIONS, + MetaTable.FILTER_EXP, + MetaTable.FORM_VIEW_COLUMNS, + MetaTable.FORM_VIEW, + MetaTable.GALLERY_VIEW_COLUMNS, + MetaTable.GALLERY_VIEW, + MetaTable.GRID_VIEW_COLUMNS, + MetaTable.GRID_VIEW, + MetaTable.HOOK_LOGS, + MetaTable.HOOKS, + MetaTable.KANBAN_VIEW_COLUMNS, + MetaTable.KANBAN_VIEW, + MetaTable.MAP_VIEW_COLUMNS, + MetaTable.MAP_VIEW, + MetaTable.MODELS, + MetaTable.SORT, + MetaTable.BASES, + MetaTable.SYNC_LOGS, + MetaTable.SYNC_SOURCE, + MetaTable.VIEWS, + MetaTable.MODEL_ROLE_VISIBILITY, + MetaTable.COMMENTS, + MetaTable.COMMENTS_REACTIONS, + MetaTable.USER_COMMENTS_NOTIFICATIONS_PREFERENCE, + MetaTable.CALENDAR_VIEW_RANGE, + MetaTable.COL_BARCODE, + MetaTable.COL_FORMULA, + MetaTable.COL_LOOKUP, + MetaTable.COL_QRCODE, + MetaTable.COL_RELATIONS, + MetaTable.COL_ROLLUP, + MetaTable.COL_SELECT_OPTIONS, + ]; + + log('Adding indexes'); + + for (const tbl of addIndexes) { + hrTime = process.hrtime(); + + await knex.schema.alterTable(tbl, (table) => { + table.index('base_id'); + }); + + logExecutionTime(`Added indexes for ${tbl}`); + } + + log('Migration completed'); +}; + +const down = async (knex: Knex) => { + // Drop base_id + await knex.schema.alterTable(MetaTable.CALENDAR_VIEW_RANGE, (table) => { + table.dropColumn('base_id'); + }); + await knex.schema.alterTable(MetaTable.COL_BARCODE, (table) => { + table.dropColumn('base_id'); + }); + await knex.schema.alterTable(MetaTable.COL_FORMULA, (table) => { + table.dropColumn('base_id'); + }); + await knex.schema.alterTable(MetaTable.COL_LOOKUP, (table) => { + table.dropColumn('base_id'); + }); + await knex.schema.alterTable(MetaTable.COL_QRCODE, (table) => { + table.dropColumn('base_id'); + }); + await knex.schema.alterTable(MetaTable.COL_RELATIONS, (table) => { + table.dropColumn('base_id'); + }); + await knex.schema.alterTable(MetaTable.COL_ROLLUP, (table) => { + table.dropColumn('base_id'); + }); + await knex.schema.alterTable(MetaTable.COL_SELECT_OPTIONS, (table) => { + table.dropColumn('base_id'); + }); +}; + +export { up, down }; 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 a9246d893d..80a50fd08b 100644 --- a/packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts +++ b/packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts @@ -27,6 +27,7 @@ import { } from '~/models'; import rolePermissions from '~/utils/acl'; import { NcError } from '~/helpers/catchError'; +import { RootScopes } from '~/utils/globals'; export const rolesLabel = { [OrgUserRoles.SUPER_ADMIN]: 'Super Admin', @@ -59,12 +60,16 @@ export class ExtractIdsMiddleware implements NestMiddleware, CanActivate { async use(req, res, next): Promise { const { params } = req; + const context = { + workspace_id: RootScopes.BYPASS, + base_id: RootScopes.BYPASS, + }; + // extract base id based on request path params if (params.baseName) { - const base = await Base.getByTitleOrId(params.baseName); + const base = await Base.getByTitleOrId(context, params.baseName); if (base) { req.ncBaseId = base.id; - res.locals.base = base; } } if (params.baseId) { @@ -72,13 +77,24 @@ export class ExtractIdsMiddleware implements NestMiddleware, CanActivate { } else if (params.dashboardId) { req.ncBaseId = params.dashboardId; } else if (params.tableId || params.modelId) { - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: params.tableId || params.modelId, }); + + if (!model) { + NcError.tableNotFound(params.tableId || params.modelId); + } + req.ncBaseId = model?.base_id; } else if (params.viewId) { const view = - (await View.get(params.viewId)) || (await Model.get(params.viewId)); + (await View.get(context, params.viewId)) || + (await Model.get(context, params.viewId)); + + if (!view) { + NcError.viewNotFound(params.viewId); + } + req.ncBaseId = view?.base_id; } else if ( params.formViewId || @@ -88,47 +104,137 @@ export class ExtractIdsMiddleware implements NestMiddleware, CanActivate { params.calendarViewId ) { const view = await View.get( + context, params.formViewId || params.gridViewId || params.kanbanViewId || params.galleryViewId || params.calendarViewId, ); + + if (!view) { + NcError.viewNotFound( + params.formViewId || + params.gridViewId || + params.kanbanViewId || + params.galleryViewId || + params.calendarViewId, + ); + } + req.ncBaseId = view?.base_id; } else if (params.publicDataUuid) { - const view = await View.getByUUID(req.params.publicDataUuid); + const view = await View.getByUUID(context, req.params.publicDataUuid); + + if (!view) { + NcError.viewNotFound(params.publicDataUuid); + } + + req.ncBaseId = view?.base_id; + } else if (params.sharedViewUuid) { + const view = await View.getByUUID(context, req.params.sharedViewUuid); + + if (!view) { + NcError.viewNotFound(req.params.sharedViewUuid); + } + req.ncBaseId = view?.base_id; + } else if (params.sharedBaseUuid) { + const base = await Base.getByUuid(context, req.params.sharedBaseUuid); + + if (!base) { + NcError.baseNotFound(req.params.sharedBaseUuid); + } + + req.ncBaseId = base?.id; } else if (params.hookId) { - const hook = await Hook.get(params.hookId); + const hook = await Hook.get(context, params.hookId); + + if (!hook) { + NcError.genericNotFound('Webhook', params.hookId); + } + req.ncBaseId = hook?.base_id; } else if (params.gridViewColumnId) { - const gridViewColumn = await GridViewColumn.get(params.gridViewColumnId); + const gridViewColumn = await GridViewColumn.get( + context, + params.gridViewColumnId, + ); + + if (!gridViewColumn) { + NcError.fieldNotFound(params.gridViewColumnId); + } + req.ncBaseId = gridViewColumn?.base_id; } else if (params.formViewColumnId) { - const formViewColumn = await FormViewColumn.get(params.formViewColumnId); + const formViewColumn = await FormViewColumn.get( + context, + params.formViewColumnId, + ); + + if (!formViewColumn) { + NcError.fieldNotFound(params.formViewColumnId); + } + req.ncBaseId = formViewColumn?.base_id; } else if (params.galleryViewColumnId) { const galleryViewColumn = await GalleryViewColumn.get( + context, params.galleryViewColumnId, ); + + if (!galleryViewColumn) { + NcError.fieldNotFound(params.galleryViewColumnId); + } + req.ncBaseId = galleryViewColumn?.base_id; } else if (params.columnId) { - const column = await Column.get({ colId: params.columnId }); + const column = await Column.get(context, { colId: params.columnId }); + + if (!column) { + NcError.fieldNotFound(params.columnId); + } + req.ncBaseId = column?.base_id; } else if (params.filterId) { - const filter = await Filter.get(params.filterId); + const filter = await Filter.get(context, params.filterId); + + if (!filter) { + NcError.genericNotFound('Filter', params.filterId); + } + req.ncBaseId = filter?.base_id; } else if (params.filterParentId) { - const filter = await Filter.get(params.filterParentId); + const filter = await Filter.get(context, params.filterParentId); + + if (!filter) { + NcError.genericNotFound('Filter', params.filterParentId); + } + req.ncBaseId = filter?.base_id; } else if (params.sortId) { - const sort = await Sort.get(params.sortId); + const sort = await Sort.get(context, params.sortId); + + if (!sort) { + NcError.genericNotFound('Sort', params.sortId); + } + req.ncBaseId = sort?.base_id; } else if (params.syncId) { - const syncSource = await SyncSource.get(req.params.syncId); + const syncSource = await SyncSource.get(context, req.params.syncId); + + if (!syncSource) { + NcError.genericNotFound('Sync Source', params.syncId); + } + req.ncBaseId = syncSource.base_id; } else if (params.extensionId) { - const extension = await Extension.get(req.params.extensionId); + const extension = await Extension.get(context, req.params.extensionId); + + if (!extension) { + NcError.genericNotFound('Extension', params.extensionId); + } + req.ncBaseId = extension.base_id; } // extract fk_model_id from query params only if it's audit post endpoint @@ -144,9 +250,14 @@ export class ExtractIdsMiddleware implements NestMiddleware, CanActivate { req.method === 'POST' && req.body?.fk_model_id ) { - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: req.body.fk_model_id, }); + + if (!model) { + NcError.tableNotFound(req.body.fk_model_id); + } + req.ncBaseId = model?.base_id; } // extract fk_model_id from query params only if it's audit get endpoint @@ -162,9 +273,14 @@ export class ExtractIdsMiddleware implements NestMiddleware, CanActivate { req.method === 'GET' && req.query.fk_model_id ) { - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: req.query?.fk_model_id, }); + + if (!model) { + NcError.tableNotFound(req.query?.fk_model_id); + } + req.ncBaseId = model?.base_id; } else if ( [ @@ -174,7 +290,12 @@ export class ExtractIdsMiddleware implements NestMiddleware, CanActivate { (req.method === 'PATCH' || req.method === 'DELETE') && req.params.commentId ) { - const comment = await Comment.get(params.commentId); + const comment = await Comment.get(context, params.commentId); + + if (!comment) { + NcError.genericNotFound('Comment', params.commentId); + } + req.ncBaseId = comment?.base_id; } // extract base id from query params only if it's userMe endpoint or webhook plugin list @@ -191,6 +312,11 @@ export class ExtractIdsMiddleware implements NestMiddleware, CanActivate { req.ncBaseId = req.query.base_id; } + req.context = { + workspace_id: null, + base_id: req.ncBaseId, + }; + next(); } diff --git a/packages/nocodb/src/models/ApiToken.ts b/packages/nocodb/src/models/ApiToken.ts index 96f056936b..8dfafb95c8 100644 --- a/packages/nocodb/src/models/ApiToken.ts +++ b/packages/nocodb/src/models/ApiToken.ts @@ -5,13 +5,14 @@ import { CacheGetType, CacheScope, MetaTable, + RootScopes, } from '~/utils/globals'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; export default class ApiToken implements ApiTokenType { + fk_workspace_id?: string; base_id?: string; - db_alias?: string; fk_user_id?: string; description?: string; permissions?: string; @@ -28,11 +29,17 @@ export default class ApiToken implements ApiTokenType { ncMeta = Noco.ncMeta, ) { const token = nanoid(40); - await ncMeta.metaInsert(null, null, MetaTable.API_TOKENS, { - description: apiToken.description, - token, - fk_user_id: apiToken.fk_user_id, - }); + await ncMeta.metaInsert2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.API_TOKENS, + { + description: apiToken.description, + token, + fk_user_id: apiToken.fk_user_id, + }, + true, + ); return this.getByToken(token).then(async (apiToken) => { await NocoCache.appendToList( CacheScope.API_TOKEN, @@ -46,9 +53,14 @@ export default class ApiToken implements ApiTokenType { static async list(userId: string, ncMeta = Noco.ncMeta) { // let tokens = await NocoCache.getList(CacheScope.API_TOKEN, []); // if (!tokens.length) { - const tokens = await ncMeta.metaList(null, null, MetaTable.API_TOKENS, { - condition: { fk_user_id: userId }, - }); + const tokens = await ncMeta.metaList2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.API_TOKENS, + { + condition: { fk_user_id: userId }, + }, + ); // await NocoCache.setList(CacheScope.API_TOKEN, [], tokens); // } return tokens?.map((t) => new ApiToken(t)); @@ -59,7 +71,12 @@ export default class ApiToken implements ApiTokenType { `${CacheScope.API_TOKEN}:${token}`, CacheDelDirection.CHILD_TO_PARENT, ); - return await ncMeta.metaDelete(null, null, MetaTable.API_TOKENS, { token }); + return await ncMeta.metaDelete( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.API_TOKENS, + { token }, + ); } static async getByToken(token, ncMeta = Noco.ncMeta) { @@ -70,7 +87,12 @@ export default class ApiToken implements ApiTokenType { CacheGetType.TYPE_OBJECT, )); if (!data) { - data = await ncMeta.metaGet(null, null, MetaTable.API_TOKENS, { token }); + data = await ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.API_TOKENS, + { token }, + ); await NocoCache.set(`${CacheScope.API_TOKEN}:${token}`, data); } return data && new ApiToken(data); diff --git a/packages/nocodb/src/models/Audit.ts b/packages/nocodb/src/models/Audit.ts index 4ecc03b4a7..21d76f0722 100644 --- a/packages/nocodb/src/models/Audit.ts +++ b/packages/nocodb/src/models/Audit.ts @@ -1,9 +1,8 @@ import { AuditOperationTypes } from 'nocodb-sdk'; import type { AuditType } from 'nocodb-sdk'; -import Model from '~/models/Model'; import Noco from '~/Noco'; import { extractProps } from '~/helpers/extractProps'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; const opTypes = [ 'COMMENT', @@ -51,6 +50,7 @@ export default class Audit implements AuditType { user?: string; ip?: string; source_id?: string; + fk_workspace_id?: string; base_id?: string; fk_model_id?: string; row_id?: string; @@ -66,8 +66,8 @@ export default class Audit implements AuditType { public static async get(auditId: string) { const audit = await Noco.ncMeta.metaGet2( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.AUDIT, auditId, ); @@ -90,6 +90,7 @@ export default class Audit implements AuditType { 'user', 'ip', 'source_id', + 'fk_workspace_id', 'base_id', 'row_id', 'fk_model_id', @@ -99,20 +100,13 @@ export default class Audit implements AuditType { 'description', 'details', ]); - if ( - (!insertObj.base_id || !insertObj.source_id) && - insertObj.fk_model_id - ) { - const model = await Model.getByIdOrName( - { id: insertObj.fk_model_id }, - ncMeta, - ); - insertObj.base_id = model.base_id; - insertObj.source_id = model.source_id; - } - - return await ncMeta.metaInsert2(null, null, MetaTable.AUDIT, insertObj); + return await ncMeta.metaInsert2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.AUDIT, + insertObj, + ); }; if (forceAwait) { @@ -153,17 +147,22 @@ export default class Audit implements AuditType { sourceId?: string; }, ) { - return await Noco.ncMeta.metaList2(null, null, MetaTable.AUDIT, { - condition: { - base_id: baseId, - ...(sourceId ? { source_id: sourceId } : {}), - }, - orderBy: { - created_at: 'desc', + return await Noco.ncMeta.metaList2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.AUDIT, + { + condition: { + base_id: baseId, + ...(sourceId ? { source_id: sourceId } : {}), + }, + orderBy: { + created_at: 'desc', + }, + limit, + offset, }, - limit, - offset, - }); + ); } static async baseAuditCount( @@ -183,14 +182,19 @@ export default class Audit implements AuditType { } static async sourceAuditList(sourceId: string, { limit = 25, offset = 0 }) { - return await Noco.ncMeta.metaList2(null, null, MetaTable.AUDIT, { - condition: { source_id: sourceId }, - orderBy: { - created_at: 'desc', + return await Noco.ncMeta.metaList2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.AUDIT, + { + condition: { source_id: sourceId }, + orderBy: { + created_at: 'desc', + }, + limit, + offset, }, - limit, - offset, - }); + ); } static async sourceAuditCount(sourceId: string) { diff --git a/packages/nocodb/src/models/BarcodeColumn.ts b/packages/nocodb/src/models/BarcodeColumn.ts index 7cd81d6778..33cf9f4a1a 100644 --- a/packages/nocodb/src/models/BarcodeColumn.ts +++ b/packages/nocodb/src/models/BarcodeColumn.ts @@ -1,11 +1,15 @@ +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; import { extractProps } from '~/helpers/extractProps'; import { CacheGetType, CacheScope, MetaTable } from '~/utils/globals'; import { Column } from '~/models/index'; +import { NcError } from '~/helpers/catchError'; export default class BarcodeColumn { id: string; + fk_workspace_id?: string; + fk_base_id?: string; fk_column_id: string; fk_barcode_value_column_id: string; barcode_format: string; @@ -15,6 +19,7 @@ export default class BarcodeColumn { } public static async insert( + context: NcContext, barcodeColumn: Partial, ncMeta = Noco.ncMeta, ) { @@ -23,12 +28,34 @@ export default class BarcodeColumn { 'fk_barcode_value_column_id', 'barcode_format', ]); - await ncMeta.metaInsert2(null, null, MetaTable.COL_BARCODE, insertObj); - return this.read(barcodeColumn.fk_column_id, ncMeta); + const column = await Column.get( + context, + { + colId: insertObj.fk_column_id, + }, + ncMeta, + ); + + if (!column) { + NcError.fieldNotFound(insertObj.fk_column_id); + } + + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.COL_BARCODE, + insertObj, + ); + + return this.read(context, barcodeColumn.fk_column_id, ncMeta); } - public static async read(columnId: string, ncMeta = Noco.ncMeta) { + public static async read( + context: NcContext, + columnId: string, + ncMeta = Noco.ncMeta, + ) { let column = columnId && (await NocoCache.get( @@ -37,8 +64,8 @@ export default class BarcodeColumn { )); if (!column) { column = await ncMeta.metaGet2( - null, //, - null, //model.db_alias, + context.workspace_id, + context.base_id, MetaTable.COL_BARCODE, { fk_column_id: columnId }, ); @@ -48,9 +75,13 @@ export default class BarcodeColumn { return column ? new BarcodeColumn(column) : null; } - async getValueColumn() { - return Column.get({ - colId: this.fk_barcode_value_column_id, - }); + async getValueColumn(context: NcContext, ncMeta = Noco.ncMeta) { + return Column.get( + context, + { + colId: this.fk_barcode_value_column_id, + }, + ncMeta, + ); } } diff --git a/packages/nocodb/src/models/Base.ts b/packages/nocodb/src/models/Base.ts index f692a87258..b9a598a6ea 100644 --- a/packages/nocodb/src/models/Base.ts +++ b/packages/nocodb/src/models/Base.ts @@ -1,5 +1,6 @@ import type { BaseType, BoolType, MetaType } from 'nocodb-sdk'; import type { DB_TYPES } from '~/utils/globals'; +import type { NcContext } from '~/interface/config'; import { BaseUser, Source } from '~/models'; import Noco from '~/Noco'; import { @@ -7,6 +8,7 @@ import { CacheGetType, CacheScope, MetaTable, + RootScopes, } from '~/utils/globals'; import { extractProps } from '~/helpers/extractProps'; import NocoCache from '~/cache/NocoCache'; @@ -15,6 +17,7 @@ import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; export default class Base implements BaseType { public id: string; + public fk_workspace_id?: string; public title: string; public prefix: string; public status: string; @@ -67,14 +70,20 @@ export default class Base implements BaseType { } const { id: baseId } = await ncMeta.metaInsert2( - null, - null, + RootScopes.BASE, + RootScopes.BASE, MetaTable.PROJECT, insertObj, ); + const context = { + workspace_id: (base as any).fk_workspace_id, + base_id: baseId, + }; + for (const source of base.sources) { await Source.createBase( + context, { type: source.config?.client as (typeof DB_TYPES)[number], ...source, @@ -85,7 +94,7 @@ export default class Base implements BaseType { } await NocoCache.del(CacheScope.INSTANCE_META); - return this.getWithInfo(baseId, ncMeta).then(async (base) => { + return this.getWithInfo(context, baseId, ncMeta).then(async (base) => { await NocoCache.appendToList( CacheScope.PROJECT, [], @@ -105,25 +114,30 @@ export default class Base implements BaseType { let { list: baseList } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !baseList.length) { - baseList = await ncMeta.metaList2(null, null, MetaTable.PROJECT, { - xcCondition: { - _or: [ - { - deleted: { - eq: false, + baseList = await ncMeta.metaList2( + RootScopes.BASE, + RootScopes.BASE, + MetaTable.PROJECT, + { + xcCondition: { + _or: [ + { + deleted: { + eq: false, + }, }, - }, - { - deleted: { - eq: null, + { + deleted: { + eq: null, + }, }, - }, - ], + ], + }, + orderBy: { + order: 'asc', + }, }, - orderBy: { - order: 'asc', - }, - }); + ); await NocoCache.setList(CacheScope.PROJECT, [], baseList); } @@ -150,7 +164,11 @@ export default class Base implements BaseType { } // @ts-ignore - static async get(baseId: string, ncMeta = Noco.ncMeta): Promise { + static async get( + context: NcContext, + baseId: string, + ncMeta = Noco.ncMeta, + ): Promise { let baseData = baseId && (await NocoCache.get( @@ -158,10 +176,15 @@ export default class Base implements BaseType { CacheGetType.TYPE_OBJECT, )); if (!baseData) { - baseData = await ncMeta.metaGet2(null, null, MetaTable.PROJECT, { - id: baseId, - deleted: false, - }); + baseData = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.PROJECT, + { + id: baseId, + deleted: false, + }, + ); if (baseData) { baseData.meta = parseMetaProp(baseData); await NocoCache.set(`${CacheScope.PROJECT}:${baseId}`, baseData); @@ -175,12 +198,17 @@ export default class Base implements BaseType { } async getSources(ncMeta = Noco.ncMeta): Promise { - return (this.sources = await Source.list({ baseId: this.id }, ncMeta)); + return (this.sources = await Source.list( + { workspace_id: this.fk_workspace_id, base_id: this.id }, + { baseId: this.id }, + ncMeta, + )); } // todo: hide credentials // @ts-ignore static async getWithInfo( + context: NcContext, baseId: string, ncMeta = Noco.ncMeta, ): Promise { @@ -192,10 +220,15 @@ export default class Base implements BaseType { )); if (!baseData) { - baseData = await ncMeta.metaGet2(null, null, MetaTable.PROJECT, { - id: baseId, - deleted: false, - }); + baseData = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.PROJECT, + { + id: baseId, + deleted: false, + }, + ); if (baseData) { baseData.meta = parseMetaProp(baseData); await NocoCache.set(`${CacheScope.PROJECT}:${baseId}`, baseData); @@ -222,8 +255,12 @@ export default class Base implements BaseType { } // @ts-ignore - static async softDelete(baseId: string, ncMeta = Noco.ncMeta): Promise { - await this.clearConnectionPool(baseId, ncMeta); + static async softDelete( + context: NcContext, + baseId: string, + ncMeta = Noco.ncMeta, + ): Promise { + await this.clearConnectionPool(context, baseId, ncMeta); // get existing cache const key = `${CacheScope.PROJECT}:${baseId}`; @@ -250,8 +287,8 @@ export default class Base implements BaseType { // set meta return await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.PROJECT, { deleted: true }, baseId, @@ -260,6 +297,7 @@ export default class Base implements BaseType { // @ts-ignore static async update( + context: NcContext, baseId: string, base: Partial, ncMeta = Noco.ncMeta, @@ -318,8 +356,8 @@ export default class Base implements BaseType { // set meta return await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.PROJECT, updateObj, baseId, @@ -327,21 +365,29 @@ export default class Base implements BaseType { } // Todo: Remove the base entry from the connection pool in NcConnectionMgrv2 - static async delete(baseId, ncMeta = Noco.ncMeta): Promise { - let base = await this.get(baseId); - const users = await BaseUser.getUsersList({ - base_id: baseId, - }); + static async delete( + context: NcContext, + baseId, + ncMeta = Noco.ncMeta, + ): Promise { + let base = await this.get(context, baseId, ncMeta); + const users = await BaseUser.getUsersList( + context, + { + base_id: baseId, + }, + ncMeta, + ); for (const user of users) { - await BaseUser.delete(baseId, user.id); + await BaseUser.delete(context, baseId, user.id, ncMeta); } - const sources = await Source.list({ baseId }); + const sources = await Source.list(context, { baseId }, ncMeta); for (const source of sources) { - await source.delete(ncMeta); + await source.delete(context, ncMeta); } - base = await this.get(baseId); + base = await this.get(context, baseId, ncMeta); if (base) { // delete : @@ -360,14 +406,24 @@ export default class Base implements BaseType { CacheDelDirection.CHILD_TO_PARENT, ); - await ncMeta.metaDelete(null, null, MetaTable.AUDIT, { - base_id: baseId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.AUDIT, + { + base_id: baseId, + }, + ); - return await ncMeta.metaDelete(null, null, MetaTable.PROJECT, baseId); + return await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.PROJECT, + baseId, + ); } - static async getByUuid(uuid, ncMeta = Noco.ncMeta) { + static async getByUuid(context: NcContext, uuid, ncMeta = Noco.ncMeta) { const baseId = uuid && (await NocoCache.get( @@ -376,9 +432,14 @@ export default class Base implements BaseType { )); let baseData = null; if (!baseId) { - baseData = await Noco.ncMeta.metaGet2(null, null, MetaTable.PROJECT, { - uuid, - }); + baseData = await Noco.ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.PROJECT, + { + uuid, + }, + ); if (baseData) { baseData.meta = parseMetaProp(baseData); await NocoCache.set( @@ -387,13 +448,17 @@ export default class Base implements BaseType { ); } } else { - return this.get(baseId); + return this.get(context, baseId, ncMeta); } - return baseData?.id && this.get(baseData?.id, ncMeta); + return baseData?.id && this.get(context, baseData?.id, ncMeta); } - static async getWithInfoByTitle(title: string, ncMeta = Noco.ncMeta) { - const base = await this.getByTitle(title, ncMeta); + static async getWithInfoByTitle( + context: NcContext, + title: string, + ncMeta = Noco.ncMeta, + ) { + const base = await this.getByTitle(context, title, ncMeta); if (base) { await base.getSources(ncMeta); } @@ -401,7 +466,11 @@ export default class Base implements BaseType { return base; } - static async getByTitle(title: string, ncMeta = Noco.ncMeta) { + static async getByTitle( + context: NcContext, + title: string, + ncMeta = Noco.ncMeta, + ) { const baseId = title && (await NocoCache.get( @@ -410,10 +479,15 @@ export default class Base implements BaseType { )); let baseData = null; if (!baseId) { - baseData = await Noco.ncMeta.metaGet2(null, null, MetaTable.PROJECT, { - title, - deleted: false, - }); + baseData = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.PROJECT, + { + title, + deleted: false, + }, + ); if (baseData) { baseData.meta = parseMetaProp(baseData); await NocoCache.set( @@ -422,12 +496,16 @@ export default class Base implements BaseType { ); } } else { - return this.get(baseId); + return this.get(context, baseId, ncMeta); } - return baseData?.id && this.get(baseData?.id, ncMeta); + return baseData?.id && this.get(context, baseData?.id, ncMeta); } - static async getByTitleOrId(titleOrId: string, ncMeta = Noco.ncMeta) { + static async getByTitleOrId( + context: NcContext, + titleOrId: string, + ncMeta = Noco.ncMeta, + ) { const baseId = titleOrId && (await NocoCache.get( @@ -436,9 +514,9 @@ export default class Base implements BaseType { )); let baseData = null; if (!baseId) { - baseData = await Noco.ncMeta.metaGet2( - null, - null, + baseData = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, MetaTable.PROJECT, { deleted: false, @@ -470,13 +548,17 @@ export default class Base implements BaseType { ); } } else { - return this.get(baseId); + return this.get(context, baseId, ncMeta); } - return baseData?.id && this.get(baseData?.id, ncMeta); + return baseData?.id && this.get(context, baseData?.id, ncMeta); } - static async getWithInfoByTitleOrId(titleOrId: string, ncMeta = Noco.ncMeta) { - const base = await this.getByTitleOrId(titleOrId, ncMeta); + static async getWithInfoByTitleOrId( + context: NcContext, + titleOrId: string, + ncMeta = Noco.ncMeta, + ) { + const base = await this.getByTitleOrId(context, titleOrId, ncMeta); // parse meta base.meta = parseMetaProp(base); @@ -488,8 +570,12 @@ export default class Base implements BaseType { return base; } - static async clearConnectionPool(baseId: string, ncMeta = Noco.ncMeta) { - const base = await this.get(baseId, ncMeta); + static async clearConnectionPool( + context: NcContext, + baseId: string, + ncMeta = Noco.ncMeta, + ) { + const base = await this.get(context, baseId, ncMeta); if (base) { const sources = await base.getSources(ncMeta); for (const source of sources) { diff --git a/packages/nocodb/src/models/BaseUser.ts b/packages/nocodb/src/models/BaseUser.ts index 761b42631e..c6dac92b30 100644 --- a/packages/nocodb/src/models/BaseUser.ts +++ b/packages/nocodb/src/models/BaseUser.ts @@ -1,12 +1,14 @@ import { ProjectRoles } from 'nocodb-sdk'; import type { BaseType } from 'nocodb-sdk'; import type User from '~/models/User'; +import type { NcContext } from '~/interface/config'; import Base from '~/models/Base'; import { CacheDelDirection, CacheGetType, CacheScope, MetaTable, + RootScopes, } from '~/utils/globals'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -14,6 +16,7 @@ import { extractProps } from '~/helpers/extractProps'; import { parseMetaProp } from '~/utils/modelUtils'; export default class BaseUser { + fk_workspace_id?: string; base_id: string; fk_user_id: string; roles?: string; @@ -27,6 +30,7 @@ export default class BaseUser { } public static async bulkInsert( + context: NcContext, baseUsers: Partial[], ncMeta = Noco.ncMeta, ) { @@ -34,9 +38,13 @@ export default class BaseUser { extractProps(baseUser, ['fk_user_id', 'base_id', 'roles']), ); + if (!insertObj.length) { + return; + } + const bulkData = await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.PROJECT_USERS, insertObj, true, @@ -68,6 +76,7 @@ export default class BaseUser { } public static async insert( + context: NcContext, baseUser: Partial, ncMeta = Noco.ncMeta, ) { @@ -78,14 +87,14 @@ export default class BaseUser { ]); const { base_id, fk_user_id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.PROJECT_USERS, insertObj, true, ); - const res = await this.get(base_id, fk_user_id, ncMeta); + const res = await this.get(context, base_id, fk_user_id, ncMeta); await NocoCache.appendToList( CacheScope.BASE_USER, @@ -97,9 +106,14 @@ export default class BaseUser { } // public static async update(id, user: Partial, ncMeta = Noco.ncMeta) { - // // return await ncMeta.metaUpdate(null, null, MetaTable.USERS, id, insertObj); + // // return await ncMeta.metaUpdate(context.workspace_id, context.base_id, insertObj); // } - static async get(baseId: string, userId: string, ncMeta = Noco.ncMeta) { + static async get( + context: NcContext, + baseId: string, + userId: string, + ncMeta = Noco.ncMeta, + ) { let baseUser = baseId && userId && @@ -148,6 +162,7 @@ export default class BaseUser { } public static async getUsersList( + context: NcContext, { base_id, mode = 'full', @@ -226,6 +241,7 @@ export default class BaseUser { } public static async getUsersCount( + context: NcContext, { base_id, query, @@ -257,6 +273,7 @@ export default class BaseUser { } static async updateRoles( + context: NcContext, baseId, userId, roles: string, @@ -264,8 +281,8 @@ export default class BaseUser { ) { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.PROJECT_USERS, { roles, @@ -284,6 +301,7 @@ export default class BaseUser { } static async update( + context: NcContext, baseId, userId, baseUser: Partial, @@ -292,24 +310,35 @@ export default class BaseUser { const updateObj = extractProps(baseUser, ['starred', 'hidden', 'order']); // set meta - await ncMeta.metaUpdate(null, null, MetaTable.PROJECT_USERS, updateObj, { - fk_user_id: userId, - base_id: baseId, - }); + await ncMeta.metaUpdate( + context.workspace_id, + context.base_id, + MetaTable.PROJECT_USERS, + updateObj, + { + fk_user_id: userId, + base_id: baseId, + }, + ); await NocoCache.update( `${CacheScope.BASE_USER}:${baseId}:${userId}`, updateObj, ); - return await this.get(baseId, userId, ncMeta); + return await this.get(context, baseId, userId, ncMeta); } - static async delete(baseId: string, userId: string, ncMeta = Noco.ncMeta) { + static async delete( + context: NcContext, + baseId: string, + userId: string, + ncMeta = Noco.ncMeta, + ) { // delete meta const response = await ncMeta.metaDelete( - null, - null, + context.workspace_id, + context.base_id, MetaTable.PROJECT_USERS, { fk_user_id: userId, @@ -330,9 +359,14 @@ export default class BaseUser { userId: string, ncMeta = Noco.ncMeta, ): Promise { - return await ncMeta.metaList2(null, null, MetaTable.PROJECT_USERS, { - condition: { fk_user_id: userId }, - }); + return await ncMeta.metaList2( + RootScopes.BASE, + RootScopes.BASE, + MetaTable.PROJECT_USERS, + { + condition: { fk_user_id: userId }, + }, + ); } static async getProjectsList( @@ -434,17 +468,21 @@ export default class BaseUser { } static async updateOrInsert( + context: NcContext, baseId, userId, baseUser: Partial, ncMeta = Noco.ncMeta, ) { - const existingProjectUser = await this.get(baseId, userId, ncMeta); + const existingProjectUser = await this.get(context, baseId, userId, ncMeta); if (existingProjectUser) { - return await this.update(baseId, userId, baseUser, ncMeta); + return await this.update(context, baseId, userId, baseUser, ncMeta); } else { - return await this.insert({ base_id: baseId, fk_user_id: userId }); + return await this.insert(context, { + base_id: baseId, + fk_user_id: userId, + }); } } } diff --git a/packages/nocodb/src/models/CalendarRange.ts b/packages/nocodb/src/models/CalendarRange.ts index 4a0de22249..6422841f68 100644 --- a/packages/nocodb/src/models/CalendarRange.ts +++ b/packages/nocodb/src/models/CalendarRange.ts @@ -1,4 +1,5 @@ import type { CalendarRangeType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; import { extractProps } from '~/helpers/extractProps'; @@ -7,6 +8,8 @@ import { CacheDelDirection, CacheScope, MetaTable } from '~/utils/globals'; export default class CalendarRange implements CalendarRangeType { id?: string; fk_from_column_id?: string; + fk_workspace_id?: string; + base_id?: string; fk_view_id?: string; constructor(data: Partial) { @@ -14,23 +17,27 @@ export default class CalendarRange implements CalendarRangeType { } public static async bulkInsert( + context: NcContext, data: Partial[], ncMeta = Noco.ncMeta, ) { - let insertObj = []; + const calRanges: { + fk_from_column_id?: string; + fk_view_id?: string; + }[] = []; for (const d of data) { const tempObj = extractProps(d, ['fk_from_column_id', 'fk_view_id']); - insertObj.push(tempObj); + calRanges.push(tempObj); } - if (!insertObj.length) return false; + if (!calRanges.length) return false; - insertObj = insertObj[0]; + const insertObj = calRanges[0]; const insertData = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW_RANGE, insertObj, ); @@ -54,7 +61,11 @@ export default class CalendarRange implements CalendarRangeType { return true; } - public static async read(fk_view_id: string, ncMeta = Noco.ncMeta) { + public static async read( + context: NcContext, + fk_view_id: string, + ncMeta = Noco.ncMeta, + ) { const cachedList = await NocoCache.getList(CacheScope.CALENDAR_VIEW_RANGE, [ fk_view_id, ]); @@ -62,8 +73,8 @@ export default class CalendarRange implements CalendarRangeType { const { isNoneList } = cachedList; if (!isNoneList && !ranges.length) { ranges = await ncMeta.metaList2( - null, //, - null, //model.db_alias, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW_RANGE, { condition: { fk_view_id } }, ); @@ -84,12 +95,13 @@ export default class CalendarRange implements CalendarRangeType { } public static async find( + context: NcContext, fk_view_id: string, ncMeta = Noco.ncMeta, ): Promise { const data = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW_RANGE, { fk_view_id, @@ -100,22 +112,28 @@ export default class CalendarRange implements CalendarRangeType { } public static async IsColumnBeingUsedAsRange( + context: NcContext, columnId: string, ncMeta = Noco.ncMeta, ) { return ( ( - await ncMeta.metaList2(null, null, MetaTable.CALENDAR_VIEW_RANGE, { - xcCondition: { - _or: [ - { - fk_from_column_id: { - eq: columnId, + await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.CALENDAR_VIEW_RANGE, + { + xcCondition: { + _or: [ + { + fk_from_column_id: { + eq: columnId, + }, }, - }, - ], + ], + }, }, - }) + ) ).length > 0 ); } diff --git a/packages/nocodb/src/models/CalendarView.ts b/packages/nocodb/src/models/CalendarView.ts index 14680f5d27..c2a59f35ac 100644 --- a/packages/nocodb/src/models/CalendarView.ts +++ b/packages/nocodb/src/models/CalendarView.ts @@ -1,6 +1,6 @@ import type { BoolType, MetaType } from 'nocodb-sdk'; import type { CalendarType } from 'nocodb-sdk'; -import View from '~/models/View'; +import type { NcContext } from '~/interface/config'; import { extractProps } from '~/helpers/extractProps'; import { prepareForDb, prepareForResponse } from '~/utils/modelUtils'; import NocoCache from '~/cache/NocoCache'; @@ -11,6 +11,7 @@ import CalendarRange from '~/models/CalendarRange'; export default class CalendarView implements CalendarType { fk_view_id: string; title: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; meta?: MetaType; @@ -27,7 +28,11 @@ export default class CalendarView implements CalendarType { Object.assign(this, data); } - public static async get(viewId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { let view = viewId && (await NocoCache.get( @@ -35,17 +40,22 @@ export default class CalendarView implements CalendarType { CacheGetType.TYPE_OBJECT, )); if (view) { - const calendarRange = await CalendarRange.read(viewId, ncMeta); + const calendarRange = await CalendarRange.read(context, viewId, ncMeta); if (calendarRange) { view.calendar_range = calendarRange.ranges; } else { view.calendar_range = []; } } else { - view = await ncMeta.metaGet2(null, null, MetaTable.CALENDAR_VIEW, { - fk_view_id: viewId, - }); - const calendarRange = await CalendarRange.read(viewId); + view = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.CALENDAR_VIEW, + { + fk_view_id: viewId, + }, + ); + const calendarRange = await CalendarRange.read(context, viewId, ncMeta); if (view && calendarRange) { view.calendar_range = calendarRange.ranges; } @@ -55,7 +65,11 @@ export default class CalendarView implements CalendarType { return view && new CalendarView(view); } - static async insert(view: Partial, ncMeta = Noco.ncMeta) { + static async insert( + context: NcContext, + view: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = { base_id: view.base_id, source_id: view.source_id, @@ -63,25 +77,19 @@ export default class CalendarView implements CalendarType { meta: view.meta, }; - const viewRef = await View.get(view.fk_view_id); - - if (!(view.base_id && view.source_id)) { - insertObj.base_id = viewRef.base_id; - insertObj.source_id = viewRef.source_id; - } - await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW, insertObj, true, ); - return this.get(view.fk_view_id, ncMeta); + return this.get(context, view.fk_view_id, ncMeta); } static async update( + context: NcContext, calendarId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -89,25 +97,32 @@ export default class CalendarView implements CalendarType { const updateObj = extractProps(body, ['fk_cover_image_col_id', 'meta']); if (body.calendar_range) { - await ncMeta.metaDelete(null, null, MetaTable.CALENDAR_VIEW_RANGE, { - fk_view_id: calendarId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.CALENDAR_VIEW_RANGE, + { + fk_view_id: calendarId, + }, + ); // if calendar range is updated, delete cache await NocoCache.del(`${CacheScope.CALENDAR_VIEW}:${calendarId}`); await CalendarRange.bulkInsert( + context, body.calendar_range.map((range) => { return { fk_view_id: calendarId, ...range, }; }), + ncMeta, ); } // update meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW, prepareForDb(updateObj), { diff --git a/packages/nocodb/src/models/CalendarViewColumn.ts b/packages/nocodb/src/models/CalendarViewColumn.ts index 3faecd178f..44366cc590 100644 --- a/packages/nocodb/src/models/CalendarViewColumn.ts +++ b/packages/nocodb/src/models/CalendarViewColumn.ts @@ -1,4 +1,5 @@ import type { BoolType, MetaType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -8,9 +9,10 @@ import { CacheGetType, CacheScope, MetaTable } from '~/utils/globals'; export default class CalendarViewColumn { id?: string; + fk_workspace_id?: string; + base_id?: string; fk_view_id?: string; fk_column_id?: string; - base_id?: string; source_id?: string; show?: BoolType; underline?: BoolType; @@ -23,7 +25,11 @@ export default class CalendarViewColumn { Object.assign(this, data); } - public static async get(calendarViewColumnId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + calendarViewColumnId: string, + ncMeta = Noco.ncMeta, + ) { let viewColumn = calendarViewColumnId && (await NocoCache.get( @@ -32,8 +38,8 @@ export default class CalendarViewColumn { )); if (!viewColumn) { viewColumn = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW_COLUMNS, calendarViewColumnId, ); @@ -52,6 +58,7 @@ export default class CalendarViewColumn { } static async insert( + context: NcContext, column: Partial, ncMeta = Noco.ncMeta, ) { @@ -73,25 +80,24 @@ export default class CalendarViewColumn { }, ); - if (!(insertObj.base_id && insertObj.source_id)) { - const viewRef = await View.get(insertObj.fk_view_id, ncMeta); - insertObj.base_id = viewRef.base_id; - insertObj.source_id = viewRef.source_id; - } - const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW_COLUMNS, insertObj, ); { - const view = await View.get(column.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const view = await View.get(context, column.fk_view_id, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } - return this.get(id, ncMeta).then(async (viewColumn) => { + return this.get(context, id, ncMeta).then(async (viewColumn) => { await NocoCache.appendToList( CacheScope.CALENDAR_VIEW_COLUMN, [column.fk_view_id], @@ -102,6 +108,7 @@ export default class CalendarViewColumn { } public static async list( + context: NcContext, viewId: string, ncMeta = Noco.ncMeta, ): Promise { @@ -113,8 +120,8 @@ export default class CalendarViewColumn { const { isNoneList } = cachedList; if (!isNoneList && !viewColumns.length) { viewColumns = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW_COLUMNS, { condition: { @@ -145,6 +152,7 @@ export default class CalendarViewColumn { } static async update( + context: NcContext, columnId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -159,8 +167,8 @@ export default class CalendarViewColumn { // update meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW_COLUMNS, updateObj, columnId, @@ -173,9 +181,9 @@ export default class CalendarViewColumn { // on view column update, delete any optimised single query cache { - const viewCol = await this.get(columnId, ncMeta); - const view = await View.get(viewCol.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view]); + const viewCol = await this.get(context, columnId, ncMeta); + const view = await View.get(context, viewCol.fk_view_id, ncMeta); + await View.clearSingleQueryCache(context, view.fk_model_id, [view]); } return res; diff --git a/packages/nocodb/src/models/Column.ts b/packages/nocodb/src/models/Column.ts index 0b469702a9..bd77568001 100644 --- a/packages/nocodb/src/models/Column.ts +++ b/packages/nocodb/src/models/Column.ts @@ -5,6 +5,7 @@ import { } from 'nocodb-sdk'; import { Logger } from '@nestjs/common'; import type { ColumnReqType, ColumnType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import FormulaColumn from '~/models/FormulaColumn'; import LinkToAnotherRecordColumn from '~/models/LinkToAnotherRecordColumn'; import LookupColumn from '~/models/LookupColumn'; @@ -52,6 +53,7 @@ const logger = new Logger('Column'); export default class Column implements ColumnType { public fk_model_id: string; + public fk_workspace_id?: string; public base_id: string; public source_id: string; @@ -92,8 +94,12 @@ export default class Column implements ColumnType { Object.assign(this, data); } - public async getModel(ncMeta = Noco.ncMeta): Promise { + public async getModel( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return Model.getByIdOrName( + context, { id: this.fk_model_id, }, @@ -102,6 +108,7 @@ export default class Column implements ColumnType { } public static async insert( + context: NcContext, column: Partial & { source_id?: string; [key: string]: any; @@ -170,24 +177,24 @@ export default class Column implements ColumnType { else insertObj.validate = JSON.stringify(column.validate); } - if (!(column.base_id && column.source_id)) { + if (!column.source_id) { const model = await Model.getByIdOrName( + context, { id: column.fk_model_id }, ncMeta, ); - insertObj.base_id = model.base_id; insertObj.source_id = model.source_id; } if (!column.uidt) throw new Error('UI Datatype not found'); const row = await ncMeta.metaInsert2( - null, //column.base_id || column.source_id, - null, //column.db_alias, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, insertObj, ); - const col = await this.get({ colId: row.id }, ncMeta); + const col = await this.get(context, { colId: row.id }, ncMeta); await NocoCache.appendToList( CacheScope.COLUMN, @@ -195,9 +202,10 @@ export default class Column implements ColumnType { `${CacheScope.COLUMN}:${row.id}`, ); - await this.insertColOption(column, row.id, ncMeta); + await this.insertColOption(context, column, row.id, ncMeta); await View.insertColumnToAllViews( + context, { fk_column_id: row.id, fk_model_id: column.fk_model_id, @@ -216,12 +224,13 @@ export default class Column implements ColumnType { ncMeta, ); - await View.clearSingleQueryCache(column.fk_model_id, null, ncMeta); + await View.clearSingleQueryCache(context, column.fk_model_id, null, ncMeta); return col; } private static async insertColOption( + context, column: Partial & { source_id?: string; [p: string]: any }, colId, ncMeta = Noco.ncMeta, @@ -230,6 +239,7 @@ export default class Column implements ColumnType { case UITypes.Lookup: { // LookupColumn.insert() await LookupColumn.insert( + context, { fk_column_id: colId, fk_relation_column_id: column.fk_relation_column_id, @@ -241,6 +251,7 @@ export default class Column implements ColumnType { } case UITypes.Rollup: { await RollupColumn.insert( + context, { fk_column_id: colId, fk_relation_column_id: column.fk_relation_column_id, @@ -255,6 +266,7 @@ export default class Column implements ColumnType { case UITypes.Links: case UITypes.LinkToAnotherRecord: { await LinkToAnotherRecordColumn.insert( + context, { fk_column_id: colId, @@ -284,6 +296,7 @@ export default class Column implements ColumnType { } case UITypes.QrCode: { await QrCodeColumn.insert( + context, { fk_column_id: colId, fk_qr_value_column_id: column.fk_qr_value_column_id, @@ -294,6 +307,7 @@ export default class Column implements ColumnType { } case UITypes.Barcode: { await BarcodeColumn.insert( + context, { fk_column_id: colId, fk_barcode_value_column_id: column.fk_barcode_value_column_id, @@ -305,6 +319,7 @@ export default class Column implements ColumnType { } case UITypes.Formula: { await FormulaColumn.insert( + context, { fk_column_id: colId, formula: column.formula, @@ -327,7 +342,7 @@ export default class Column implements ColumnType { color: selectColors[i % selectColors.length], }); } - await SelectOption.bulkInsert(bulkOptions, ncMeta); + await SelectOption.bulkInsert(context, bulkOptions, ncMeta); } else { const bulkOptions = []; for (const [i, option] of column.colOptions.options.entries() || @@ -344,7 +359,7 @@ export default class Column implements ColumnType { }); } - await SelectOption.bulkInsert(bulkOptions, ncMeta); + await SelectOption.bulkInsert(context, bulkOptions, ncMeta); } break; } @@ -360,7 +375,7 @@ export default class Column implements ColumnType { color: selectColors[i % selectColors.length], }); } - await SelectOption.bulkInsert(bulkOptions, ncMeta); + await SelectOption.bulkInsert(context, bulkOptions, ncMeta); } else { const bulkOptions = []; for (const [i, option] of column.colOptions.options.entries() || @@ -376,7 +391,7 @@ export default class Column implements ColumnType { order: i + 1, }); } - await SelectOption.bulkInsert(bulkOptions, ncMeta); + await SelectOption.bulkInsert(context, bulkOptions, ncMeta); } break; } @@ -384,8 +399,8 @@ export default class Column implements ColumnType { /* default: { await ncMeta.metaInsert2( - model.base_id, - model.db_alias, + context.workspace_id, + context.base_id, 'nc_col_props_v2', { column_id: model.column_id, @@ -419,8 +434,8 @@ export default class Column implements ColumnType { ) { for (const option of model.dtxp.split(',')) await ncMeta.metaInsert2( - model.base_id, - model.db_alias, + context.workspace_id, + context.base_id, MetaTable.COL_SELECT_OPTIONS', { column_id: colId, @@ -433,36 +448,39 @@ export default class Column implements ColumnType { } } - public async getColOptions(ncMeta = Noco.ncMeta): Promise { + public async getColOptions( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { let res: any; switch (this.uidt) { case UITypes.Lookup: - res = await LookupColumn.read(this.id, ncMeta); + res = await LookupColumn.read(context, this.id, ncMeta); break; case UITypes.Rollup: - res = await RollupColumn.read(this.id, ncMeta); + res = await RollupColumn.read(context, this.id, ncMeta); break; case UITypes.LinkToAnotherRecord: - res = await LinkToAnotherRecordColumn.read(this.id, ncMeta); + res = await LinkToAnotherRecordColumn.read(context, this.id, ncMeta); break; case UITypes.Links: - res = await LinksColumn.read(this.id, ncMeta); + res = await LinksColumn.read(context, this.id, ncMeta); break; case UITypes.MultiSelect: - res = await SelectOption.read(this.id, ncMeta); + res = await SelectOption.read(context, this.id, ncMeta); break; case UITypes.SingleSelect: - res = await SelectOption.read(this.id, ncMeta); + res = await SelectOption.read(context, this.id, ncMeta); break; case UITypes.Formula: - res = await FormulaColumn.read(this.id, ncMeta); + res = await FormulaColumn.read(context, this.id, ncMeta); break; case UITypes.QrCode: - res = await QrCodeColumn.read(this.id, ncMeta); + res = await QrCodeColumn.read(context, this.id, ncMeta); break; case UITypes.Barcode: - res = await BarcodeColumn.read(this.id, ncMeta); + res = await BarcodeColumn.read(context, this.id, ncMeta); break; // default: // res = await DbColumn.read(this.id); @@ -472,19 +490,28 @@ export default class Column implements ColumnType { return res; } - async loadModel(force = false): Promise { + async loadModel( + context: NcContext, + force = false, + ncMeta = Noco.ncMeta, + ): Promise { if (!this.model || force) { - this.model = await Model.getByIdOrName({ - // source_id: this.base_id, - // db_alias: this.db_alias, - id: this.fk_model_id, - }); + this.model = await Model.getByIdOrName( + context, + { + // source_id: this.base_id, + // db_alias: this.db_alias, + id: this.fk_model_id, + }, + ncMeta, + ); } return this.model; } public static async list( + context: NcContext, { fk_model_id, fk_default_view_id, @@ -501,7 +528,7 @@ export default class Column implements ColumnType { const { isNoneList } = cachedList; const defaultViewColumns = fk_default_view_id - ? await View.getColumns(fk_default_view_id) + ? await View.getColumns(context, fk_default_view_id, ncMeta) : []; const defaultViewColumnOrderMap = defaultViewColumns.reduce((acc, col) => { @@ -510,14 +537,19 @@ export default class Column implements ColumnType { }, {} as Record); if (!isNoneList && !columnsList.length) { - columnsList = await ncMeta.metaList2(null, null, MetaTable.COLUMNS, { - condition: { - fk_model_id, - }, - orderBy: { - order: 'asc', + columnsList = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.COLUMNS, + { + condition: { + fk_model_id, + }, + orderBy: { + order: 'asc', + }, }, - }); + ); columnsList.forEach((column) => { column.meta = parseMetaProp(column); @@ -542,7 +574,7 @@ export default class Column implements ColumnType { } const column = new Column(m); - await column.getColOptions(ncMeta); + await column.getColOptions(context, ncMeta); return column; }), ); @@ -585,9 +617,8 @@ export default class Column implements ColumnType { } public static async get( + context: NcContext, { - source_id, - db_alias, colId, }: { source_id?: string; @@ -604,8 +635,8 @@ export default class Column implements ColumnType { )); if (!colData) { colData = await ncMeta.metaGet2( - source_id, - db_alias, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, colId, ); @@ -620,7 +651,7 @@ export default class Column implements ColumnType { } if (colData) { const column = new Column(colData); - await column.getColOptions(ncMeta); + await column.getColOptions(context, ncMeta); return column; } return null; @@ -628,8 +659,8 @@ export default class Column implements ColumnType { id: string; - static async delete(id, ncMeta = Noco.ncMeta) { - const col = await this.get({ colId: id }, ncMeta); + static async delete(context: NcContext, id, ncMeta = Noco.ncMeta) { + const col = await this.get(context, { colId: id }, ncMeta); // if column is not found, return if (!col) { @@ -641,29 +672,29 @@ export default class Column implements ColumnType { // get qr code columns and delete { const qrCodeCols = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_QRCODE, { condition: { fk_qr_value_column_id: id }, }, ); for (const qrCodeCol of qrCodeCols) { - await Column.delete(qrCodeCol.fk_column_id, ncMeta); + await Column.delete(context, qrCodeCol.fk_column_id, ncMeta); } } { const barcodeCols = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_BARCODE, { condition: { fk_barcode_value_column_id: id }, }, ); for (const barcodeCol of barcodeCols) { - await Column.delete(barcodeCol.fk_column_id, ncMeta); + await Column.delete(context, barcodeCol.fk_column_id, ncMeta); } } @@ -673,12 +704,17 @@ export default class Column implements ColumnType { let { list: lookups } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !lookups.length) { - lookups = await ncMeta.metaList2(null, null, MetaTable.COL_LOOKUP, { - condition: { fk_lookup_column_id: id }, - }); + lookups = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.COL_LOOKUP, + { + condition: { fk_lookup_column_id: id }, + }, + ); } for (const lookup of lookups) { - await Column.delete(lookup.fk_column_id, ncMeta); + await Column.delete(context, lookup.fk_column_id, ncMeta); } } @@ -688,12 +724,17 @@ export default class Column implements ColumnType { let { list: rollups } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !rollups.length) { - rollups = await ncMeta.metaList2(null, null, MetaTable.COL_ROLLUP, { - condition: { fk_rollup_column_id: id }, - }); + rollups = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.COL_ROLLUP, + { + condition: { fk_rollup_column_id: id }, + }, + ); } for (const rollup of rollups) { - await Column.delete(rollup.fk_column_id, ncMeta); + await Column.delete(context, rollup.fk_column_id, ncMeta); } } @@ -704,19 +745,24 @@ export default class Column implements ColumnType { let { list: formulaColumns } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !formulaColumns.length) { - formulaColumns = await ncMeta.metaList2(null, null, MetaTable.COLUMNS, { - condition: { - fk_model_id: col.fk_model_id, - uidt: UITypes.Formula, + formulaColumns = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.COLUMNS, + { + condition: { + fk_model_id: col.fk_model_id, + uidt: UITypes.Formula, + }, }, - }); + ); } formulaColumns = formulaColumns.filter((c) => c.uidt === UITypes.Formula); for (const formulaCol of formulaColumns) { const formula = await new Column( formulaCol, - ).getColOptions(); + ).getColOptions(context, ncMeta); if ( addFormulaErrorIfMissingColumn({ formula, @@ -725,6 +771,7 @@ export default class Column implements ColumnType { }) ) await FormulaColumn.update( + context, formulaCol.id, formula as FormulaColumn & { parsed_tree?: any }, ncMeta, @@ -740,12 +787,17 @@ export default class Column implements ColumnType { let { list: lookups } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !lookups.length) { - lookups = await ncMeta.metaList2(null, null, MetaTable.COL_LOOKUP, { - condition: { fk_relation_column_id: id }, - }); + lookups = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.COL_LOOKUP, + { + condition: { fk_relation_column_id: id }, + }, + ); } for (const lookup of lookups) { - await Column.delete(lookup.fk_column_id, ncMeta); + await Column.delete(context, lookup.fk_column_id, ncMeta); } } @@ -755,12 +807,17 @@ export default class Column implements ColumnType { let { list: rollups } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !rollups.length) { - rollups = await ncMeta.metaList2(null, null, MetaTable.COL_ROLLUP, { - condition: { fk_relation_column_id: id }, - }); + rollups = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.COL_ROLLUP, + { + condition: { fk_relation_column_id: id }, + }, + ); } for (const rollup of rollups) { - await Column.delete(rollup.fk_column_id, ncMeta); + await Column.delete(context, rollup.fk_column_id, ncMeta); } } } @@ -771,14 +828,19 @@ export default class Column implements ColumnType { let { list: sorts } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !sorts.length) { - sorts = await ncMeta.metaList2(null, null, MetaTable.SORT, { - condition: { - fk_column_id: id, + sorts = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.SORT, + { + condition: { + fk_column_id: id, + }, }, - }); + ); } for (const sort of sorts) { - await Sort.delete(sort.id, ncMeta); + await Sort.delete(context, sort.id, ncMeta); } } // delete filters @@ -787,15 +849,20 @@ export default class Column implements ColumnType { let { list: filters } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !filters.length) { - filters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { - fk_column_id: id, + filters = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { + fk_column_id: id, + }, }, - }); + ); } for (const filter of filters) { if (filter.fk_parent_id) continue; - await Filter.delete(filter.id, ncMeta); + await Filter.delete(context, filter.id, ncMeta); } } @@ -836,9 +903,14 @@ export default class Column implements ColumnType { } if (colOptionTableName && cacheScopeName) { - await ncMeta.metaDelete(null, null, colOptionTableName, { - fk_column_id: col.id, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + colOptionTableName, + { + fk_column_id: col.id, + }, + ); await NocoCache.deepDel( `${cacheScopeName}:${col.id}`, CacheDelDirection.CHILD_TO_PARENT, @@ -862,10 +934,17 @@ export default class Column implements ColumnType { for (let i = 0; i < viewColumnTables.length; i++) { const table = viewColumnTables[i]; const cacheScope = viewColumnCacheScope[i]; - const viewColumns = await ncMeta.metaList2(null, null, table, { - condition: { fk_column_id: id }, + const viewColumns = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + table, + { + condition: { fk_column_id: id }, + }, + ); + await ncMeta.metaDelete(context.workspace_id, context.base_id, table, { + fk_column_id: id, }); - await ncMeta.metaDelete(null, null, table, { fk_column_id: id }); for (const viewColumn of viewColumns) { await NocoCache.deepDel( `${cacheScope}:${viewColumn.id}`, @@ -876,8 +955,8 @@ export default class Column implements ColumnType { // Get LTAR columns in which current column is referenced as foreign key const ltarColumns = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_RELATIONS, { xcCondition: { @@ -893,11 +972,16 @@ export default class Column implements ColumnType { // Delete LTAR columns in which current column is referenced as foreign key for (const ltarColumn of ltarColumns) { - await Column.delete(ltarColumn.fk_column_id, ncMeta); + await Column.delete(context, ltarColumn.fk_column_id, ncMeta); } // Columns - await ncMeta.metaDelete(null, null, MetaTable.COLUMNS, col.id); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COLUMNS, + col.id, + ); await NocoCache.deepDel( `${CacheScope.COLUMN}:${col.id}`, CacheDelDirection.CHILD_TO_PARENT, @@ -905,25 +989,31 @@ export default class Column implements ColumnType { // on column delete, delete any optimised single query cache { - await View.clearSingleQueryCache(col.fk_model_id, null, ncMeta); + await View.clearSingleQueryCache(context, col.fk_model_id, null, ncMeta); } } static async update( + context: NcContext, colId: string, column: Partial & Partial>, ncMeta = Noco.ncMeta, skipFormulaInvalidate = false, ) { - const oldCol = await Column.get({ colId }, ncMeta); + const oldCol = await Column.get(context, { colId }, ncMeta); switch (oldCol.uidt) { case UITypes.Lookup: { // LookupColumn.insert() - await ncMeta.metaDelete(null, null, MetaTable.COL_LOOKUP, { - fk_column_id: colId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COL_LOOKUP, + { + fk_column_id: colId, + }, + ); await NocoCache.deepDel( `${CacheScope.COL_LOOKUP}:${colId}`, CacheDelDirection.CHILD_TO_PARENT, @@ -931,9 +1021,14 @@ export default class Column implements ColumnType { break; } case UITypes.Rollup: { - await ncMeta.metaDelete(null, null, MetaTable.COL_ROLLUP, { - fk_column_id: colId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COL_ROLLUP, + { + fk_column_id: colId, + }, + ); await NocoCache.deepDel( `${CacheScope.COL_ROLLUP}:${colId}`, CacheDelDirection.CHILD_TO_PARENT, @@ -942,9 +1037,14 @@ export default class Column implements ColumnType { } case UITypes.LinkToAnotherRecord: { - await ncMeta.metaDelete(null, null, MetaTable.COL_RELATIONS, { - fk_column_id: colId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COL_RELATIONS, + { + fk_column_id: colId, + }, + ); await NocoCache.deepDel( `${CacheScope.COL_RELATION}:${colId}`, CacheDelDirection.CHILD_TO_PARENT, @@ -952,9 +1052,14 @@ export default class Column implements ColumnType { break; } case UITypes.Formula: { - await ncMeta.metaDelete(null, null, MetaTable.COL_FORMULA, { - fk_column_id: colId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COL_FORMULA, + { + fk_column_id: colId, + }, + ); await NocoCache.deepDel( `${CacheScope.COL_FORMULA}:${colId}`, @@ -963,9 +1068,14 @@ export default class Column implements ColumnType { break; } case UITypes.QrCode: { - await ncMeta.metaDelete(null, null, MetaTable.COL_QRCODE, { - fk_column_id: colId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COL_QRCODE, + { + fk_column_id: colId, + }, + ); await NocoCache.deepDel( `${CacheScope.COL_QRCODE}:${colId}`, @@ -975,9 +1085,14 @@ export default class Column implements ColumnType { } case UITypes.Barcode: { - await ncMeta.metaDelete(null, null, MetaTable.COL_BARCODE, { - fk_column_id: colId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COL_BARCODE, + { + fk_column_id: colId, + }, + ); await NocoCache.deepDel( `${CacheScope.COL_BARCODE}:${colId}`, @@ -988,9 +1103,14 @@ export default class Column implements ColumnType { case UITypes.MultiSelect: case UITypes.SingleSelect: { - await ncMeta.metaDelete(null, null, MetaTable.COL_SELECT_OPTIONS, { - fk_column_id: colId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COL_SELECT_OPTIONS, + { + fk_column_id: colId, + }, + ); await NocoCache.deepDel( `${CacheScope.COL_SELECT_OPTION}:${colId}:list`, @@ -1037,26 +1157,26 @@ export default class Column implements ColumnType { // get qr code columns and delete if target type is not supported by QR code column type if (!AllowedColumnTypesForQrAndBarcodes.includes(updateObj.uidt)) { const qrCodeCols = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_QRCODE, { condition: { fk_qr_value_column_id: colId }, }, ); const barcodeCols = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_BARCODE, { condition: { fk_barcode_value_column_id: colId }, }, ); for (const qrCodeCol of qrCodeCols) { - await Column.delete(qrCodeCol.fk_column_id, ncMeta); + await Column.delete(context, qrCodeCol.fk_column_id, ncMeta); } for (const barcodeCol of barcodeCols) { - await Column.delete(barcodeCol.fk_column_id, ncMeta); + await Column.delete(context, barcodeCol.fk_column_id, ncMeta); } } if ( @@ -1065,9 +1185,10 @@ export default class Column implements ColumnType { column.column_order.view_id ) { const viewColumn = ( - await View.getColumns(column.column_order.view_id, ncMeta) + await View.getColumns(context, column.column_order.view_id, ncMeta) ).find((col) => col.fk_column_id === column.id); await View.updateColumn( + context, column.column_order.view_id, viewColumn.id, { @@ -1079,8 +1200,8 @@ export default class Column implements ColumnType { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, prepareForDb(updateObj), colId, @@ -1091,19 +1212,21 @@ export default class Column implements ColumnType { prepareForResponse(updateObj), ); - await this.insertColOption(column, colId, ncMeta); + await this.insertColOption(context, column, colId, ncMeta); // on column update, delete any optimised single query cache - await View.clearSingleQueryCache(oldCol.fk_model_id, null, ncMeta); + await View.clearSingleQueryCache(context, oldCol.fk_model_id, null, ncMeta); - const updatedColumn = await Column.get({ colId }, ncMeta); + const updatedColumn = await Column.get(context, { colId }, ncMeta); if (!skipFormulaInvalidate) { // invalidate formula parsed-tree in which current column is used // whenever a new request comes for that formula, it will be populated again getFormulasReferredTheColumn( + context, { column: updatedColumn, columns: await Column.list( + context, { fk_model_id: oldCol.fk_model_id }, ncMeta, ), @@ -1113,6 +1236,7 @@ export default class Column implements ColumnType { .then(async (formulas) => { for (const formula of formulas) { await FormulaColumn.update( + context, formula.id, { parsed_tree: null, @@ -1129,14 +1253,15 @@ export default class Column implements ColumnType { } static async updateAlias( + context: NcContext, colId: string, { title }: { title: string }, ncMeta = Noco.ncMeta, ) { // set meta await ncMeta.metaUpdate( - null, //column.base_id || column.source_id, - null, //column.db_alias, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, { title, @@ -1146,9 +1271,9 @@ export default class Column implements ColumnType { await NocoCache.update(`${CacheScope.COLUMN}:${colId}`, { title }); - const column = await Column.get({ colId }, ncMeta); + const column = await Column.get(context, { colId }, ncMeta); - await View.clearSingleQueryCache(column.fk_model_id, null, ncMeta); + await View.clearSingleQueryCache(context, column.fk_model_id, null, ncMeta); } public getValidators(): any { @@ -1159,11 +1284,12 @@ export default class Column implements ColumnType { return null; } - async delete(ncMeta = Noco.ncMeta) { - return await Column.delete(this.id, ncMeta); + async delete(context: NcContext, ncMeta = Noco.ncMeta) { + return await Column.delete(context, this.id, ncMeta); } static async checkTitleAvailable( + context: NcContext, { column_name, fk_model_id, @@ -1172,8 +1298,8 @@ export default class Column implements ColumnType { ncMeta = Noco.ncMeta, ) { return !(await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, { column_name, @@ -1185,12 +1311,13 @@ export default class Column implements ColumnType { } static async checkAliasAvailable( + context: NcContext, { title, fk_model_id, exclude_id }: { title; fk_model_id; exclude_id? }, ncMeta = Noco.ncMeta, ) { return !(await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, { title, @@ -1202,14 +1329,15 @@ export default class Column implements ColumnType { } static async markAsSystemField( + context: NcContext, colId: string, system = true, ncMeta = Noco.ncMeta, ) { // update system field in meta db await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, { system, @@ -1234,13 +1362,14 @@ export default class Column implements ColumnType { } static async updateMeta( + context: NcContext, { colId, meta }: { colId: string; meta: any }, ncMeta = Noco.ncMeta, ) { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, prepareForDb({ meta }), colId, @@ -1253,12 +1382,13 @@ export default class Column implements ColumnType { } static async updateTargetView( + context: NcContext, { colId, fk_target_view_id }: { colId: string; fk_target_view_id: string }, ncMeta = Noco.ncMeta, ) { await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_RELATIONS, { fk_target_view_id, @@ -1274,6 +1404,7 @@ export default class Column implements ColumnType { } static async bulkInsert( + context: NcContext, param: { columns: Column[]; fk_model_id: any; @@ -1343,21 +1474,24 @@ export default class Column implements ColumnType { columns.push(colWithId); } + if (columns.length === 0) return []; + // bulk insert columns await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, extractedColumnMetas, true, ); - await Column.bulkInsertColOption(columns, ncMeta); + await Column.bulkInsertColOption(context, columns, ncMeta); return columns; } private static async bulkInsertColOption( + context: NcContext, columns: (Partial & { source_id?: string; [p: string]: any })[], ncMeta = Noco.ncMeta, ) { @@ -1507,8 +1641,8 @@ export default class Column implements ColumnType { case UITypes.SingleSelect: case UITypes.MultiSelect: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_SELECT_OPTIONS, insertGroups.get(group), ); @@ -1516,8 +1650,8 @@ export default class Column implements ColumnType { case UITypes.Lookup: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_LOOKUP, insertGroups.get(group), ); @@ -1525,8 +1659,8 @@ export default class Column implements ColumnType { case UITypes.Rollup: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_ROLLUP, insertGroups.get(group), ); @@ -1534,32 +1668,32 @@ export default class Column implements ColumnType { case UITypes.Links: case UITypes.LinkToAnotherRecord: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_RELATIONS, insertGroups.get(group), ); break; case UITypes.QrCode: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_QRCODE, insertGroups.get(group), ); break; case UITypes.Barcode: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_BARCODE, insertGroups.get(group), ); break; case UITypes.Formula: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_FORMULA, insertGroups.get(group), ); diff --git a/packages/nocodb/src/models/Comment.ts b/packages/nocodb/src/models/Comment.ts index a0d22b2b15..679877b45d 100644 --- a/packages/nocodb/src/models/Comment.ts +++ b/packages/nocodb/src/models/Comment.ts @@ -1,9 +1,11 @@ import type { CommentType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; import { MetaTable } from '~/utils/globals'; import { prepareForDb } from '~/utils/modelUtils'; import { extractProps } from '~/helpers/extractProps'; import Model from '~/models/Model'; +import { NcError } from '~/helpers/catchError'; export default class Comment implements CommentType { id?: string; @@ -12,6 +14,7 @@ export default class Comment implements CommentType { comment?: string; parent_comment_id?: string; source_id?: string; + fk_workspace_id?: string; base_id?: string; created_by?: string; resolved_by?: string; @@ -23,10 +26,14 @@ export default class Comment implements CommentType { Object.assign(this, comment); } - public static async get(commentId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + commentId: string, + ncMeta = Noco.ncMeta, + ) { const comment = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COMMENTS, commentId, ); @@ -35,6 +42,7 @@ export default class Comment implements CommentType { } public static async list( + context: NcContext, { row_id, fk_model_id, @@ -57,7 +65,11 @@ export default class Comment implements CommentType { return commentList.map((comment) => new Comment(comment)); } - public static async insert(comment: Partial, ncMeta = Noco.ncMeta) { + public static async insert( + context: NcContext, + comment: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = extractProps(comment, [ 'id', 'fk_model_id', @@ -71,19 +83,20 @@ export default class Comment implements CommentType { 'created_by_email', ]); - if ((!insertObj.base_id || !insertObj.source_id) && insertObj.fk_model_id) { + if (!insertObj.fk_model_id) NcError.tableNotFound(insertObj.fk_model_id); + + if (!insertObj.source_id) { const model = await Model.getByIdOrName( + context, { id: insertObj.fk_model_id }, ncMeta, ); - - insertObj.base_id = model.base_id; insertObj.source_id = model.source_id; } const res = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COMMENTS, prepareForDb(insertObj), ); @@ -91,6 +104,7 @@ export default class Comment implements CommentType { return res; } public static async update( + context: NcContext, commentId: string, comment: Partial, ncMeta = Noco.ncMeta, @@ -102,20 +116,24 @@ export default class Comment implements CommentType { ]); await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COMMENTS, prepareForDb(updateObj), commentId, ); - return Comment.get(commentId, ncMeta); + return Comment.get(context, commentId, ncMeta); } - static async delete(commentId: string, ncMeta = Noco.ncMeta) { + static async delete( + context: NcContext, + commentId: string, + ncMeta = Noco.ncMeta, + ) { await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COMMENTS, { is_deleted: true }, commentId, @@ -124,10 +142,14 @@ export default class Comment implements CommentType { return true; } - static async deleteRowComments(fk_model_id: string, ncMeta = Noco.ncMeta) { + static async deleteRowComments( + context: NcContext, + fk_model_id: string, + ncMeta = Noco.ncMeta, + ) { return ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COMMENTS, { is_deleted: true, @@ -138,10 +160,13 @@ export default class Comment implements CommentType { ); } - public static async commentsCount(args: { - ids: string[]; - fk_model_id: string; - }) { + public static async commentsCount( + context: NcContext, + args: { + ids: string[]; + fk_model_id: string; + }, + ) { const audits = await Noco.ncMeta .knex(MetaTable.COMMENTS) .count('id', { as: 'count' }) diff --git a/packages/nocodb/src/models/Extension.ts b/packages/nocodb/src/models/Extension.ts index ebf3fe06fa..9af5928c47 100644 --- a/packages/nocodb/src/models/Extension.ts +++ b/packages/nocodb/src/models/Extension.ts @@ -1,3 +1,4 @@ +import type { NcContext } from '~/interface/config'; import { prepareForDb, prepareForResponse } from '~/utils/modelUtils'; import Noco from '~/Noco'; import { extractProps } from '~/helpers/extractProps'; @@ -11,6 +12,7 @@ import NocoCache from '~/cache/NocoCache'; export default class Extension { id?: string; + fk_workspace_id?: string; base_id?: string; fk_user_id?: string; extension_id?: string; @@ -23,7 +25,11 @@ export default class Extension { Object.assign(this, extension); } - public static async get(extensionId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + extensionId: string, + ncMeta = Noco.ncMeta, + ) { let extension = await NocoCache.get( `${CacheScope.EXTENSION}:${extensionId}`, CacheGetType.TYPE_OBJECT, @@ -31,8 +37,8 @@ export default class Extension { if (!extension) { extension = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.EXTENSIONS, extensionId, ); @@ -46,19 +52,24 @@ export default class Extension { return extension && new Extension(extension); } - static async list(baseId: string, ncMeta = Noco.ncMeta) { + static async list(context: NcContext, baseId: string, ncMeta = Noco.ncMeta) { const cachedList = await NocoCache.getList(CacheScope.EXTENSION, [baseId]); let { list: extensionList } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !extensionList.length) { - extensionList = await ncMeta.metaList(null, null, MetaTable.EXTENSIONS, { - condition: { - base_id: baseId, - }, - orderBy: { - created_at: 'asc', + extensionList = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.EXTENSIONS, + { + condition: { + base_id: baseId, + }, + orderBy: { + created_at: 'asc', + }, }, - }); + ); if (extensionList) { extensionList = extensionList.map((extension) => @@ -74,6 +85,7 @@ export default class Extension { } public static async insert( + context: NcContext, extension: Partial, ncMeta = Noco.ncMeta, ) { @@ -95,13 +107,13 @@ export default class Extension { } const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.EXTENSIONS, prepareForDb(insertObj, ['kv_store', 'meta']), ); - return this.get(id, ncMeta).then(async (res) => { + return this.get(context, id, ncMeta).then(async (res) => { await NocoCache.appendToList( CacheScope.EXTENSION, [extension.base_id], @@ -112,12 +124,12 @@ export default class Extension { } public static async update( + context: NcContext, extensionId: string, extension: Partial, ncMeta = Noco.ncMeta, ) { const updateObj = extractProps(extension, [ - 'base_id', 'fk_user_id', 'extension_id', 'title', @@ -128,8 +140,8 @@ export default class Extension { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.EXTENSIONS, prepareForDb(updateObj, ['kv_store', 'meta']), extensionId, @@ -140,13 +152,17 @@ export default class Extension { prepareForResponse(updateObj, ['kv_store', 'meta']), ); - return this.get(extensionId, ncMeta); + return this.get(context, extensionId, ncMeta); } - static async delete(extensionId: any, ncMeta = Noco.ncMeta) { + static async delete( + context: NcContext, + extensionId: any, + ncMeta = Noco.ncMeta, + ) { const res = await ncMeta.metaDelete( - null, - null, + context.workspace_id, + context.base_id, MetaTable.EXTENSIONS, extensionId, ); diff --git a/packages/nocodb/src/models/Filter.ts b/packages/nocodb/src/models/Filter.ts index d97449dd06..216b70c787 100644 --- a/packages/nocodb/src/models/Filter.ts +++ b/packages/nocodb/src/models/Filter.ts @@ -1,6 +1,7 @@ import { UITypes } from 'nocodb-sdk'; import type { BoolType, FilterType } from 'nocodb-sdk'; import type { COMPARISON_OPS, COMPARISON_SUB_OPS } from '~/utils/globals'; +import type { NcContext } from '~/interface/config'; import Model from '~/models/Model'; import Column from '~/models/Column'; import Hook from '~/models/Hook'; @@ -19,6 +20,7 @@ import { extractProps } from '~/helpers/extractProps'; export default class Filter implements FilterType { id: string; + fk_workspace_id?: string; fk_model_id?: string; fk_view_id?: string; fk_hook_id?: string; @@ -51,10 +53,17 @@ export default class Filter implements FilterType { return filter && new Filter(filter); } - public async getModel(ncMeta = Noco.ncMeta): Promise { + public async getModel( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return this.fk_view_id - ? (await View.get(this.fk_view_id, ncMeta)).getModel(ncMeta) + ? (await View.get(context, this.fk_view_id, ncMeta)).getModel( + context, + ncMeta, + ) : Model.getByIdOrName( + context, { id: this.fk_model_id, }, @@ -63,6 +72,7 @@ export default class Filter implements FilterType { } public static async insert( + context: NcContext, filter: Partial & { order?: number }, ncMeta = Noco.ncMeta, ) { @@ -94,29 +104,36 @@ export default class Filter implements FilterType { [referencedModelColName]: filter[referencedModelColName], }); - if (!(filter.base_id && filter.source_id)) { + if (!filter.source_id) { let model: { base_id?: string; source_id?: string }; if (filter.fk_view_id) { - model = await View.get(filter.fk_view_id, ncMeta); + model = await View.get(context, filter.fk_view_id, ncMeta); } else if (filter.fk_hook_id) { - model = await Hook.get(filter.fk_hook_id, ncMeta); + model = await Hook.get(context, filter.fk_hook_id, ncMeta); } else if (filter.fk_link_col_id) { - model = await Column.get({ colId: filter.fk_link_col_id }, ncMeta); + model = await Column.get( + context, + { colId: filter.fk_link_col_id }, + ncMeta, + ); } else if (filter.fk_column_id) { - model = await Column.get({ colId: filter.fk_column_id }, ncMeta); + model = await Column.get( + context, + { colId: filter.fk_column_id }, + ncMeta, + ); } else { NcError.invalidFilter(JSON.stringify(filter)); } if (model != null) { - insertObj.base_id = model.base_id; insertObj.source_id = model.source_id; } } const row = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FILTER_EXP, insertObj, ); @@ -124,6 +141,7 @@ export default class Filter implements FilterType { await Promise.all( filter.children.map((f) => this.insert( + context, { ...f, fk_parent_id: row.id, @@ -134,10 +152,11 @@ export default class Filter implements FilterType { ), ); } - return await this.redisPostInsert(row.id, filter, ncMeta); + return await this.redisPostInsert(context, row.id, filter, ncMeta); } static async redisPostInsert( + context: NcContext, id, filter: Partial, ncMeta = Noco.ncMeta, @@ -151,7 +170,12 @@ export default class Filter implements FilterType { let value = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); if (!value) { /* get from db */ - value = await ncMeta.metaGet2(null, null, MetaTable.FILTER_EXP, id); + value = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + id, + ); /* store in redis */ await NocoCache.set(key, value).then(async () => { @@ -219,16 +243,26 @@ export default class Filter implements FilterType { { // if not a view filter then no need to delete if (filter.fk_view_id) { - const view = await View.get(filter.fk_view_id, ncMeta); + const view = await View.get(context, filter.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } } return this.castType(value); } - static async update(id, filter: Partial, ncMeta = Noco.ncMeta) { + static async update( + context: NcContext, + id, + filter: Partial, + ncMeta = Noco.ncMeta, + ) { const updateObj = extractProps(filter, [ 'fk_column_id', 'comparison_op', @@ -245,8 +279,8 @@ export default class Filter implements FilterType { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FILTER_EXP, updateObj, id, @@ -256,11 +290,12 @@ export default class Filter implements FilterType { // on update delete any optimised single query cache { - const filter = await this.get(id, ncMeta); + const filter = await this.get(context, id, ncMeta); // if not a view filter then no need to delete if (filter.fk_view_id) { - const view = await View.get(filter.fk_view_id, ncMeta); + const view = await View.get(context, filter.fk_view_id, ncMeta); await View.clearSingleQueryCache( + context, view.fk_model_id, [{ id: filter.fk_view_id }], ncMeta, @@ -271,14 +306,19 @@ export default class Filter implements FilterType { return res; } - static async delete(id: string, ncMeta = Noco.ncMeta) { - const filter = await this.get(id, ncMeta); + static async delete(context: NcContext, id: string, ncMeta = Noco.ncMeta) { + const filter = await this.get(context, id, ncMeta); const deleteRecursively = async (filter: Filter) => { if (!filter) return; - for (const f of (await filter?.getChildren()) || []) + for (const f of (await filter?.getChildren(context, ncMeta)) || []) await deleteRecursively(f); - await ncMeta.metaDelete(null, null, MetaTable.FILTER_EXP, filter.id); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + filter.id, + ); await NocoCache.deepDel( `${CacheScope.FILTER_EXP}:${filter.id}`, CacheDelDirection.CHILD_TO_PARENT, @@ -290,9 +330,10 @@ export default class Filter implements FilterType { { // if not a view filter then no need to delete if (filter.fk_view_id) { - const view = await View.get(filter.fk_view_id, ncMeta); + const view = await View.get(context, filter.fk_view_id, ncMeta); await View.clearSingleQueryCache( + context, view.fk_model_id, [{ id: filter.fk_view_id }], ncMeta, @@ -301,23 +342,35 @@ export default class Filter implements FilterType { } } - public getColumn(): Promise { + public getColumn(context: NcContext, ncMeta = Noco.ncMeta): Promise { if (!this.fk_column_id) return null; - return Column.get({ - colId: this.fk_column_id, - }); + return Column.get( + context, + { + colId: this.fk_column_id, + }, + ncMeta, + ); } - public async getGroup(ncMeta = Noco.ncMeta): Promise { + public async getGroup( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { if (!this.fk_parent_id) return null; let filterObj = await NocoCache.get( `${CacheScope.FILTER_EXP}:${this.fk_parent_id}`, 2, ); if (!filterObj) { - filterObj = await ncMeta.metaGet2(null, null, MetaTable.FILTER_EXP, { - id: this.fk_parent_id, - }); + filterObj = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + id: this.fk_parent_id, + }, + ); await NocoCache.set( `${CacheScope.FILTER_EXP}:${this.fk_parent_id}`, filterObj, @@ -326,7 +379,10 @@ export default class Filter implements FilterType { return this.castType(filterObj); } - public async getChildren(ncMeta = Noco.ncMeta): Promise { + public async getChildren( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { if (this.children) return this.children; if (!this.is_group) return null; const cachedList = await NocoCache.getList(CacheScope.FILTER_EXP, [ @@ -335,14 +391,19 @@ export default class Filter implements FilterType { let { list: childFilters } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !childFilters.length) { - childFilters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { - fk_parent_id: this.id, - }, - orderBy: { - order: 'asc', + childFilters = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { + fk_parent_id: this.id, + }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.FILTER_EXP, [this.id], childFilters); } return childFilters && childFilters.map((f) => this.castType(f)); @@ -356,8 +417,8 @@ export default class Filter implements FilterType { // if (!viewId) return null; // // const filterObj = await ncMeta.metaGet2( - // null, - // null, + // context.workspace_id, + // context.base_id, // MetaTable.FILTER_EXP, // { fk_view_id: viewId, fk_parent_id: null } // ); @@ -365,6 +426,7 @@ export default class Filter implements FilterType { // } public static async getFilterObject( + context: NcContext, { viewId, hookId, @@ -392,12 +454,17 @@ export default class Filter implements FilterType { condition.fk_link_col_id = linkColId; } - filters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition, - orderBy: { - order: 'asc', + filters = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList( CacheScope.FILTER_EXP, @@ -423,7 +490,7 @@ export default class Filter implements FilterType { grouped[filter._fk_parent_id] = grouped[filter._fk_parent_id] || []; grouped[filter._fk_parent_id].push(filter); idFilterMapping[filter.id] = filter; - filter.column = await new Filter(filter).getColumn(); + filter.column = await new Filter(filter).getColumn(context, ncMeta); if (filter.column?.uidt === UITypes.LinkToAnotherRecord) { } } @@ -436,14 +503,23 @@ export default class Filter implements FilterType { return result; } - static async deleteAll(viewId: string, ncMeta = Noco.ncMeta) { - const filter = await this.getFilterObject({ viewId }, ncMeta); + static async deleteAll( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { + const filter = await this.getFilterObject(context, { viewId }, ncMeta); const deleteRecursively = async (filter) => { if (!filter) return; for (const f of filter?.children || []) await deleteRecursively(f); if (filter.id) { - await ncMeta.metaDelete(null, null, MetaTable.FILTER_EXP, filter.id); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + filter.id, + ); await NocoCache.deepDel( `${CacheScope.FILTER_EXP}:${filter.id}`, CacheDelDirection.CHILD_TO_PARENT, @@ -454,19 +530,33 @@ export default class Filter implements FilterType { // on update delete any optimised single query cache { - const view = await View.get(viewId, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const view = await View.get(context, viewId, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } } - static async deleteAllByHook(hookId: string, ncMeta = Noco.ncMeta) { - const filter = await this.getFilterObject({ hookId }, ncMeta); + static async deleteAllByHook( + context: NcContext, + hookId: string, + ncMeta = Noco.ncMeta, + ) { + const filter = await this.getFilterObject(context, { hookId }, ncMeta); const deleteRecursively = async (filter) => { if (!filter) return; for (const f of filter?.children || []) await deleteRecursively(f); if (filter.id) { - await ncMeta.metaDelete(null, null, MetaTable.FILTER_EXP, filter.id); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + filter.id, + ); await NocoCache.deepDel( `${CacheScope.FILTER_EXP}:${filter.id}`, CacheDelDirection.CHILD_TO_PARENT, @@ -476,7 +566,11 @@ export default class Filter implements FilterType { await deleteRecursively(filter); } - public static async get(id: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + id: string, + ncMeta = Noco.ncMeta, + ) { let filterObj = id && (await NocoCache.get( @@ -484,15 +578,21 @@ export default class Filter implements FilterType { CacheGetType.TYPE_OBJECT, )); if (!filterObj) { - filterObj = await ncMeta.metaGet2(null, null, MetaTable.FILTER_EXP, { - id, - }); + filterObj = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + id, + }, + ); await NocoCache.set(`${CacheScope.FILTER_EXP}:${id}`, filterObj); } return this.castType(filterObj); } static async rootFilterList( + context: NcContext, { viewId }: { viewId: any }, ncMeta = Noco.ncMeta, ) { @@ -500,12 +600,17 @@ export default class Filter implements FilterType { let { list: filterObjs } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !filterObjs.length) { - filterObjs = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { fk_view_id: viewId }, - orderBy: { - order: 'asc', + filterObjs = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { fk_view_id: viewId }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.FILTER_EXP, [viewId], filterObjs); } return filterObjs @@ -514,6 +619,7 @@ export default class Filter implements FilterType { } static async rootFilterListByHook( + context: NcContext, { hookId }: { hookId: any }, ncMeta = Noco.ncMeta, ) { @@ -521,12 +627,17 @@ export default class Filter implements FilterType { let { list: filterObjs } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !filterObjs.length) { - filterObjs = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { fk_hook_id: hookId }, - orderBy: { - order: 'asc', + filterObjs = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { fk_hook_id: hookId }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.FILTER_EXP, [hookId], filterObjs); } return filterObjs @@ -535,6 +646,7 @@ export default class Filter implements FilterType { } static async parentFilterList( + context: NcContext, { parentId, }: { @@ -548,21 +660,27 @@ export default class Filter implements FilterType { let { list: filterObjs } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !filterObjs.length) { - filterObjs = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { - fk_parent_id: parentId, - // fk_view_id: viewId, - }, - orderBy: { - order: 'asc', + filterObjs = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { + fk_parent_id: parentId, + // fk_view_id: viewId, + }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.FILTER_EXP, [parentId], filterObjs); } return filterObjs?.map((f) => this.castType(f)); } static async parentFilterListByHook( + context: NcContext, { hookId, parentId, @@ -579,15 +697,20 @@ export default class Filter implements FilterType { let { list: filterObjs } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !filterObjs.length) { - filterObjs = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { - fk_parent_id: parentId, - fk_hook_id: hookId, - }, - orderBy: { - order: 'asc', + filterObjs = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { + fk_parent_id: parentId, + fk_hook_id: hookId, + }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList( CacheScope.FILTER_EXP, [hookId, parentId], @@ -597,10 +720,14 @@ export default class Filter implements FilterType { return filterObjs?.map((f) => this.castType(f)); } - static async hasEmptyOrNullFilters(baseId: string, ncMeta = Noco.ncMeta) { + static async hasEmptyOrNullFilters( + context: NcContext, + baseId: string, + ncMeta = Noco.ncMeta, + ) { const emptyOrNullFilterObjs = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FILTER_EXP, { condition: { @@ -636,6 +763,7 @@ export default class Filter implements FilterType { } static async rootFilterListByLink( + _context: NcContext, { columnId: _columnId }: { columnId: any }, _ncMeta = Noco.ncMeta, ) { diff --git a/packages/nocodb/src/models/FormView.ts b/packages/nocodb/src/models/FormView.ts index 14939f29d1..3f5f672469 100644 --- a/packages/nocodb/src/models/FormView.ts +++ b/packages/nocodb/src/models/FormView.ts @@ -4,6 +4,7 @@ import type { FormType, MetaType, } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import { PresignedUrl } from '~/models'; import FormViewColumn from '~/models/FormViewColumn'; import View from '~/models/View'; @@ -37,6 +38,7 @@ export default class FormView implements FormViewType { fk_view_id: string; columns?: FormViewColumn[]; + fk_workspace_id?: string; base_id?: string; source_id?: string; meta?: MetaType; @@ -45,7 +47,11 @@ export default class FormView implements FormViewType { Object.assign(this, data); } - public static async get(viewId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { let view = viewId && (await NocoCache.get( @@ -53,9 +59,14 @@ export default class FormView implements FormViewType { CacheGetType.TYPE_OBJECT, )); if (!view) { - view = await ncMeta.metaGet2(null, null, MetaTable.FORM_VIEW, { - fk_view_id: viewId, - }); + view = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.FORM_VIEW, + { + fk_view_id: viewId, + }, + ); if (view) { view.meta = deserializeJSON(view.meta); @@ -74,7 +85,11 @@ export default class FormView implements FormViewType { return view && new FormView(view); } - static async insert(view: Partial, ncMeta = Noco.ncMeta) { + static async insert( + context: NcContext, + view: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = extractProps(view, [ 'fk_view_id', 'base_id', @@ -105,17 +120,24 @@ export default class FormView implements FormViewType { ); } - if (!(view.base_id && view.source_id)) { - const viewRef = await View.get(view.fk_view_id); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, view.fk_view_id, ncMeta); + + if (!view.source_id) { insertObj.source_id = viewRef.source_id; } - await ncMeta.metaInsert2(null, null, MetaTable.FORM_VIEW, insertObj, true); + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.FORM_VIEW, + insertObj, + true, + ); - return this.get(view.fk_view_id, ncMeta); + return this.get(context, view.fk_view_id, ncMeta); } static async update( + context: NcContext, formId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -146,8 +168,8 @@ export default class FormView implements FormViewType { // update meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FORM_VIEW, prepareForDb(updateObj), { @@ -163,13 +185,21 @@ export default class FormView implements FormViewType { return res; } - async getColumns(ncMeta = Noco.ncMeta) { - return (this.columns = await FormViewColumn.list(this.fk_view_id, ncMeta)); + async getColumns(context: NcContext, ncMeta = Noco.ncMeta) { + return (this.columns = await FormViewColumn.list( + context, + this.fk_view_id, + ncMeta, + )); } - static async getWithInfo(formViewId: string, ncMeta = Noco.ncMeta) { - const form = await this.get(formViewId, ncMeta); - await form.getColumns(ncMeta); + static async getWithInfo( + context: NcContext, + formViewId: string, + ncMeta = Noco.ncMeta, + ) { + const form = await this.get(context, formViewId, ncMeta); + await form.getColumns(context, ncMeta); return form; } diff --git a/packages/nocodb/src/models/FormViewColumn.ts b/packages/nocodb/src/models/FormViewColumn.ts index 5265dbc794..634dbc4da3 100644 --- a/packages/nocodb/src/models/FormViewColumn.ts +++ b/packages/nocodb/src/models/FormViewColumn.ts @@ -4,6 +4,7 @@ import type { MetaType, StringOrNullType, } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -16,6 +17,7 @@ export default class FormViewColumn implements FormColumnType { id?: string; fk_view_id?: string; fk_column_id?: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; label?: StringOrNullType; @@ -32,7 +34,11 @@ export default class FormViewColumn implements FormColumnType { Object.assign(this, data); } - public static async get(formViewColumnId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + formViewColumnId: string, + ncMeta = Noco.ncMeta, + ) { let viewColumn = formViewColumnId && (await NocoCache.get( @@ -41,8 +47,8 @@ export default class FormViewColumn implements FormColumnType { )); if (!viewColumn) { viewColumn = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FORM_VIEW_COLUMNS, formViewColumnId, ); @@ -60,7 +66,11 @@ export default class FormViewColumn implements FormColumnType { return viewColumn && new FormViewColumn(viewColumn); } - static async insert(column: Partial, ncMeta = Noco.ncMeta) { + static async insert( + context: NcContext, + column: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = extractProps(column, [ 'fk_view_id', 'fk_column_id', @@ -86,20 +96,20 @@ export default class FormViewColumn implements FormColumnType { insertObj.meta = serializeJSON(insertObj.meta); } - if (!(insertObj.base_id && insertObj.source_id)) { - const viewRef = await View.get(insertObj.fk_view_id, ncMeta); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FORM_VIEW_COLUMNS, insertObj, ); - return this.get(id, ncMeta).then(async (viewColumn) => { + return this.get(context, id, ncMeta).then(async (viewColumn) => { await NocoCache.appendToList( CacheScope.FORM_VIEW_COLUMN, [column.fk_view_id], @@ -110,6 +120,7 @@ export default class FormViewColumn implements FormColumnType { } public static async list( + context: NcContext, viewId: string, ncMeta = Noco.ncMeta, ): Promise { @@ -120,8 +131,8 @@ export default class FormViewColumn implements FormColumnType { const { isNoneList } = cachedList; if (!isNoneList && !viewColumns.length) { viewColumns = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FORM_VIEW_COLUMNS, { condition: { @@ -152,6 +163,7 @@ export default class FormViewColumn implements FormColumnType { } static async update( + context: NcContext, columnId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -169,8 +181,8 @@ export default class FormViewColumn implements FormColumnType { // update meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FORM_VIEW_COLUMNS, prepareForDb(updateObj), columnId, diff --git a/packages/nocodb/src/models/FormulaColumn.ts b/packages/nocodb/src/models/FormulaColumn.ts index 40ea7aa76c..041e98008f 100644 --- a/packages/nocodb/src/models/FormulaColumn.ts +++ b/packages/nocodb/src/models/FormulaColumn.ts @@ -1,3 +1,4 @@ +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; import { extractProps } from '~/helpers/extractProps'; @@ -7,6 +8,8 @@ import { parseMetaProp, stringifyMetaProp } from '~/utils/modelUtils'; export default class FormulaColumn { formula: string; formula_raw: string; + fk_workspace_id?: string; + base_id?: string; fk_column_id: string; error: string; private parsed_tree?: any; @@ -18,6 +21,7 @@ export default class FormulaColumn { } public static async insert( + context: NcContext, formulaColumn: Partial & { parsed_tree?: any }, ncMeta = Noco.ncMeta, ) { @@ -31,12 +35,21 @@ export default class FormulaColumn { insertObj.parsed_tree = stringifyMetaProp(insertObj, 'parsed_tree'); - await ncMeta.metaInsert2(null, null, MetaTable.COL_FORMULA, insertObj); + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.COL_FORMULA, + insertObj, + ); - return this.read(formulaColumn.fk_column_id, ncMeta); + return this.read(context, formulaColumn.fk_column_id, ncMeta); } - public static async read(columnId: string, ncMeta = Noco.ncMeta) { + public static async read( + context: NcContext, + columnId: string, + ncMeta = Noco.ncMeta, + ) { let column = columnId && (await NocoCache.get( @@ -45,8 +58,8 @@ export default class FormulaColumn { )); if (!column) { column = await ncMeta.metaGet2( - null, //, - null, //model.db_alias, + context.workspace_id, + context.base_id, MetaTable.COL_FORMULA, { fk_column_id: columnId }, ); @@ -62,6 +75,7 @@ export default class FormulaColumn { id: string; static async update( + context: NcContext, columnId: string, formula: Partial & { parsed_tree?: any }, ncMeta = Noco.ncMeta, @@ -77,9 +91,15 @@ export default class FormulaColumn { if ('parsed_tree' in updateObj) updateObj.parsed_tree = stringifyMetaProp(updateObj, 'parsed_tree'); // set meta - await ncMeta.metaUpdate(null, null, MetaTable.COL_FORMULA, updateObj, { - fk_column_id: columnId, - }); + await ncMeta.metaUpdate( + context.workspace_id, + context.base_id, + MetaTable.COL_FORMULA, + updateObj, + { + fk_column_id: columnId, + }, + ); await NocoCache.update(`${CacheScope.COL_FORMULA}:${columnId}`, updateObj); } diff --git a/packages/nocodb/src/models/GalleryView.ts b/packages/nocodb/src/models/GalleryView.ts index 10b69e1631..bfea75a083 100644 --- a/packages/nocodb/src/models/GalleryView.ts +++ b/packages/nocodb/src/models/GalleryView.ts @@ -5,6 +5,7 @@ import type { GalleryType, MetaType, } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -28,6 +29,7 @@ export default class GalleryView implements GalleryType { show_all_fields?: BoolType; fk_cover_image_col_id?: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; @@ -38,7 +40,11 @@ export default class GalleryView implements GalleryType { Object.assign(this, data); } - public static async get(viewId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { let view = viewId && (await NocoCache.get( @@ -46,19 +52,28 @@ export default class GalleryView implements GalleryType { CacheGetType.TYPE_OBJECT, )); if (!view) { - view = await ncMeta.metaGet2(null, null, MetaTable.GALLERY_VIEW, { - fk_view_id: viewId, - }); + view = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.GALLERY_VIEW, + { + fk_view_id: viewId, + }, + ); await NocoCache.set(`${CacheScope.GALLERY_VIEW}:${viewId}`, view); } return view && new GalleryView(view); } - static async insert(view: Partial, ncMeta = Noco.ncMeta) { - const columns = await View.get(view.fk_view_id, ncMeta) - .then((v) => v?.getModel(ncMeta)) - .then((m) => m.getColumns(ncMeta)); + static async insert( + context: NcContext, + view: Partial, + ncMeta = Noco.ncMeta, + ) { + const columns = await View.get(context, view.fk_view_id, ncMeta) + .then((v) => v?.getModel(context, ncMeta)) + .then((m) => m.getColumns(context, ncMeta)); const insertObj = extractProps(view, [ 'base_id', @@ -77,24 +92,25 @@ export default class GalleryView implements GalleryType { view?.fk_cover_image_col_id || columns?.find((c) => c.uidt === UITypes.Attachment)?.id; - if (!(view.base_id && view.source_id)) { - const viewRef = await View.get(view.fk_view_id); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GALLERY_VIEW, insertObj, true, ); - return this.get(view.fk_view_id, ncMeta); + return this.get(context, view.fk_view_id, ncMeta); } static async update( + context: NcContext, galleryId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -103,8 +119,8 @@ export default class GalleryView implements GalleryType { // update meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GALLERY_VIEW, prepareForDb(updateObj), { @@ -117,10 +133,11 @@ export default class GalleryView implements GalleryType { prepareForResponse(updateObj), ); - const view = await View.get(galleryId); + const view = await View.get(context, galleryId, ncMeta); // on update, delete any optimised single query cache await View.clearSingleQueryCache( + context, view.fk_model_id, [{ id: galleryId }], ncMeta, diff --git a/packages/nocodb/src/models/GalleryViewColumn.ts b/packages/nocodb/src/models/GalleryViewColumn.ts index 3ae4319811..1c80bde4a5 100644 --- a/packages/nocodb/src/models/GalleryViewColumn.ts +++ b/packages/nocodb/src/models/GalleryViewColumn.ts @@ -1,4 +1,5 @@ import type { BoolType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -13,6 +14,7 @@ export default class GalleryViewColumn { fk_view_id: string; fk_column_id: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; @@ -20,7 +22,11 @@ export default class GalleryViewColumn { Object.assign(this, data); } - public static async get(galleryViewColumnId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + galleryViewColumnId: string, + ncMeta = Noco.ncMeta, + ) { let view = galleryViewColumnId && (await NocoCache.get( @@ -29,8 +35,8 @@ export default class GalleryViewColumn { )); if (!view) { view = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GALLERY_VIEW_COLUMNS, galleryViewColumnId, ); @@ -42,6 +48,7 @@ export default class GalleryViewColumn { return view && new GalleryViewColumn(view); } static async insert( + context: NcContext, column: Partial, ncMeta = Noco.ncMeta, ) { @@ -60,26 +67,31 @@ export default class GalleryViewColumn { }, ); - if (!(column.base_id && column.source_id)) { - const viewRef = await View.get(column.fk_view_id, ncMeta); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GALLERY_VIEW_COLUMNS, insertObj, ); // on new view column, delete any optimised single query cache { - const view = await View.get(column.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const view = await View.get(context, column.fk_view_id, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } - return this.get(id, ncMeta).then(async (viewColumn) => { + return this.get(context, id, ncMeta).then(async (viewColumn) => { await NocoCache.appendToList( CacheScope.GALLERY_VIEW_COLUMN, [column.fk_view_id], @@ -90,6 +102,7 @@ export default class GalleryViewColumn { } public static async list( + context: NcContext, viewId: string, ncMeta = Noco.ncMeta, ): Promise { @@ -100,8 +113,8 @@ export default class GalleryViewColumn { const { isNoneList } = cachedList; if (!isNoneList && !views.length) { views = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GALLERY_VIEW_COLUMNS, { condition: { @@ -123,6 +136,7 @@ export default class GalleryViewColumn { } static async update( + context: NcContext, columnId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -131,8 +145,8 @@ export default class GalleryViewColumn { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GALLERY_VIEW_COLUMNS, updateObj, columnId, @@ -144,9 +158,9 @@ export default class GalleryViewColumn { // on view column update, delete any optimised single query cache { - const viewCol = await this.get(columnId, ncMeta); - const view = await View.get(viewCol.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view]); + const viewCol = await this.get(context, columnId, ncMeta); + const view = await View.get(context, viewCol.fk_view_id, ncMeta); + await View.clearSingleQueryCache(context, view.fk_model_id, [view]); } return res; diff --git a/packages/nocodb/src/models/GridView.ts b/packages/nocodb/src/models/GridView.ts index de20ff83ec..025e942121 100644 --- a/packages/nocodb/src/models/GridView.ts +++ b/packages/nocodb/src/models/GridView.ts @@ -1,4 +1,5 @@ import type { GridType, MetaType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import GridViewColumn from '~/models/GridViewColumn'; import View from '~/models/View'; import Noco from '~/Noco'; @@ -9,6 +10,7 @@ import { prepareForDb, prepareForResponse } from '~/utils/modelUtils'; export default class GridView implements GridType { fk_view_id: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; meta?: MetaType; @@ -19,11 +21,15 @@ export default class GridView implements GridType { Object.assign(this, data); } - async getColumns(): Promise { - return (this.columns = await GridViewColumn.list(this.fk_view_id)); + async getColumns(context: NcContext): Promise { + return (this.columns = await GridViewColumn.list(context, this.fk_view_id)); } - public static async get(viewId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { let view = viewId && (await NocoCache.get( @@ -31,16 +37,25 @@ export default class GridView implements GridType { CacheGetType.TYPE_OBJECT, )); if (!view) { - view = await ncMeta.metaGet2(null, null, MetaTable.GRID_VIEW, { - fk_view_id: viewId, - }); + view = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.GRID_VIEW, + { + fk_view_id: viewId, + }, + ); await NocoCache.set(`${CacheScope.GRID_VIEW}:${viewId}`, view); } return view && new GridView(view); } - static async insert(view: Partial, ncMeta = Noco.ncMeta) { + static async insert( + context: NcContext, + view: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = extractProps(view, [ 'fk_view_id', 'base_id', @@ -48,23 +63,34 @@ export default class GridView implements GridType { 'row_height', ]); - if (!(insertObj.base_id && insertObj.source_id)) { - const viewRef = await View.get(insertObj.fk_view_id, ncMeta); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } - await ncMeta.metaInsert2(null, null, MetaTable.GRID_VIEW, insertObj, true); + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.GRID_VIEW, + insertObj, + true, + ); - return this.get(view.fk_view_id, ncMeta); + return this.get(context, view.fk_view_id, ncMeta); } - static async getWithInfo(id: string, ncMeta = Noco.ncMeta) { - const view = await this.get(id, ncMeta); + static async getWithInfo( + context: NcContext, + id: string, + ncMeta = Noco.ncMeta, + ) { + const view = await this.get(context, id, ncMeta); return view; } static async update( + context: NcContext, viewId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -73,8 +99,8 @@ export default class GridView implements GridType { // update meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW, prepareForDb(updateObj), { diff --git a/packages/nocodb/src/models/GridViewColumn.ts b/packages/nocodb/src/models/GridViewColumn.ts index e0528f5e43..37b6d53c4c 100644 --- a/packages/nocodb/src/models/GridViewColumn.ts +++ b/packages/nocodb/src/models/GridViewColumn.ts @@ -1,4 +1,5 @@ import type { BoolType, GridColumnType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import { extractProps } from '~/helpers/extractProps'; @@ -13,6 +14,7 @@ export default class GridViewColumn implements GridColumnType { fk_view_id: string; fk_column_id: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; @@ -25,6 +27,7 @@ export default class GridViewColumn implements GridColumnType { } public static async list( + context: NcContext, viewId: string, ncMeta = Noco.ncMeta, ): Promise { @@ -34,14 +37,19 @@ export default class GridViewColumn implements GridColumnType { let { list: views } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !views.length) { - views = await ncMeta.metaList2(null, null, MetaTable.GRID_VIEW_COLUMNS, { - condition: { - fk_view_id: viewId, - }, - orderBy: { - order: 'asc', + views = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.GRID_VIEW_COLUMNS, + { + condition: { + fk_view_id: viewId, + }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.GRID_VIEW_COLUMN, [viewId], views); } views.sort( @@ -52,7 +60,11 @@ export default class GridViewColumn implements GridColumnType { return views?.map((v) => new GridViewColumn(v)); } - public static async get(gridViewColumnId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + gridViewColumnId: string, + ncMeta = Noco.ncMeta, + ) { let view = gridViewColumnId && (await NocoCache.get( @@ -61,8 +73,8 @@ export default class GridViewColumn implements GridColumnType { )); if (!view) { view = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, gridViewColumnId, ); @@ -74,7 +86,11 @@ export default class GridViewColumn implements GridColumnType { return view && new GridViewColumn(view); } - static async insert(column: Partial, ncMeta = Noco.ncMeta) { + static async insert( + context: NcContext, + column: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = extractProps(column, [ 'fk_view_id', 'fk_column_id', @@ -94,30 +110,35 @@ export default class GridViewColumn implements GridColumnType { fk_view_id: column.fk_view_id, })); - if (!(column.base_id && column.source_id)) { - const viewRef = await View.get(column.fk_view_id, ncMeta); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } insertObj.width = column?.width ?? '180px'; const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, insertObj, ); - await View.fixPVColumnForView(column.fk_view_id, ncMeta); + await View.fixPVColumnForView(context, column.fk_view_id, ncMeta); // on new view column, delete any optimised single query cache { - const view = await View.get(column.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const view = await View.get(context, column.fk_view_id, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } - return this.get(id, ncMeta).then(async (viewColumn) => { + return this.get(context, id, ncMeta).then(async (viewColumn) => { await NocoCache.appendToList( CacheScope.GRID_VIEW_COLUMN, [column.fk_view_id], @@ -128,6 +149,7 @@ export default class GridViewColumn implements GridColumnType { } static async update( + context: NcContext, columnId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -143,8 +165,8 @@ export default class GridViewColumn implements GridColumnType { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, updateObj, columnId, @@ -157,9 +179,14 @@ export default class GridViewColumn implements GridColumnType { // on view column update, delete any optimised single query cache { - const gridCol = await this.get(columnId, ncMeta); - const view = await View.get(gridCol.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const gridCol = await this.get(context, columnId, ncMeta); + const view = await View.get(context, gridCol.fk_view_id, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } return res; diff --git a/packages/nocodb/src/models/Hook.ts b/packages/nocodb/src/models/Hook.ts index d87d37ebd6..bb0818518a 100644 --- a/packages/nocodb/src/models/Hook.ts +++ b/packages/nocodb/src/models/Hook.ts @@ -1,4 +1,5 @@ import type { BoolType, HookReqType, HookType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Model from '~/models/Model'; import Filter from '~/models/Filter'; import HookFilter from '~/models/HookFilter'; @@ -33,6 +34,7 @@ export default class Hook implements HookType { timeout?: number; active?: BoolType; + fk_workspace_id?: string; base_id?: string; source_id?: string; version?: 'v1' | 'v2'; @@ -41,7 +43,11 @@ export default class Hook implements HookType { Object.assign(this, hook); } - public static async get(hookId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + hookId: string, + ncMeta = Noco.ncMeta, + ) { let hook = hookId && (await NocoCache.get( @@ -49,35 +55,27 @@ export default class Hook implements HookType { CacheGetType.TYPE_OBJECT, )); if (!hook) { - hook = await ncMeta.metaGet2(null, null, MetaTable.HOOKS, hookId); + hook = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.HOOKS, + hookId, + ); await NocoCache.set(`${CacheScope.HOOK}:${hookId}`, hook); } return hook && new Hook(hook); } - public async getFilters(ncMeta = Noco.ncMeta) { - return await Filter.rootFilterListByHook({ hookId: this.id }, ncMeta); + public async getFilters(context: NcContext, ncMeta = Noco.ncMeta) { + return await Filter.rootFilterListByHook( + context, + { hookId: this.id }, + ncMeta, + ); } - // public static async insert(hook: Partial) { - // const { id } = await ncMeta.metaInsert2(null, null, MetaTable.HOOKS, { - // // user: hook.user, - // // ip: hook.ip, - // // source_id: hook.source_id, - // // base_id: hook.base_id, - // // row_id: hook.row_id, - // // fk_model_id: hook.fk_model_id, - // // op_type: hook.op_type, - // // op_sub_type: hook.op_sub_type, - // // status: hook.status, - // // description: hook.description, - // // details: hook.details - // }); - // - // return this.get(id); - // } - static async list( + context: NcContext, param: { fk_model_id: string; event?: HookType['event']; @@ -91,18 +89,23 @@ export default class Hook implements HookType { let { list: hooks } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !hooks.length) { - hooks = await ncMeta.metaList(null, null, MetaTable.HOOKS, { - condition: { - fk_model_id: param.fk_model_id, - // ...(param.event ? { event: param.event?.toLowerCase?.() } : {}), - // ...(param.operation - // ? { operation: param.operation?.toLowerCase?.() } - // : {}) - }, - orderBy: { - created_at: 'asc', + hooks = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.HOOKS, + { + condition: { + fk_model_id: param.fk_model_id, + // ...(param.event ? { event: param.event?.toLowerCase?.() } : {}), + // ...(param.operation + // ? { operation: param.operation?.toLowerCase?.() } + // : {}) + }, + orderBy: { + created_at: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.HOOK, [param.fk_model_id], hooks); } // filter event & operation @@ -119,7 +122,11 @@ export default class Hook implements HookType { return hooks?.map((h) => new Hook(h)); } - public static async insert(hook: Partial, ncMeta = Noco.ncMeta) { + public static async insert( + context: NcContext, + hook: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = extractProps(hook, [ 'fk_model_id', 'title', @@ -145,9 +152,13 @@ export default class Hook implements HookType { insertObj.notification = JSON.stringify(insertObj.notification); } - if (!(hook.base_id && hook.source_id)) { - const model = await Model.getByIdOrName({ id: hook.fk_model_id }, ncMeta); - insertObj.base_id = model.base_id; + const model = await Model.getByIdOrName( + context, + { id: hook.fk_model_id }, + ncMeta, + ); + + if (!insertObj.source_id) { insertObj.source_id = model.source_id; } @@ -155,13 +166,13 @@ export default class Hook implements HookType { insertObj.version = 'v2'; const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.HOOKS, insertObj, ); - return this.get(id, ncMeta).then(async (hook) => { + return this.get(context, id, ncMeta).then(async (hook) => { await NocoCache.appendToList( CacheScope.HOOK, [hook.fk_model_id], @@ -172,6 +183,7 @@ export default class Hook implements HookType { } public static async update( + context: NcContext, hookId: string, hook: Partial, ncMeta = Noco.ncMeta, @@ -210,18 +222,24 @@ export default class Hook implements HookType { } // set meta - await ncMeta.metaUpdate(null, null, MetaTable.HOOKS, updateObj, hookId); + await ncMeta.metaUpdate( + context.workspace_id, + context.base_id, + MetaTable.HOOKS, + updateObj, + hookId, + ); await NocoCache.update(`${CacheScope.HOOK}:${hookId}`, updateObj); - return this.get(hookId, ncMeta); + return this.get(context, hookId, ncMeta); } - static async delete(hookId: any, ncMeta = Noco.ncMeta) { + static async delete(context: NcContext, hookId: any, ncMeta = Noco.ncMeta) { // Delete Hook Filters const filterList = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FILTER_EXP, { condition: { fk_hook_id: hookId }, @@ -232,13 +250,18 @@ export default class Hook implements HookType { `${CacheScope.FILTER_EXP}:${filter.id}`, CacheDelDirection.CHILD_TO_PARENT, ); - await HookFilter.delete(filter.id); + await HookFilter.delete(context, filter.id, ncMeta); } // Delete Hook await NocoCache.deepDel( `${CacheScope.HOOK}:${hookId}`, CacheDelDirection.CHILD_TO_PARENT, ); - return await ncMeta.metaDelete(null, null, MetaTable.HOOKS, hookId); + return await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.HOOKS, + hookId, + ); } } diff --git a/packages/nocodb/src/models/HookFilter.ts b/packages/nocodb/src/models/HookFilter.ts index 5259be882c..d50a60a2cb 100644 --- a/packages/nocodb/src/models/HookFilter.ts +++ b/packages/nocodb/src/models/HookFilter.ts @@ -1,5 +1,6 @@ import { UITypes } from 'nocodb-sdk'; import type { FilterType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Model from '~/models/Model'; import Column from '~/models/Column'; import View from '~/models/View'; @@ -27,6 +28,7 @@ export default class Filter { logical_op?: string; is_group?: boolean; children?: Filter[]; + fk_workspace_id?: string; base_id?: string; source_id?: string; column?: Column; @@ -35,10 +37,17 @@ export default class Filter { Object.assign(this, data); } - public async getModel(ncMeta = Noco.ncMeta): Promise { + public async getModel( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return this.fk_view_id - ? (await View.get(this.fk_view_id, ncMeta)).getModel(ncMeta) + ? (await View.get(context, this.fk_view_id, ncMeta)).getModel( + context, + ncMeta, + ) : Model.getByIdOrName( + context, { id: this.fk_model_id, }, @@ -47,6 +56,7 @@ export default class Filter { } public static async insert( + context: NcContext, filter: Partial, ncMeta = Noco.ncMeta, ) { @@ -63,29 +73,34 @@ export default class Filter { 'source_id', ]); - if (!(filter.base_id && filter.source_id)) { - const model = await Column.get({ colId: filter.fk_column_id }, ncMeta); - insertObj.base_id = model.base_id; + const model = await Column.get( + context, + { colId: filter.fk_column_id }, + ncMeta, + ); + + if (!filter.source_id) { insertObj.source_id = model.source_id; } const row = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FILTER_EXP, insertObj, ); if (filter?.children?.length) { await Promise.all( filter.children.map((f) => - this.insert({ ...f, fk_parent_id: row.id }, ncMeta), + this.insert(context, { ...f, fk_parent_id: row.id }, ncMeta), ), ); } - return await this.redisPostInsert(row.id, filter, ncMeta); + return await this.redisPostInsert(context, row.id, filter, ncMeta); } static async redisPostInsert( + context: NcContext, id, filter: Partial, ncMeta = Noco.ncMeta, @@ -99,7 +114,12 @@ export default class Filter { let value = await NocoCache.get(key, CacheGetType.TYPE_OBJECT); if (!value) { /* get from db */ - value = await ncMeta.metaGet2(null, null, MetaTable.FILTER_EXP, id); + value = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + id, + ); /* store in redis */ await NocoCache.set(key, value).then(async () => { @@ -143,7 +163,12 @@ export default class Filter { return new Filter(value); } - static async update(id, filter: Partial, ncMeta = Noco.ncMeta) { + static async update( + context: NcContext, + id, + filter: Partial, + ncMeta = Noco.ncMeta, + ) { const updateObj = extractProps(filter, [ 'fk_column_id', 'comparison_op', @@ -154,20 +179,31 @@ export default class Filter { ]); // set meta - await ncMeta.metaUpdate(null, null, MetaTable.FILTER_EXP, updateObj, id); + await ncMeta.metaUpdate( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + updateObj, + id, + ); // update cache await NocoCache.update(`${CacheScope.FILTER_EXP}:${id}`, updateObj); } - static async delete(id: string, ncMeta = Noco.ncMeta) { - const filter = await this.get(id); + static async delete(context: NcContext, id: string, ncMeta = Noco.ncMeta) { + const filter = await this.get(context, id, ncMeta); const deleteRecursively = async (filter: Filter) => { if (!filter) return; - for (const f of (await filter?.getChildren()) || []) + for (const f of (await filter?.getChildren(context, ncMeta)) || []) await deleteRecursively(f); - await ncMeta.metaDelete(null, null, MetaTable.FILTER_EXP, filter.id); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + filter.id, + ); await NocoCache.deepDel( `${CacheScope.FILTER_EXP}:${filter.id}`, CacheDelDirection.CHILD_TO_PARENT, @@ -176,11 +212,15 @@ export default class Filter { await deleteRecursively(filter); } - public getColumn(): Promise { + public getColumn(context: NcContext, ncMeta = Noco.ncMeta): Promise { if (!this.fk_column_id) return null; - return Column.get({ - colId: this.fk_column_id, - }); + return Column.get( + context, + { + colId: this.fk_column_id, + }, + ncMeta, + ); } // public async getGroup(ncMeta = Noco.ncMeta): Promise { @@ -190,7 +230,7 @@ export default class Filter { // 2 // ); // if (!filterObj) { - // filterObj = await ncMeta.metaGet2(null, null, MetaTable.FILTER_EXP, { + // filterObj = await ncMeta.metaGet2(context.workspace_id, context.base_id, MetaTable.FILTER_EXP, { // id: this.fk_parent_id // }); // await NocoCache.set( @@ -201,7 +241,10 @@ export default class Filter { // return filterObj && new Filter(filterObj); // } // - public async getChildren(ncMeta = Noco.ncMeta): Promise { + public async getChildren( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { if (this.children) return this.children; if (!this.is_group) return null; const cachedList = await NocoCache.getList(CacheScope.FILTER_EXP, [ @@ -210,11 +253,16 @@ export default class Filter { let { list: childFilters } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !childFilters.length) { - childFilters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { - fk_parent_id: this.id, + childFilters = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { + fk_parent_id: this.id, + }, }, - }); + ); await NocoCache.setList(CacheScope.FILTER_EXP, [this.id], childFilters); } return childFilters && childFilters.map((f) => new Filter(f)); @@ -228,8 +276,8 @@ export default class Filter { // if (!viewId) return null; // // const filterObj = await ncMeta.metaGet2( - // null, - // null, + // context.workspace_id, + // context.base_id, // MetaTable.FILTER_EXP, // { fk_view_id: viewId, fk_parent_id: null } // ); @@ -237,6 +285,7 @@ export default class Filter { // } public static async getFilterObject( + context: NcContext, { viewId, }: { @@ -248,9 +297,14 @@ export default class Filter { let { list: filters } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !filters.length) { - filters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { fk_view_id: viewId }, - }); + filters = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { fk_view_id: viewId }, + }, + ); await NocoCache.setList(CacheScope.FILTER_EXP, [viewId], filters); } @@ -272,7 +326,7 @@ export default class Filter { grouped[filter._fk_parent_id] = grouped[filter._fk_parent_id] || []; grouped[filter._fk_parent_id].push(filter); idFilterMapping[filter.id] = filter; - filter.column = await new Filter(filter).getColumn(); + filter.column = await new Filter(filter).getColumn(context, ncMeta); if (filter.column?.uidt === UITypes.LinkToAnotherRecord) { } } @@ -299,7 +353,7 @@ export default class Filter { // if (!filter) return; // for (const f of filter?.children || []) await deleteRecursively(f); // if (filter.id) { - // await ncMeta.metaDelete(null, null, MetaTable.FILTER_EXP, filter.id); + // await ncMeta.metaDelete(context.workspace_id, context.base_id, filter.id); // await NocoCache.deepDel( // `${CacheScope.FILTER_EXP}:${filter.id}`, // CacheDelDirection.CHILD_TO_PARENT @@ -309,7 +363,11 @@ export default class Filter { // await deleteRecursively(filter); // } // - private static async get(id: string, ncMeta = Noco.ncMeta) { + private static async get( + context: NcContext, + id: string, + ncMeta = Noco.ncMeta, + ) { let filterObj = id && (await NocoCache.get( @@ -317,15 +375,21 @@ export default class Filter { CacheGetType.TYPE_OBJECT, )); if (!filterObj) { - filterObj = await ncMeta.metaGet2(null, null, MetaTable.FILTER_EXP, { - id, - }); + filterObj = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + id, + }, + ); await NocoCache.set(`${CacheScope.FILTER_EXP}:${id}`, filterObj); } return filterObj && new Filter(filterObj); } // static async rootFilterList( + context: NcContext, { viewId }: { viewId: any }, ncMeta = Noco.ncMeta, ) { @@ -333,9 +397,14 @@ export default class Filter { let { list: filterObjs } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !filterObjs.length) { - filterObjs = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { - condition: { fk_view_id: viewId }, - }); + filterObjs = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.FILTER_EXP, + { + condition: { fk_view_id: viewId }, + }, + ); await NocoCache.setList(CacheScope.FILTER_EXP, [viewId], filterObjs); } return filterObjs?.map((f) => new Filter(f)); @@ -356,7 +425,7 @@ export default class Filter { // parentId // ]); // if (!filterObjs.length) { - // filterObjs = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP, { + // filterObjs = await ncMeta.metaList2(context.workspace_id, context.base_id, MetaTable.FILTER_EXP, { // condition: { // fk_parent_id: parentId, // fk_view_id: viewId diff --git a/packages/nocodb/src/models/HookLog.ts b/packages/nocodb/src/models/HookLog.ts index 96d74697d8..e7ba7b65e6 100644 --- a/packages/nocodb/src/models/HookLog.ts +++ b/packages/nocodb/src/models/HookLog.ts @@ -1,4 +1,5 @@ import type { HookLogType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Hook from '~/models/Hook'; import Noco from '~/Noco'; import { extractProps } from '~/helpers/extractProps'; @@ -7,6 +8,7 @@ import { MetaTable } from '~/utils/globals'; export default class HookLog implements HookLogType { id?: string; source_id?: string; + fk_workspace_id?: string; base_id?: string; fk_hook_id?: string; type?: string; @@ -28,6 +30,7 @@ export default class HookLog implements HookLogType { } static async list( + context: NcContext, param: { fk_hook_id: string; event?: HookLogType['event']; @@ -42,27 +45,36 @@ export default class HookLog implements HookLogType { }, ncMeta = Noco.ncMeta, ) { - const hookLogs = await ncMeta.metaList2(null, null, MetaTable.HOOK_LOGS, { - condition: { - fk_hook_id: param.fk_hook_id, - }, - ...(process.env.NC_AUTOMATION_LOG_LEVEL === 'ERROR' && { - xcCondition: { - error_message: { - neq: null, + const hookLogs = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.HOOK_LOGS, + { + condition: { + fk_hook_id: param.fk_hook_id, + }, + ...(process.env.NC_AUTOMATION_LOG_LEVEL === 'ERROR' && { + xcCondition: { + error_message: { + neq: null, + }, }, + }), + orderBy: { + created_at: 'desc', }, - }), - orderBy: { - created_at: 'desc', + limit, + offset, }, - limit, - offset, - }); + ); return hookLogs?.map((h) => new HookLog(h)); } - public static async insert(hookLog: Partial, ncMeta = Noco.ncMeta) { + public static async insert( + context: NcContext, + hookLog: Partial, + ncMeta = Noco.ncMeta, + ) { if (process.env.NC_AUTOMATION_LOG_LEVEL === 'OFF') { return; } @@ -85,9 +97,9 @@ export default class HookLog implements HookLogType { 'triggered_by', ]); - if (!(hookLog.base_id && hookLog.source_id) && hookLog.fk_hook_id) { - const hook = await Hook.get(hookLog.fk_hook_id, ncMeta); - insertObj.base_id = hook.base_id; + const hook = await Hook.get(context, hookLog.fk_hook_id, ncMeta); + + if (!hookLog.source_id) { insertObj.source_id = hook.source_id; } @@ -97,10 +109,16 @@ export default class HookLog implements HookLogType { insertObj.execution_time = parseInt(insertObj.execution_time) || 0; - return await ncMeta.metaInsert2(null, null, MetaTable.HOOK_LOGS, insertObj); + return await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.HOOK_LOGS, + insertObj, + ); } public static async count( + context: NcContext, { hookId }: { hookId?: string }, ncMeta = Noco.ncMeta, ) { diff --git a/packages/nocodb/src/models/KanbanView.ts b/packages/nocodb/src/models/KanbanView.ts index ac3a2208ca..27ab9f96e4 100644 --- a/packages/nocodb/src/models/KanbanView.ts +++ b/packages/nocodb/src/models/KanbanView.ts @@ -1,5 +1,6 @@ import { UITypes } from 'nocodb-sdk'; import type { BoolType, KanbanType, MetaType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -10,6 +11,7 @@ import { prepareForDb, prepareForResponse } from '~/utils/modelUtils'; export default class KanbanView implements KanbanType { fk_view_id: string; title: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; fk_grp_col_id?: string; @@ -29,7 +31,11 @@ export default class KanbanView implements KanbanType { Object.assign(this, data); } - public static async get(viewId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { let view = viewId && (await NocoCache.get( @@ -37,9 +43,14 @@ export default class KanbanView implements KanbanType { CacheGetType.TYPE_OBJECT, )); if (!view) { - view = await ncMeta.metaGet2(null, null, MetaTable.KANBAN_VIEW, { - fk_view_id: viewId, - }); + view = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.KANBAN_VIEW, + { + fk_view_id: viewId, + }, + ); view = prepareForResponse(view); @@ -50,24 +61,34 @@ export default class KanbanView implements KanbanType { } public static async IsColumnBeingUsedAsGroupingField( + context: NcContext, columnId: string, ncMeta = Noco.ncMeta, ) { return ( ( - await ncMeta.metaList2(null, null, MetaTable.KANBAN_VIEW, { - condition: { - fk_grp_col_id: columnId, + await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.KANBAN_VIEW, + { + condition: { + fk_grp_col_id: columnId, + }, }, - }) + ) ).length > 0 ); } - static async insert(view: Partial, ncMeta = Noco.ncMeta) { - const columns = await View.get(view.fk_view_id, ncMeta) - .then((v) => v?.getModel(ncMeta)) - .then((m) => m.getColumns(ncMeta)); + static async insert( + context: NcContext, + view: Partial, + ncMeta = Noco.ncMeta, + ) { + const columns = await View.get(context, view.fk_view_id, ncMeta) + .then((v) => v?.getModel(context, ncMeta)) + .then((m) => m.getColumns(context, ncMeta)); const insertObj = extractProps(view, [ 'base_id', @@ -81,24 +102,25 @@ export default class KanbanView implements KanbanType { view?.fk_cover_image_col_id || columns?.find((c) => c.uidt === UITypes.Attachment)?.id; - if (!(view.base_id && view.source_id)) { - const viewRef = await View.get(view.fk_view_id); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.KANBAN_VIEW, insertObj, true, ); - return this.get(view.fk_view_id, ncMeta); + return this.get(context, view.fk_view_id, ncMeta); } static async update( + context: NcContext, kanbanId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -111,8 +133,8 @@ export default class KanbanView implements KanbanType { // update meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.KANBAN_VIEW, prepareForDb(updateObj), { @@ -125,10 +147,11 @@ export default class KanbanView implements KanbanType { prepareForResponse(updateObj), ); - const view = await View.get(kanbanId); + const view = await View.get(context, kanbanId); // on update, delete any optimised single query cache await View.clearSingleQueryCache( + context, view.fk_model_id, [{ id: kanbanId }], ncMeta, diff --git a/packages/nocodb/src/models/KanbanViewColumn.ts b/packages/nocodb/src/models/KanbanViewColumn.ts index 495e1df8f0..07cd41ebf2 100644 --- a/packages/nocodb/src/models/KanbanViewColumn.ts +++ b/packages/nocodb/src/models/KanbanViewColumn.ts @@ -1,4 +1,5 @@ import type { BoolType, KanbanColumnType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -13,6 +14,7 @@ export default class KanbanViewColumn implements KanbanColumnType { fk_view_id: string; fk_column_id: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; @@ -20,7 +22,11 @@ export default class KanbanViewColumn implements KanbanColumnType { Object.assign(this, data); } - public static async get(kanbanViewColumnId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + kanbanViewColumnId: string, + ncMeta = Noco.ncMeta, + ) { let view = kanbanViewColumnId && (await NocoCache.get( @@ -29,8 +35,8 @@ export default class KanbanViewColumn implements KanbanColumnType { )); if (!view) { view = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.KANBAN_VIEW_COLUMNS, kanbanViewColumnId, ); @@ -41,7 +47,11 @@ export default class KanbanViewColumn implements KanbanColumnType { } return view && new KanbanViewColumn(view); } - static async insert(column: Partial, ncMeta = Noco.ncMeta) { + static async insert( + context: NcContext, + column: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = extractProps(column, [ 'fk_view_id', 'fk_column_id', @@ -57,20 +67,20 @@ export default class KanbanViewColumn implements KanbanColumnType { }, ); - if (!(column.base_id && column.source_id)) { - const viewRef = await View.get(column.fk_view_id, ncMeta); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.KANBAN_VIEW_COLUMNS, insertObj, ); - return this.get(id, ncMeta).then(async (kanbanViewColumn) => { + return this.get(context, id, ncMeta).then(async (kanbanViewColumn) => { await NocoCache.appendToList( CacheScope.KANBAN_VIEW_COLUMN, [column.fk_view_id], @@ -81,6 +91,7 @@ export default class KanbanViewColumn implements KanbanColumnType { } public static async list( + context: NcContext, viewId: string, ncMeta = Noco.ncMeta, ): Promise { @@ -91,8 +102,8 @@ export default class KanbanViewColumn implements KanbanColumnType { const { isNoneList } = cachedList; if (!isNoneList && !views.length) { views = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.KANBAN_VIEW_COLUMNS, { condition: { @@ -115,6 +126,7 @@ export default class KanbanViewColumn implements KanbanColumnType { // todo: update prop names static async update( + context: NcContext, columnId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -123,8 +135,8 @@ export default class KanbanViewColumn implements KanbanColumnType { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.KANBAN_VIEW_COLUMNS, updateObj, columnId, @@ -136,9 +148,9 @@ export default class KanbanViewColumn implements KanbanColumnType { // on view column update, delete any optimised single query cache { - const viewCol = await this.get(columnId, ncMeta); - const view = await View.get(viewCol.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view]); + const viewCol = await this.get(context, columnId, ncMeta); + const view = await View.get(context, viewCol.fk_view_id, ncMeta); + await View.clearSingleQueryCache(context, view.fk_model_id, [view]); } return res; diff --git a/packages/nocodb/src/models/LinkToAnotherRecordColumn.ts b/packages/nocodb/src/models/LinkToAnotherRecordColumn.ts index 4229025cfa..717ea32670 100644 --- a/packages/nocodb/src/models/LinkToAnotherRecordColumn.ts +++ b/packages/nocodb/src/models/LinkToAnotherRecordColumn.ts @@ -1,4 +1,5 @@ import type { BoolType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import type Filter from '~/models/Filter'; import Model from '~/models/Model'; import Column from '~/models/Column'; @@ -10,6 +11,10 @@ import { View } from '~/models/index'; export default class LinkToAnotherRecordColumn { id: string; + + fk_workspace_id?: string; + base_id?: string; + fk_column_id: string; fk_child_column_id?: string; fk_parent_column_id?: string; @@ -42,8 +47,12 @@ export default class LinkToAnotherRecordColumn { Object.assign(this, data); } - public async getChildColumn(ncMeta = Noco.ncMeta): Promise { + public async getChildColumn( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return (this.childColumn = await Column.get( + context, { colId: this.fk_child_column_id, }, @@ -51,8 +60,12 @@ export default class LinkToAnotherRecordColumn { )); } - public async getMMChildColumn(ncMeta = Noco.ncMeta): Promise { + public async getMMChildColumn( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return (this.mmChildColumn = await Column.get( + context, { colId: this.fk_mm_child_column_id, }, @@ -60,32 +73,48 @@ export default class LinkToAnotherRecordColumn { )); } - public async getParentColumn(ncMeta = Noco.ncMeta): Promise { + public async getParentColumn( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return (this.parentColumn = await Column.get( + context, { colId: this.fk_parent_column_id, }, ncMeta, )); } - public async getMMParentColumn(ncMeta = Noco.ncMeta): Promise { + public async getMMParentColumn( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return (this.mmParentColumn = await Column.get( + context, { colId: this.fk_mm_parent_column_id, }, ncMeta, )); } - public async getMMModel(ncMeta = Noco.ncMeta): Promise { + public async getMMModel( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return (this.mmModel = await Model.getByIdOrName( + context, { id: this.fk_mm_model_id, }, ncMeta, )); } - public async getRelatedTable(ncMeta = Noco.ncMeta): Promise { + public async getRelatedTable( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return (this.relatedTable = await Model.getByIdOrName( + context, { id: this.fk_related_model_id, }, @@ -94,6 +123,7 @@ export default class LinkToAnotherRecordColumn { } public static async insert( + context: NcContext, data: Partial, ncMeta = Noco.ncMeta, ) { @@ -112,16 +142,26 @@ export default class LinkToAnotherRecordColumn { 'fk_related_model_id', 'virtual', ]); - await ncMeta.metaInsert2(null, null, MetaTable.COL_RELATIONS, insertObj); - return this.read(data.fk_column_id, ncMeta); + + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.COL_RELATIONS, + insertObj, + ); + return this.read(context, data.fk_column_id, ncMeta); } - async getChildView(ncMeta = Noco.ncMeta) { + async getChildView(context: NcContext, ncMeta = Noco.ncMeta) { if (!this.fk_target_view_id) return; - return await View.get(this.fk_target_view_id, ncMeta); + return await View.get(context, this.fk_target_view_id, ncMeta); } - public static async read(columnId: string, ncMeta = Noco.ncMeta) { + public static async read( + context: NcContext, + columnId: string, + ncMeta = Noco.ncMeta, + ) { let colData = columnId && (await NocoCache.get( @@ -130,8 +170,8 @@ export default class LinkToAnotherRecordColumn { )); if (!colData) { colData = await ncMeta.metaGet2( - null, //, - null, //model.db_alias + context.workspace_id, + context.base_id, MetaTable.COL_RELATIONS, { fk_column_id: columnId }, ); @@ -141,6 +181,7 @@ export default class LinkToAnotherRecordColumn { } static async update( + _context: NcContext, _fk_column_id: string, _param: { fk_target_view_id: string | null }, ) { diff --git a/packages/nocodb/src/models/LinksColumn.ts b/packages/nocodb/src/models/LinksColumn.ts index d45b7c7508..be6ffbc5db 100644 --- a/packages/nocodb/src/models/LinksColumn.ts +++ b/packages/nocodb/src/models/LinksColumn.ts @@ -1,4 +1,5 @@ import type { RollupColumn } from '~/models/'; +import type { NcContext } from '~/interface/config'; import { Column } from '~/models/'; import LinkToAnotherRecordColumn from '~/models/LinkToAnotherRecordColumn'; import Noco from '~/Noco'; @@ -20,21 +21,39 @@ export default class LinksColumn } } - async getRelationColumn(ncMeta = Noco.ncMeta): Promise { - return await Column.get({ colId: this.fk_column_id }, ncMeta); + async getRelationColumn( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { + return await Column.get(context, { colId: this.fk_column_id }, ncMeta); } - async getRollupColumn(ncMeta = Noco.ncMeta): Promise { - return await Column.get({ colId: this.fk_rollup_column_id }, ncMeta); + async getRollupColumn( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { + return await Column.get( + context, + { colId: this.fk_rollup_column_id }, + ncMeta, + ); } - public static async read(columnId: string, ncMeta = Noco.ncMeta) { - const colData = await super.read(columnId, ncMeta); + public static async read( + context: NcContext, + columnId: string, + ncMeta = Noco.ncMeta, + ) { + const colData = await super.read(context, columnId, ncMeta); return colData && new LinksColumn(colData); } - public static async insert(data: Partial, ncMeta = Noco.ncMeta) { - const colData = await super.insert(data, ncMeta); + public static async insert( + context: NcContext, + data: Partial, + ncMeta = Noco.ncMeta, + ) { + const colData = await super.insert(context, data, ncMeta); return colData && new LinksColumn(colData); } } diff --git a/packages/nocodb/src/models/LookupColumn.ts b/packages/nocodb/src/models/LookupColumn.ts index 8ff29616ba..50f7f6296f 100644 --- a/packages/nocodb/src/models/LookupColumn.ts +++ b/packages/nocodb/src/models/LookupColumn.ts @@ -1,4 +1,5 @@ import type { LookupType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Column from '~/models/Column'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -14,19 +15,20 @@ export default class LookupColumn implements LookupType { Object.assign(this, data); } - public async getRelationColumn(): Promise { - return await Column.get({ + public async getRelationColumn(context: NcContext): Promise { + return await Column.get(context, { colId: this.fk_relation_column_id, }); } - public async getLookupColumn(): Promise { - return await Column.get({ + public async getLookupColumn(context: NcContext): Promise { + return await Column.get(context, { colId: this.fk_lookup_column_id, }); } public static async insert( + context: NcContext, data: Partial, ncMeta = Noco.ncMeta, ) { @@ -36,26 +38,37 @@ export default class LookupColumn implements LookupType { 'fk_lookup_column_id', ]); - await ncMeta.metaInsert2(null, null, MetaTable.COL_LOOKUP, insertObj); + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.COL_LOOKUP, + insertObj, + ); - return this.read(data.fk_column_id, ncMeta).then(async (lookupColumn) => { - await NocoCache.appendToList( - CacheScope.COL_LOOKUP, - [data.fk_lookup_column_id], - `${CacheScope.COL_LOOKUP}:${data.fk_column_id}`, - ); + return this.read(context, data.fk_column_id, ncMeta).then( + async (lookupColumn) => { + await NocoCache.appendToList( + CacheScope.COL_LOOKUP, + [data.fk_lookup_column_id], + `${CacheScope.COL_LOOKUP}:${data.fk_column_id}`, + ); - await NocoCache.appendToList( - CacheScope.COL_LOOKUP, - [data.fk_relation_column_id], - `${CacheScope.COL_LOOKUP}:${data.fk_column_id}`, - ); + await NocoCache.appendToList( + CacheScope.COL_LOOKUP, + [data.fk_relation_column_id], + `${CacheScope.COL_LOOKUP}:${data.fk_column_id}`, + ); - return lookupColumn; - }); + return lookupColumn; + }, + ); } - public static async read(columnId: string, ncMeta = Noco.ncMeta) { + public static async read( + context: NcContext, + columnId: string, + ncMeta = Noco.ncMeta, + ) { let colData = columnId && (await NocoCache.get( @@ -64,8 +77,8 @@ export default class LookupColumn implements LookupType { )); if (!colData) { colData = await ncMeta.metaGet2( - null, //, - null, //model.db_alias, + context.workspace_id, + context.base_id, MetaTable.COL_LOOKUP, { fk_column_id: columnId }, ); diff --git a/packages/nocodb/src/models/MapView.ts b/packages/nocodb/src/models/MapView.ts index 260b7482a5..7b60e7007d 100644 --- a/packages/nocodb/src/models/MapView.ts +++ b/packages/nocodb/src/models/MapView.ts @@ -1,5 +1,6 @@ import type { MetaType } from 'nocodb-sdk'; import type { MapType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import MapViewColumn from '~/models/MapViewColumn'; import { extractProps } from '~/helpers/extractProps'; @@ -11,6 +12,7 @@ import { prepareForDb, prepareForResponse } from '~/utils/modelUtils'; export default class MapView implements MapType { fk_view_id: string; title: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; fk_geo_data_col_id?: string; @@ -28,7 +30,11 @@ export default class MapView implements MapType { Object.assign(this, data); } - public static async get(viewId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { let view = viewId && (await NocoCache.get( @@ -36,16 +42,25 @@ export default class MapView implements MapType { CacheGetType.TYPE_OBJECT, )); if (!view) { - view = await ncMeta.metaGet2(null, null, MetaTable.MAP_VIEW, { - fk_view_id: viewId, - }); + view = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.MAP_VIEW, + { + fk_view_id: viewId, + }, + ); await NocoCache.set(`${CacheScope.MAP_VIEW}:${viewId}`, view); } return view && new MapView(view); } - static async insert(view: Partial, ncMeta = Noco.ncMeta) { + static async insert( + context: NcContext, + view: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = { base_id: view.base_id, source_id: view.source_id, @@ -54,19 +69,25 @@ export default class MapView implements MapType { meta: view.meta, }; - const viewRef = await View.get(view.fk_view_id); + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); - if (!(view.base_id && view.source_id)) { - insertObj.base_id = viewRef.base_id; + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } - await ncMeta.metaInsert2(null, null, MetaTable.MAP_VIEW, insertObj, true); + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.MAP_VIEW, + insertObj, + true, + ); - return this.get(view.fk_view_id, ncMeta); + return this.get(context, view.fk_view_id, ncMeta); } static async update( + context: NcContext, mapId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -74,20 +95,25 @@ export default class MapView implements MapType { const updateObj = extractProps(body, ['fk_geo_data_col_id', 'meta']); if (body.fk_geo_data_col_id != null) { - const mapViewColumns = await MapViewColumn.list(mapId); + const mapViewColumns = await MapViewColumn.list(context, mapId); const mapViewMappedByColumn = mapViewColumns.find( (mapViewColumn) => mapViewColumn.fk_column_id === body.fk_geo_data_col_id, ); - await View.updateColumn(body.fk_view_id, mapViewMappedByColumn.id, { - show: true, - }); + await View.updateColumn( + context, + body.fk_view_id, + mapViewMappedByColumn.id, + { + show: true, + }, + ); } // update meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MAP_VIEW, prepareForDb(updateObj), { diff --git a/packages/nocodb/src/models/MapViewColumn.ts b/packages/nocodb/src/models/MapViewColumn.ts index 7e82e4510c..24f02f273e 100644 --- a/packages/nocodb/src/models/MapViewColumn.ts +++ b/packages/nocodb/src/models/MapViewColumn.ts @@ -1,4 +1,5 @@ import type { BoolType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -12,6 +13,7 @@ export default class MapViewColumn { fk_view_id: string; fk_column_id: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; @@ -19,7 +21,11 @@ export default class MapViewColumn { Object.assign(this, data); } - public static async get(mapViewColumnId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + mapViewColumnId: string, + ncMeta = Noco.ncMeta, + ) { let view = mapViewColumnId && (await NocoCache.get( @@ -28,8 +34,8 @@ export default class MapViewColumn { )); if (!view) { view = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MAP_VIEW_COLUMNS, mapViewColumnId, ); @@ -40,7 +46,11 @@ export default class MapViewColumn { } return view && new MapViewColumn(view); } - static async insert(column: Partial, ncMeta = Noco.ncMeta) { + static async insert( + context: NcContext, + column: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = { fk_view_id: column.fk_view_id, fk_column_id: column.fk_column_id, @@ -52,20 +62,20 @@ export default class MapViewColumn { source_id: column.source_id, }; - if (!(column.base_id && column.source_id)) { - const viewRef = await View.get(column.fk_view_id, ncMeta); - insertObj.base_id = viewRef.base_id; + const viewRef = await View.get(context, insertObj.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = viewRef.source_id; } const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MAP_VIEW_COLUMNS, insertObj, ); - return this.get(id, ncMeta).then(async (viewCol) => { + return this.get(context, id, ncMeta).then(async (viewCol) => { await NocoCache.appendToList( CacheScope.MAP_VIEW_COLUMN, [column.fk_view_id], @@ -76,6 +86,7 @@ export default class MapViewColumn { } public static async list( + context: NcContext, viewId: string, ncMeta = Noco.ncMeta, ): Promise { @@ -85,14 +96,19 @@ export default class MapViewColumn { let { list: views } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !views.length) { - views = await ncMeta.metaList2(null, null, MetaTable.MAP_VIEW_COLUMNS, { - condition: { - fk_view_id: viewId, - }, - orderBy: { - order: 'asc', + views = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.MAP_VIEW_COLUMNS, + { + condition: { + fk_view_id: viewId, + }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.MAP_VIEW_COLUMN, [viewId], views); } views.sort( @@ -105,6 +121,7 @@ export default class MapViewColumn { // todo: update prop names static async update( + context: NcContext, columnId: string, body: Partial, ncMeta = Noco.ncMeta, @@ -120,8 +137,8 @@ export default class MapViewColumn { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MAP_VIEW_COLUMNS, updateObj, columnId, @@ -133,9 +150,9 @@ export default class MapViewColumn { // on view column update, delete any optimised single query cache { - const viewCol = await this.get(columnId, ncMeta); - const view = await View.get(viewCol.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view]); + const viewCol = await this.get(context, columnId, ncMeta); + const view = await View.get(context, viewCol.fk_view_id, ncMeta); + await View.clearSingleQueryCache(context, view.fk_model_id, [view]); } return res; diff --git a/packages/nocodb/src/models/Model.ts b/packages/nocodb/src/models/Model.ts index 5454f4ca8e..61915ca6df 100644 --- a/packages/nocodb/src/models/Model.ts +++ b/packages/nocodb/src/models/Model.ts @@ -9,6 +9,7 @@ import dayjs from 'dayjs'; import type { BoolType, TableReqType, TableType } from 'nocodb-sdk'; import type { XKnex } from '~/db/CustomKnex'; import type { LinksColumn, LinkToAnotherRecordColumn } from '~/models/index'; +import type { NcContext } from '~/interface/config'; import Hook from '~/models/Hook'; import View from '~/models/View'; import Comment from '~/models/Comment'; @@ -42,6 +43,7 @@ export default class Model implements TableType { parent_id: string; password: string; pin: BoolType; + fk_workspace_id?: string; base_id: string; schema: any; show_all_fields: boolean; @@ -65,10 +67,12 @@ export default class Model implements TableType { } public async getColumns( + context: NcContext, ncMeta = Noco.ncMeta, defaultViewId = undefined, ): Promise { this.columns = await Column.list( + context, { fk_model_id: this.id, fk_default_view_id: defaultViewId, @@ -79,9 +83,13 @@ export default class Model implements TableType { } // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public async getViews(force = false, ncMeta = Noco.ncMeta): Promise { - this.views = await View.listWithInfo(this.id, ncMeta); + public async getViews( + context: NcContext, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + force = false, + ncMeta = Noco.ncMeta, + ): Promise { + this.views = await View.listWithInfo(context, this.id, ncMeta); return this.views; } @@ -118,11 +126,13 @@ export default class Model implements TableType { } public static async insert( + context: NcContext, baseId, sourceId, model: Partial & { mm?: BoolType; type?: ModelTypes; + source_id?: string; }, ncMeta = Noco.ncMeta, ) { @@ -152,14 +162,17 @@ export default class Model implements TableType { insertObj.type = ModelTypes.TABLE; } + insertObj.source_id = sourceId; + const { id } = await ncMeta.metaInsert2( - baseId, - sourceId, + context.workspace_id, + context.base_id, MetaTable.MODELS, insertObj, ); const insertedColumns = await Column.bulkInsert( + context, { columns: (model?.columns || []) as Column[], fk_model_id: id, @@ -170,6 +183,7 @@ export default class Model implements TableType { ); await View.insertMetaOnly( + context, { fk_model_id: id, title: model.title || model.table_name, @@ -184,7 +198,7 @@ export default class Model implements TableType { ncMeta, ); - const modelRes = await this.getWithInfo({ id }, ncMeta); + const modelRes = await this.getWithInfo(context, { id }, ncMeta); // append to model list since model list cache will be there already if (sourceId) { @@ -206,6 +220,7 @@ export default class Model implements TableType { } public static async list( + context: NcContext, { base_id, source_id, @@ -222,11 +237,16 @@ export default class Model implements TableType { let { list: modelList } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !modelList.length) { - modelList = await ncMeta.metaList2(base_id, source_id, MetaTable.MODELS, { - orderBy: { - order: 'asc', + modelList = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.MODELS, + { + orderBy: { + order: 'asc', + }, }, - }); + ); // parse meta of each model for (const model of modelList) { @@ -255,6 +275,7 @@ export default class Model implements TableType { model.meta = { ...(model.meta ?? {}), hasNonDefaultViews: await Model.getNonDefaultViewsCountAndReset( + context, { modelId: model.id }, ncMeta, ), @@ -266,6 +287,7 @@ export default class Model implements TableType { } public static async listWithInfo( + context: NcContext, { base_id, db_alias, @@ -282,7 +304,11 @@ export default class Model implements TableType { let { list: modelList } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !modelList.length) { - modelList = await ncMeta.metaList2(base_id, db_alias, MetaTable.MODELS); + modelList = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.MODELS, + ); // parse meta of each model for (const model of modelList) { @@ -297,6 +323,7 @@ export default class Model implements TableType { model.meta = { ...(model.meta ?? {}), hasNonDefaultViews: await Model.getNonDefaultViewsCountAndReset( + context, { modelId: model.id }, ncMeta, ), @@ -307,7 +334,11 @@ export default class Model implements TableType { return modelList.map((m) => new Model(m)); } - public static async get(id: string, ncMeta = Noco.ncMeta): Promise { + public static async get( + context: NcContext, + id: string, + ncMeta = Noco.ncMeta, + ): Promise { let modelData = id && (await NocoCache.get( @@ -315,7 +346,12 @@ export default class Model implements TableType { CacheGetType.TYPE_OBJECT, )); if (!modelData) { - modelData = await ncMeta.metaGet2(null, null, MetaTable.MODELS, id); + modelData = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.MODELS, + id, + ); if (modelData) { modelData.meta = parseMetaProp(modelData); @@ -326,6 +362,7 @@ export default class Model implements TableType { } public static async getByIdOrName( + context: NcContext, args: | { base_id: string; @@ -345,7 +382,12 @@ export default class Model implements TableType { CacheGetType.TYPE_OBJECT, )); if (!modelData) { - modelData = await ncMeta.metaGet2(null, null, MetaTable.MODELS, k); + modelData = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.MODELS, + k, + ); if (modelData) { modelData.meta = parseMetaProp(modelData); } @@ -359,6 +401,7 @@ export default class Model implements TableType { } public static async getWithInfo( + context: NcContext, { table_name, id, @@ -376,8 +419,8 @@ export default class Model implements TableType { )); if (!modelData) { modelData = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODELS, id || { table_name, @@ -395,11 +438,11 @@ export default class Model implements TableType { if (modelData) { const m = new Model(modelData); - await m.getViews(false, ncMeta); + await m.getViews(context, false, ncMeta); const defaultViewId = m.views.find((view) => view.is_default).id; - const columns = await m.getColumns(ncMeta, defaultViewId); + const columns = await m.getColumns(context, ncMeta, defaultViewId); m.columnsById = columns.reduce((agg, c) => ({ ...agg, [c.id]: c }), {}); return m; @@ -408,6 +451,7 @@ export default class Model implements TableType { } public static async getBaseModelSQL( + context: NcContext, args: { id?: string; viewId?: string; @@ -417,33 +461,42 @@ export default class Model implements TableType { }, ncMeta = Noco.ncMeta, ): Promise { - const model = args?.model || (await this.get(args.id, ncMeta)); + const model = args?.model || (await this.get(context, args.id, ncMeta)); if (!args?.viewId && args.extractDefaultView) { - const view = await View.getDefaultView(model.id, ncMeta); + const view = await View.getDefaultView(context, model.id, ncMeta); args.viewId = view.id; } return new BaseModelSqlv2({ + context, dbDriver: args.dbDriver, viewId: args.viewId, model, }); } - async delete(ncMeta = Noco.ncMeta, force = false): Promise { - await Comment.deleteRowComments(this.id, ncMeta); + async delete( + context: NcContext, + ncMeta = Noco.ncMeta, + force = false, + ): Promise { + await Comment.deleteRowComments(context, this.id, ncMeta); - for (const view of await this.getViews(true, ncMeta)) { - await view.delete(ncMeta); + for (const view of await this.getViews(context, true, ncMeta)) { + await view.delete(context, ncMeta); } // delete associated hooks - for (const hook of await Hook.list({ fk_model_id: this.id }, ncMeta)) { - await Hook.delete(hook.id, ncMeta); + for (const hook of await Hook.list( + context, + { fk_model_id: this.id }, + ncMeta, + )) { + await Hook.delete(context, hook.id, ncMeta); } - for (const col of await this.getColumns(ncMeta)) { + for (const col of await this.getColumns(context, ncMeta)) { let colOptionTableName = null; let cacheScopeName = null; switch (col.uidt) { @@ -479,9 +532,14 @@ export default class Model implements TableType { break; } if (colOptionTableName && cacheScopeName) { - await ncMeta.metaDelete(null, null, colOptionTableName, { - fk_column_id: col.id, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + colOptionTableName, + { + fk_column_id: col.id, + }, + ); await NocoCache.deepDel( `${cacheScopeName}:${col.id}`, CacheDelDirection.CHILD_TO_PARENT, @@ -491,8 +549,8 @@ export default class Model implements TableType { if (force) { const leftOverColumns = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_RELATIONS, { condition: { @@ -508,24 +566,39 @@ export default class Model implements TableType { ); } - await ncMeta.metaDelete(null, null, MetaTable.COL_RELATIONS, { - fk_related_model_id: this.id, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COL_RELATIONS, + { + fk_related_model_id: this.id, + }, + ); } await NocoCache.deepDel( `${CacheScope.COLUMN}:${this.id}`, CacheDelDirection.CHILD_TO_PARENT, ); - await ncMeta.metaDelete(null, null, MetaTable.COLUMNS, { - fk_model_id: this.id, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.COLUMNS, + { + fk_model_id: this.id, + }, + ); await NocoCache.deepDel( `${CacheScope.MODEL}:${this.id}`, CacheDelDirection.CHILD_TO_PARENT, ); - await ncMeta.metaDelete(null, null, MetaTable.MODELS, this.id); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.MODELS, + this.id, + ); // delete alias cache await NocoCache.del([ @@ -538,6 +611,7 @@ export default class Model implements TableType { } async mapAliasToColumn( + context: NcContext, data, clientMeta = { isMySQL: false, @@ -549,7 +623,7 @@ export default class Model implements TableType { columns?: Column[], ) { const insertObj = {}; - for (const col of columns || (await this.getColumns())) { + for (const col of columns || (await this.getColumns(context))) { if (isVirtualCol(col)) continue; let val = data?.[col.column_name] !== undefined @@ -627,9 +701,9 @@ export default class Model implements TableType { return insertObj; } - async mapColumnToAlias(data, columns?: Column[]) { + async mapColumnToAlias(context: NcContext, data, columns?: Column[]) { const res = {}; - for (const col of columns || (await this.getColumns())) { + for (const col of columns || (await this.getColumns(context))) { if (isVirtualCol(col)) continue; let val = data?.[col.title] !== undefined @@ -646,6 +720,7 @@ export default class Model implements TableType { } static async updateAliasAndTableName( + context: NcContext, tableId, title: string, table_name: string, @@ -658,12 +733,12 @@ export default class Model implements TableType { NcError.badRequest("Missing 'table_name' property in body"); } - const oldModel = await this.get(tableId, ncMeta); + const oldModel = await this.get(context, tableId, ncMeta); // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODELS, { title, @@ -686,17 +761,23 @@ export default class Model implements TableType { ]); // clear all the cached query under this model - await View.clearSingleQueryCache(tableId, null, ncMeta); + await View.clearSingleQueryCache(context, tableId, null, ncMeta); // clear all the cached query under related models - for (const col of await this.get(tableId).then((t) => t.getColumns())) { + for (const col of await this.get(context, tableId).then((t) => + t.getColumns(context), + )) { if (!isLinksOrLTAR(col)) continue; - const colOptions = await col.getColOptions(); + const colOptions = await col.getColOptions( + context, + ncMeta, + ); if (colOptions.fk_related_model_id === tableId) continue; await View.clearSingleQueryCache( + context, colOptions.fk_related_model_id, null, ncMeta, @@ -706,11 +787,16 @@ export default class Model implements TableType { return res; } - static async markAsMmTable(tableId, isMm = true, ncMeta = Noco.ncMeta) { + static async markAsMmTable( + context: NcContext, + tableId, + isMm = true, + ncMeta = Noco.ncMeta, + ) { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODELS, { mm: isMm, @@ -725,8 +811,8 @@ export default class Model implements TableType { return res; } - async getAliasColMapping() { - return (await this.getColumns()).reduce((o, c) => { + async getAliasColMapping(context: NcContext) { + return (await this.getColumns(context)).reduce((o, c) => { if (c.column_name) { o[c.title] = c.column_name; } @@ -734,8 +820,8 @@ export default class Model implements TableType { }, {}); } - async getColAliasMapping() { - return (await this.getColumns()).reduce((o, c) => { + async getColAliasMapping(context: NcContext) { + return (await this.getColumns(context)).reduce((o, c) => { if (c.column_name) { o[c.column_name] = c.title; } @@ -744,14 +830,15 @@ export default class Model implements TableType { } static async updateOrder( + context: NcContext, tableId: string, order: number, ncMeta = Noco.ncMeta, ) { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODELS, { order, @@ -767,11 +854,12 @@ export default class Model implements TableType { } static async updatePrimaryColumn( + context: NcContext, tableId: string, columnId: string, ncMeta = Noco.ncMeta, ) { - const model = await this.getWithInfo({ id: tableId }); + const model = await this.getWithInfo(context, { id: tableId }, ncMeta); const newPvCol = model.columns.find((c) => c.id === columnId); if (!newPvCol) NcError.fieldNotFound(columnId); @@ -780,8 +868,8 @@ export default class Model implements TableType { for (const col of model.columns?.filter((c) => c.pv) || []) { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, { pv: false, @@ -796,8 +884,8 @@ export default class Model implements TableType { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, { pv: true, @@ -810,8 +898,8 @@ export default class Model implements TableType { }); const grid_views_with_column = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, { condition: { @@ -822,7 +910,7 @@ export default class Model implements TableType { if (grid_views_with_column.length) { for (const gv of grid_views_with_column) { - await View.fixPVColumnForView(gv.fk_view_id, ncMeta); + await View.fixPVColumnForView(context, gv.fk_view_id, ncMeta); } } @@ -834,24 +922,24 @@ export default class Model implements TableType { if (!isLinksOrLTAR(col)) continue; const colOptions = await col.getColOptions< LinkToAnotherRecordColumn | LinksColumn - >(); + >(context); relatedModelIds.add(colOptions?.fk_related_model_id); } await Promise.all( Array.from(relatedModelIds).map(async (modelId: string) => { - await View.clearSingleQueryCache(modelId, null, ncMeta); + await View.clearSingleQueryCache(context, modelId, null, ncMeta); }), ); return true; } - static async setAsMm(id: any, ncMeta = Noco.ncMeta) { + static async setAsMm(context: NcContext, id: any, ncMeta = Noco.ncMeta) { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODELS, { mm: true, @@ -865,6 +953,7 @@ export default class Model implements TableType { } static async getByAliasOrId( + context: NcContext, { base_id, source_id, @@ -886,8 +975,8 @@ export default class Model implements TableType { if (!modelId) { const model = source_id ? await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODELS, { base_id, source_id }, null, @@ -907,8 +996,8 @@ export default class Model implements TableType { }, ) : await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODELS, { base_id }, null, @@ -933,21 +1022,17 @@ export default class Model implements TableType { } return model && new Model(model); } - return modelId && this.get(modelId); + return modelId && this.get(context, modelId); } static async checkTitleAvailable( - { - table_name, - base_id, - source_id, - exclude_id, - }: { table_name; base_id; source_id; exclude_id? }, + context: NcContext, + { table_name, exclude_id }: { table_name; base_id; source_id; exclude_id? }, ncMeta = Noco.ncMeta, ) { return !(await ncMeta.metaGet2( - base_id, - source_id, + context.workspace_id, + context.base_id, MetaTable.MODELS, { table_name, @@ -958,17 +1043,13 @@ export default class Model implements TableType { } static async checkAliasAvailable( - { - title, - base_id, - source_id, - exclude_id, - }: { title; base_id; source_id; exclude_id? }, + context: NcContext, + { title, exclude_id }: { title; base_id; source_id; exclude_id? }, ncMeta = Noco.ncMeta, ) { return !(await ncMeta.metaGet2( - base_id, - source_id, + context.workspace_id, + context.base_id, MetaTable.MODELS, { title, @@ -978,8 +1059,8 @@ export default class Model implements TableType { )); } - async getAliasColObjMap(columns?: Column[]) { - return (columns || (await this.getColumns())).reduce( + async getAliasColObjMap(context: NcContext, columns?: Column[]) { + return (columns || (await this.getColumns(context))).reduce( (sortAgg, c) => ({ ...sortAgg, [c.title]: c }), {}, ); @@ -987,14 +1068,15 @@ export default class Model implements TableType { // For updating table meta static async updateMeta( + context: NcContext, tableId: string, meta: string | Record, ncMeta = Noco.ncMeta, ) { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODELS, prepareForDb({ meta, @@ -1013,6 +1095,7 @@ export default class Model implements TableType { } static async getNonDefaultViewsCountAndReset( + context: NcContext, { modelId, }: { @@ -1020,16 +1103,16 @@ export default class Model implements TableType { }, ncMeta = Noco.ncMeta, ) { - const model = await this.get(modelId, ncMeta); + const model = await this.get(context, modelId, ncMeta); let modelMeta = parseMetaProp(model); - const views = await View.list(modelId, ncMeta); + const views = await View.list(context, modelId, ncMeta); modelMeta = { ...(modelMeta ?? {}), hasNonDefaultViews: views.length > 1, }; - await this.updateMeta(modelId, modelMeta, ncMeta); + await this.updateMeta(context, modelId, modelMeta, ncMeta); return modelMeta?.hasNonDefaultViews; } diff --git a/packages/nocodb/src/models/ModelRoleVisibility.ts b/packages/nocodb/src/models/ModelRoleVisibility.ts index 04b18e2d87..29822e2d77 100644 --- a/packages/nocodb/src/models/ModelRoleVisibility.ts +++ b/packages/nocodb/src/models/ModelRoleVisibility.ts @@ -1,4 +1,5 @@ import type { ModelRoleVisibilityType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import View from '~/models/View'; import Noco from '~/Noco'; import { @@ -12,6 +13,7 @@ import { extractProps } from '~/helpers/extractProps'; export default class ModelRoleVisibility implements ModelRoleVisibilityType { id?: string; + fk_workspace_id?: string; base_id?: string; source_id?: string; // fk_model_id?: string; @@ -23,7 +25,10 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { Object.assign(this, body); } - static async list(baseId): Promise { + static async list( + context: NcContext, + baseId, + ): Promise { const cachedList = await NocoCache.getList( CacheScope.MODEL_ROLE_VISIBILITY, [baseId], @@ -32,8 +37,8 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { const { isNoneList } = cachedList; if (!isNoneList && !data.length) { data = await Noco.ncMeta.metaList2( - baseId, - null, + context.workspace_id, + context.base_id, MetaTable.MODEL_ROLE_VISIBILITY, ); await NocoCache.setList( @@ -47,6 +52,7 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { } static async get( + context: NcContext, args: { role: string; fk_view_id: any }, ncMeta = Noco.ncMeta, ) { @@ -59,8 +65,8 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { )); if (!data) { data = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODEL_ROLE_VISIBILITY, // args.fk_model_id // ? { @@ -82,14 +88,16 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { } static async update( + context: NcContext, fk_view_id: string, role: string, body: { disabled: any }, + ncMeta = Noco.ncMeta, ) { // set meta - const res = await Noco.ncMeta.metaUpdate( - null, - null, + const res = await ncMeta.metaUpdate( + context.workspace_id, + context.base_id, MetaTable.MODEL_ROLE_VISIBILITY, { disabled: body.disabled, @@ -110,13 +118,23 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { return res; } - async delete() { - return await ModelRoleVisibility.delete(this.fk_view_id, this.role); + async delete(context: NcContext, ncMeta = Noco.ncMeta) { + return await ModelRoleVisibility.delete( + context, + this.fk_view_id, + this.role, + ncMeta, + ); } - static async delete(fk_view_id: string, role: string) { - const res = await Noco.ncMeta.metaDelete( - null, - null, + static async delete( + context: NcContext, + fk_view_id: string, + role: string, + ncMeta = Noco.ncMeta, + ) { + const res = await ncMeta.metaDelete( + context.workspace_id, + context.base_id, MetaTable.MODEL_ROLE_VISIBILITY, { fk_view_id, @@ -131,6 +149,7 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { } static async insert( + context: NcContext, body: Partial, ncMeta = Noco.ncMeta, ) { @@ -142,15 +161,15 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { 'source_id', ]); - if (!(insertObj.base_id && insertObj.source_id)) { - const view = await View.get(body.fk_view_id, ncMeta); - insertObj.base_id = view.base_id; + const view = await View.get(context, body.fk_view_id, ncMeta); + + if (!insertObj.source_id) { insertObj.source_id = view.source_id; } const result = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MODEL_ROLE_VISIBILITY, insertObj, ); @@ -158,6 +177,7 @@ export default class ModelRoleVisibility implements ModelRoleVisibilityType { insertObj.id = result.id; return this.get( + context, { fk_view_id: body.fk_view_id, role: body.role, diff --git a/packages/nocodb/src/models/Notification.ts b/packages/nocodb/src/models/Notification.ts index d087b33d1c..c41b8f6c2f 100644 --- a/packages/nocodb/src/models/Notification.ts +++ b/packages/nocodb/src/models/Notification.ts @@ -1,7 +1,7 @@ import type { AppEvents } from 'nocodb-sdk'; import { extractProps } from '~/helpers/extractProps'; import Noco from '~/Noco'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; import { prepareForDb, prepareForResponse } from '~/utils/modelUtils'; export default class Notification { @@ -31,8 +31,8 @@ export default class Notification { ]); return await ncMeta.metaInsert2( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.NOTIFICATION, prepareForDb(insertData, 'body'), ); @@ -47,7 +47,12 @@ export default class Notification { ) { const condition = extractProps(params, ['id', 'fk_user_id']); - return await ncMeta.metaGet2(null, null, MetaTable.NOTIFICATION, condition); + return await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.NOTIFICATION, + condition, + ); } public static async list( @@ -68,9 +73,9 @@ export default class Notification { 'fk_user_id', ]); - const notifications = await ncMeta.metaList( - null, - null, + const notifications = await ncMeta.metaList2( + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.NOTIFICATION, { condition, @@ -101,9 +106,14 @@ export default class Notification { 'is_deleted', 'fk_user_id', ]); - const count = await ncMeta.metaCount(null, null, MetaTable.NOTIFICATION, { - condition, - }); + const count = await ncMeta.metaCount( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.NOTIFICATION, + { + condition, + }, + ); return count; } @@ -122,8 +132,8 @@ export default class Notification { ]); return await ncMeta.metaUpdate( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.NOTIFICATION, prepareForDb(updateData, 'body'), id, @@ -132,8 +142,8 @@ export default class Notification { public static async markAllAsRead(fk_user_id: string, ncMeta = Noco.ncMeta) { return ncMeta.metaUpdate( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.NOTIFICATION, { is_read: true }, { diff --git a/packages/nocodb/src/models/Plugin.ts b/packages/nocodb/src/models/Plugin.ts index 3862a75223..37ab8072bb 100644 --- a/packages/nocodb/src/models/Plugin.ts +++ b/packages/nocodb/src/models/Plugin.ts @@ -2,7 +2,12 @@ import type { PluginType } from 'nocodb-sdk'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; import { extractProps } from '~/helpers/extractProps'; -import { CacheGetType, CacheScope, MetaTable } from '~/utils/globals'; +import { + CacheGetType, + CacheScope, + MetaTable, + RootScopes, +} from '~/utils/globals'; export default class Plugin implements PluginType { id?: string; @@ -36,7 +41,12 @@ export default class Plugin implements PluginType { CacheGetType.TYPE_OBJECT, )); if (!plugin) { - plugin = await ncMeta.metaGet2(null, null, MetaTable.PLUGIN, pluginId); + plugin = await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.PLUGIN, + pluginId, + ); await NocoCache.set(`${CacheScope.PLUGIN}:${pluginId}`, plugin); } return plugin && new Plugin(plugin); @@ -47,7 +57,11 @@ export default class Plugin implements PluginType { let { list: pluginList } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !pluginList.length) { - pluginList = await ncMeta.metaList2(null, null, MetaTable.PLUGIN); + pluginList = await ncMeta.metaList2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.PLUGIN, + ); await NocoCache.setList(CacheScope.PLUGIN, [], pluginList); } return pluginList; @@ -67,8 +81,8 @@ export default class Plugin implements PluginType { // set meta await Noco.ncMeta.metaUpdate( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.PLUGIN, updateObj, pluginId, @@ -95,9 +109,14 @@ export default class Plugin implements PluginType { CacheGetType.TYPE_OBJECT, )); if (!plugin) { - plugin = await ncMeta.metaGet2(null, null, MetaTable.PLUGIN, { - title, - }); + plugin = await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.PLUGIN, + { + title, + }, + ); await NocoCache.set(`${CacheScope.PLUGIN}:${title}`, plugin); } return plugin; diff --git a/packages/nocodb/src/models/QrCodeColumn.ts b/packages/nocodb/src/models/QrCodeColumn.ts index aa597145b2..1b2672deb0 100644 --- a/packages/nocodb/src/models/QrCodeColumn.ts +++ b/packages/nocodb/src/models/QrCodeColumn.ts @@ -1,10 +1,14 @@ +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; import { extractProps } from '~/helpers/extractProps'; import { CacheGetType, CacheScope, MetaTable } from '~/utils/globals'; import { Column } from '~/models'; +import { NcError } from '~/helpers/catchError'; export default class QrCodeColumn { + base_id?: string; + fk_workspace_id?: string; fk_column_id: string; fk_qr_value_column_id: string; @@ -13,6 +17,7 @@ export default class QrCodeColumn { } public static async insert( + context: NcContext, qrCode: Partial, ncMeta = Noco.ncMeta, ) { @@ -21,11 +26,32 @@ export default class QrCodeColumn { 'fk_qr_value_column_id', ]); - await ncMeta.metaInsert2(null, null, MetaTable.COL_QRCODE, insertObj); + const column = await Column.get( + context, + { + colId: insertObj.fk_column_id, + }, + ncMeta, + ); - return this.read(qrCode.fk_column_id, ncMeta); + if (!column) { + NcError.fieldNotFound(insertObj.fk_column_id); + } + + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.COL_QRCODE, + insertObj, + ); + + return this.read(context, qrCode.fk_column_id, ncMeta); } - public static async read(columnId: string, ncMeta = Noco.ncMeta) { + public static async read( + context: NcContext, + columnId: string, + ncMeta = Noco.ncMeta, + ) { let column = columnId && (await NocoCache.get( @@ -34,8 +60,8 @@ export default class QrCodeColumn { )); if (!column) { column = await ncMeta.metaGet2( - null, //, - null, //model.db_alias, + context.workspace_id, + context.base_id, MetaTable.COL_QRCODE, { fk_column_id: columnId }, ); @@ -47,8 +73,8 @@ export default class QrCodeColumn { id: string; - async getValueColumn() { - return Column.get({ + async getValueColumn(context: NcContext) { + return Column.get(context, { colId: this.fk_qr_value_column_id, }); } diff --git a/packages/nocodb/src/models/RollupColumn.ts b/packages/nocodb/src/models/RollupColumn.ts index cc3b788dbb..6978471256 100644 --- a/packages/nocodb/src/models/RollupColumn.ts +++ b/packages/nocodb/src/models/RollupColumn.ts @@ -1,9 +1,11 @@ import type { RollupType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Column from '~/models/Column'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; import { extractProps } from '~/helpers/extractProps'; import { CacheGetType, CacheScope, MetaTable } from '~/utils/globals'; +import { NcError } from '~/helpers/catchError'; export const ROLLUP_FUNCTIONS = [ 'count', @@ -17,6 +19,8 @@ export const ROLLUP_FUNCTIONS = [ export default class RollupColumn implements RollupType { id: string; + base_id?: string; + fk_workspace_id?: string; fk_column_id; fk_relation_column_id; fk_rollup_column_id; @@ -27,6 +31,7 @@ export default class RollupColumn implements RollupType { } public static async insert( + context: NcContext, data: Partial, ncMeta = Noco.ncMeta, ) { @@ -36,26 +41,50 @@ export default class RollupColumn implements RollupType { 'fk_rollup_column_id', 'rollup_function', ]); - await ncMeta.metaInsert2(null, null, MetaTable.COL_ROLLUP, insertObj); - return this.read(data.fk_column_id, ncMeta).then(async (rollupColumn) => { - await NocoCache.appendToList( - CacheScope.COL_ROLLUP, - [data.fk_rollup_column_id], - `${CacheScope.COL_ROLLUP}:${data.fk_column_id}`, - ); + const column = await Column.get( + context, + { + colId: insertObj.fk_column_id, + }, + ncMeta, + ); - await NocoCache.appendToList( - CacheScope.COL_ROLLUP, - [data.fk_relation_column_id], - `${CacheScope.COL_ROLLUP}:${data.fk_column_id}`, - ); + if (!column) { + NcError.fieldNotFound(insertObj.fk_column_id); + } + + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.COL_ROLLUP, + insertObj, + ); + + return this.read(context, data.fk_column_id, ncMeta).then( + async (rollupColumn) => { + await NocoCache.appendToList( + CacheScope.COL_ROLLUP, + [data.fk_rollup_column_id], + `${CacheScope.COL_ROLLUP}:${data.fk_column_id}`, + ); - return rollupColumn; - }); + await NocoCache.appendToList( + CacheScope.COL_ROLLUP, + [data.fk_relation_column_id], + `${CacheScope.COL_ROLLUP}:${data.fk_column_id}`, + ); + + return rollupColumn; + }, + ); } - public static async read(columnId: string, ncMeta = Noco.ncMeta) { + public static async read( + context: NcContext, + columnId: string, + ncMeta = Noco.ncMeta, + ) { let column = columnId && (await NocoCache.get( @@ -64,8 +93,8 @@ export default class RollupColumn implements RollupType { )); if (!column) { column = await ncMeta.metaGet2( - null, //, - null, //model.db_alias, + context.workspace_id, + context.base_id, MetaTable.COL_ROLLUP, { fk_column_id: columnId }, ); @@ -74,11 +103,17 @@ export default class RollupColumn implements RollupType { return column ? new RollupColumn(column) : null; } - public async getRollupColumn(ncMeta = Noco.ncMeta): Promise { - return Column.get({ colId: this.fk_rollup_column_id }, ncMeta); + public async getRollupColumn( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { + return Column.get(context, { colId: this.fk_rollup_column_id }, ncMeta); } - public async getRelationColumn(ncMeta = Noco.ncMeta): Promise { - return Column.get({ colId: this.fk_relation_column_id }, ncMeta); + public async getRelationColumn( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { + return Column.get(context, { colId: this.fk_relation_column_id }, ncMeta); } } diff --git a/packages/nocodb/src/models/SelectOption.ts b/packages/nocodb/src/models/SelectOption.ts index 63297c6b48..7fa30fd0fe 100644 --- a/packages/nocodb/src/models/SelectOption.ts +++ b/packages/nocodb/src/models/SelectOption.ts @@ -1,12 +1,17 @@ import type { SelectOptionType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; import { extractProps } from '~/helpers/extractProps'; import { CacheGetType, CacheScope, MetaTable } from '~/utils/globals'; +import { Column } from '~/models'; +import { NcError } from '~/helpers/catchError'; export default class SelectOption implements SelectOptionType { id: string; title: string; + base_id?: string; + fk_workspace_id?: string; fk_column_id: string; color: string; order: number; @@ -16,6 +21,7 @@ export default class SelectOption implements SelectOptionType { } public static async insert( + context: NcContext, data: Partial, ncMeta = Noco.ncMeta, ) { @@ -27,14 +33,26 @@ export default class SelectOption implements SelectOptionType { 'order', ]); + const column = await Column.get( + context, + { + colId: insertObj.fk_column_id, + }, + ncMeta, + ); + + if (!column) { + NcError.fieldNotFound(insertObj.fk_column_id); + } + const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_SELECT_OPTIONS, insertObj, ); - return this.get(id, ncMeta).then(async (selectOption) => { + return this.get(context, id, ncMeta).then(async (selectOption) => { await NocoCache.appendToList( CacheScope.COL_SELECT_OPTION, [data.fk_column_id], @@ -45,6 +63,7 @@ export default class SelectOption implements SelectOptionType { } public static async bulkInsert( + context: NcContext, data: Partial[], ncMeta = Noco.ncMeta, ) { @@ -61,9 +80,13 @@ export default class SelectOption implements SelectOptionType { insertObj.push(tempObj); } + if (!insertObj.length) { + return false; + } + const bulkData = await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_SELECT_OPTIONS, insertObj, ); @@ -81,6 +104,7 @@ export default class SelectOption implements SelectOptionType { } public static async get( + context: NcContext, selectOptionId: string, ncMeta = Noco.ncMeta, ): Promise { @@ -92,8 +116,8 @@ export default class SelectOption implements SelectOptionType { )); if (!data) { data = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_SELECT_OPTIONS, selectOptionId, ); @@ -105,7 +129,11 @@ export default class SelectOption implements SelectOptionType { return data && new SelectOption(data); } - public static async read(fk_column_id: string, ncMeta = Noco.ncMeta) { + public static async read( + context: NcContext, + fk_column_id: string, + ncMeta = Noco.ncMeta, + ) { const cachedList = await NocoCache.getList(CacheScope.COL_SELECT_OPTION, [ fk_column_id, ]); @@ -113,8 +141,8 @@ export default class SelectOption implements SelectOptionType { const { isNoneList } = cachedList; if (!isNoneList && !options.length) { options = await ncMeta.metaList2( - null, //, - null, //model.db_alias, + context.workspace_id, + context.base_id, MetaTable.COL_SELECT_OPTIONS, { condition: { fk_column_id } }, ); @@ -135,13 +163,14 @@ export default class SelectOption implements SelectOptionType { } public static async find( + context: NcContext, fk_column_id: string, title: string, ncMeta = Noco.ncMeta, ): Promise { const data = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_SELECT_OPTIONS, { fk_column_id, diff --git a/packages/nocodb/src/models/Sort.ts b/packages/nocodb/src/models/Sort.ts index 737911173d..cffb21c439 100644 --- a/packages/nocodb/src/models/Sort.ts +++ b/packages/nocodb/src/models/Sort.ts @@ -1,4 +1,5 @@ import type { SortType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Model from '~/models/Model'; import Column from '~/models/Column'; import Noco from '~/Noco'; @@ -18,6 +19,7 @@ export default class Sort { fk_view_id: string; fk_column_id?: string; direction?: 'asc' | 'desc' | 'count-desc' | 'count-asc'; + fk_workspace_id?: string; base_id?: string; source_id?: string; @@ -25,23 +27,38 @@ export default class Sort { Object.assign(this, data); } - public static async deleteAll(viewId: string, ncMeta = Noco.ncMeta) { + public static async deleteAll( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { await NocoCache.deepDel( `${CacheScope.SORT}:${viewId}`, CacheDelDirection.PARENT_TO_CHILD, ); - await ncMeta.metaDelete(null, null, MetaTable.SORT, { - fk_view_id: viewId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.SORT, + { + fk_view_id: viewId, + }, + ); // on delete, delete any optimised single query cache { - const view = await View.get(viewId, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const view = await View.get(context, viewId, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } } public static async insert( + context: NcContext, sortObj: Partial & { push_to_top?: boolean; order?: number }, ncMeta = Noco.ncMeta, ) { @@ -66,9 +83,14 @@ export default class Sort { }) .first() )?.order || 0) + 1; - if (!(sortObj.base_id && sortObj.source_id)) { - const model = await Column.get({ colId: sortObj.fk_column_id }, ncMeta); - insertObj.base_id = model.base_id; + + const model = await Column.get( + context, + { colId: sortObj.fk_column_id }, + ncMeta, + ); + + if (!sortObj.source_id) { insertObj.source_id = model.source_id; } @@ -82,23 +104,38 @@ export default class Sort { .increment('order', 1); } - const row = await ncMeta.metaInsert2(null, null, MetaTable.SORT, insertObj); + const row = await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.SORT, + insertObj, + ); if (sortObj.push_to_top) { - const sortList = await ncMeta.metaList2(null, null, MetaTable.SORT, { - condition: { fk_view_id: sortObj.fk_view_id }, - orderBy: { - order: 'asc', + const sortList = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.SORT, + { + condition: { fk_view_id: sortObj.fk_view_id }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.SORT, [sortObj.fk_view_id], sortList); } // on insert, delete any optimised single query cache { - const view = await View.get(row.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const view = await View.get(context, row.fk_view_id, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } - return this.get(row.id, ncMeta).then(async (sort) => { + return this.get(context, row.id, ncMeta).then(async (sort) => { if (!sortObj.push_to_top) { await NocoCache.appendToList( CacheScope.SORT, @@ -115,14 +152,19 @@ export default class Sort { }); } - public getColumn(): Promise { + public getColumn(context: NcContext, ncMeta = Noco.ncMeta): Promise { if (!this.fk_column_id) return null; - return Column.get({ - colId: this.fk_column_id, - }); + return Column.get( + context, + { + colId: this.fk_column_id, + }, + ncMeta, + ); } public static async list( + context: NcContext, { viewId }: { viewId: string }, ncMeta = Noco.ncMeta, ): Promise { @@ -131,12 +173,17 @@ export default class Sort { let { list: sortList } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !sortList.length) { - sortList = await ncMeta.metaList2(null, null, MetaTable.SORT, { - condition: { fk_view_id: viewId }, - orderBy: { - order: 'asc', + sortList = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.SORT, + { + condition: { fk_view_id: viewId }, + orderBy: { + order: 'asc', + }, }, - }); + ); await NocoCache.setList(CacheScope.SORT, [viewId], sortList); } sortList.sort( @@ -147,11 +194,16 @@ export default class Sort { return sortList.map((s) => new Sort(s)); } - public static async update(sortId, body, ncMeta = Noco.ncMeta) { + public static async update( + context: NcContext, + sortId, + body, + ncMeta = Noco.ncMeta, + ) { // set meta const res = await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.SORT, { fk_column_id: body.fk_column_id, @@ -167,18 +219,32 @@ export default class Sort { // on update, delete any optimised single query cache { - const sort = await this.get(sortId, ncMeta); - const view = await View.get(sort.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const sort = await this.get(context, sortId, ncMeta); + const view = await View.get(context, sort.fk_view_id, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } return res; } - public static async delete(sortId: string, ncMeta = Noco.ncMeta) { - const sort = await this.get(sortId, ncMeta); + public static async delete( + context: NcContext, + sortId: string, + ncMeta = Noco.ncMeta, + ) { + const sort = await this.get(context, sortId, ncMeta); - await ncMeta.metaDelete(null, null, MetaTable.SORT, sortId); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.SORT, + sortId, + ); await NocoCache.deepDel( `${CacheScope.SORT}:${sortId}`, @@ -187,12 +253,17 @@ export default class Sort { // on delete, delete any optimised single query cache if (sort?.fk_view_id) { - const view = await View.get(sort.fk_view_id, ncMeta); - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + const view = await View.get(context, sort.fk_view_id, ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); } } - public static async get(id: any, ncMeta = Noco.ncMeta) { + public static async get(context: NcContext, id: any, ncMeta = Noco.ncMeta) { let sortData = id && (await NocoCache.get( @@ -200,14 +271,23 @@ export default class Sort { CacheGetType.TYPE_OBJECT, )); if (!sortData) { - sortData = await ncMeta.metaGet2(null, null, MetaTable.SORT, id); + sortData = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.SORT, + id, + ); await NocoCache.set(`${CacheScope.SORT}:${id}`, sortData); } return sortData && new Sort(sortData); } - public async getModel(ncMeta = Noco.ncMeta): Promise { + public async getModel( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return Model.getByIdOrName( + context, { id: this.fk_view_id, }, diff --git a/packages/nocodb/src/models/Source.ts b/packages/nocodb/src/models/Source.ts index 54de376512..22a58937e8 100644 --- a/packages/nocodb/src/models/Source.ts +++ b/packages/nocodb/src/models/Source.ts @@ -3,6 +3,7 @@ import CryptoJS from 'crypto-js'; import { v4 as uuidv4 } from 'uuid'; import type { DriverClient } from '~/utils/nc-config'; import type { BoolType, SourceType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import { Base, Model, SyncSource } from '~/models'; import NocoCache from '~/cache/NocoCache'; import { @@ -27,6 +28,7 @@ import { InstanceCommands } from '~/interface/Jobs'; // todo: hide credentials export default class Source implements SourceType { id?: string; + fk_workspace_id?: string; base_id?: string; alias?: string; type?: DriverClient; @@ -48,6 +50,7 @@ export default class Source implements SourceType { } public static async createBase( + context: NcContext, source: SourceType & { baseId: string; created_at?; @@ -83,14 +86,13 @@ export default class Source implements SourceType { }); const { id } = await ncMeta.metaInsert2( - source.baseId, - null, + context.workspace_id, + context.base_id, MetaTable.BASES, insertObj, ); - // call before reorder to update cache - const returnBase = await this.get(id, false, ncMeta); + const returnBase = await this.get(context, id, false, ncMeta); await NocoCache.appendToList( CacheScope.BASE, @@ -102,6 +104,7 @@ export default class Source implements SourceType { } public static async updateBase( + context: NcContext, sourceId: string, source: SourceType & { baseId: string; @@ -111,9 +114,9 @@ export default class Source implements SourceType { }, ncMeta = Noco.ncMeta, ) { - const oldBase = await Source.get(sourceId, false, ncMeta); + const oldSource = await Source.get(context, sourceId, false, ncMeta); - if (!oldBase) NcError.sourceNotFound(sourceId); + if (!oldSource) NcError.sourceNotFound(sourceId); const updateObj = extractProps(source, [ 'alias', @@ -138,33 +141,33 @@ export default class Source implements SourceType { // type property is undefined even if not provided if (!updateObj.type) { - updateObj.type = oldBase.type; + updateObj.type = oldSource.type; } // if order is missing (possible in old versions), get next order - if (!oldBase.order && !updateObj.order) { + if (!oldSource.order && !updateObj.order) { updateObj.order = await ncMeta.metaGetNextOrder(MetaTable.BASES, { base_id: source.baseId, }); - if (updateObj.order <= 1 && !oldBase.isMeta()) { + if (updateObj.order <= 1 && !oldSource.isMeta()) { updateObj.order = 2; } } // keep order 1 for default source - if (oldBase.isMeta()) { + if (oldSource.isMeta()) { updateObj.order = 1; } // keep order 1 for default source - if (!oldBase.isMeta()) { + if (!oldSource.isMeta()) { if (updateObj.order <= 1) { NcError.badRequest('Cannot change order to 1 or less'); } // if order is 1 for non-default source, move it to last - if (oldBase.order <= 1 && !updateObj.order) { + if (oldSource.order <= 1 && !updateObj.order) { updateObj.order = await ncMeta.metaGetNextOrder(MetaTable.BASES, { base_id: source.baseId, }); @@ -172,11 +175,11 @@ export default class Source implements SourceType { } await ncMeta.metaUpdate( - source.baseId, - null, + context.workspace_id, + context.base_id, MetaTable.BASES, prepareForDb(updateObj), - oldBase.id, + oldSource.id, ); await NocoCache.update( @@ -190,12 +193,13 @@ export default class Source implements SourceType { } // call before reorder to update cache - const returnBase = await this.get(oldBase.id, false, ncMeta); + const returnBase = await this.get(context, oldSource.id, false, ncMeta); return returnBase; } static async list( + context: NcContext, args: { baseId: string }, ncMeta = Noco.ncMeta, ): Promise { @@ -204,8 +208,8 @@ export default class Source implements SourceType { const { isNoneList } = cachedList; if (!isNoneList && !baseDataList.length) { baseDataList = await ncMeta.metaList2( - args.baseId, - null, + context.workspace_id, + context.base_id, MetaTable.BASES, { xcCondition: { @@ -246,6 +250,7 @@ export default class Source implements SourceType { } static async get( + context: NcContext, id: string, force = false, ncMeta = Noco.ncMeta, @@ -258,8 +263,8 @@ export default class Source implements SourceType { )); if (!baseData) { baseData = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.BASES, id, null, @@ -290,10 +295,14 @@ export default class Source implements SourceType { return this.castType(baseData); } - static async getByUUID(uuid: string, ncMeta = Noco.ncMeta) { + static async getByUUID( + context: NcContext, + uuid: string, + ncMeta = Noco.ncMeta, + ) { const source = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.BASES, { erd_uuid: uuid, @@ -354,8 +363,8 @@ export default class Source implements SourceType { return config; } - getProject(ncMeta = Noco.ncMeta): Promise { - return Base.get(this.base_id, ncMeta); + getProject(context: NcContext, ncMeta = Noco.ncMeta): Promise { + return Base.get(context, this.base_id, ncMeta); } async sourceCleanup(_ncMeta = Noco.ncMeta) { @@ -367,14 +376,23 @@ export default class Source implements SourceType { } } - async delete(ncMeta = Noco.ncMeta, { force }: { force?: boolean } = {}) { - const sources = await Source.list({ baseId: this.base_id }, ncMeta); + async delete( + context: NcContext, + ncMeta = Noco.ncMeta, + { force }: { force?: boolean } = {}, + ) { + const sources = await Source.list( + context, + { baseId: this.base_id }, + ncMeta, + ); if (sources[0].id === this.id && !force) { NcError.badRequest('Cannot delete first source'); } const models = await Model.list( + context, { source_id: this.id, base_id: this.base_id, @@ -391,7 +409,7 @@ export default class Source implements SourceType { }; for (const model of models) { - for (const col of await model.getColumns(ncMeta)) { + for (const col of await model.getColumns(context, ncMeta)) { let colOptionTableName = null; let cacheScopeName = null; switch (col.uidt) { @@ -420,9 +438,14 @@ export default class Source implements SourceType { }); for (const relCol of relColumns) { - await ncMeta.metaDelete(null, null, relCol.colOptionTableName, { - fk_column_id: relCol.col.id, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + relCol.colOptionTableName, + { + fk_column_id: relCol.col.id, + }, + ); await NocoCache.deepDel( `${relCol.cacheScopeName}:${relCol.col.id}`, CacheDelDirection.CHILD_TO_PARENT, @@ -430,17 +453,27 @@ export default class Source implements SourceType { } for (const model of models) { - await model.delete(ncMeta, true); + await model.delete(context, ncMeta, true); } - const syncSources = await SyncSource.list(this.base_id, this.id, ncMeta); + const syncSources = await SyncSource.list( + context, + this.base_id, + this.id, + ncMeta, + ); for (const syncSource of syncSources) { - await SyncSource.delete(syncSource.id, ncMeta); + await SyncSource.delete(context, syncSource.id, ncMeta); } await this.sourceCleanup(ncMeta); - const res = await ncMeta.metaDelete(null, null, MetaTable.BASES, this.id); + const res = await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.BASES, + this.id, + ); await NocoCache.deepDel( `${CacheScope.BASE}:${this.id}`, @@ -450,7 +483,11 @@ export default class Source implements SourceType { return res; } - async softDelete(ncMeta = Noco.ncMeta, { force }: { force?: boolean } = {}) { + async softDelete( + context: NcContext, + ncMeta = Noco.ncMeta, + { force }: { force?: boolean } = {}, + ) { const bases = await Base.list({ baseId: this.base_id }, ncMeta); if (bases[0].id === this.id && !force) { @@ -458,8 +495,8 @@ export default class Source implements SourceType { } await ncMeta.metaUpdate( - this.base_id, - null, + context.workspace_id, + context.base_id, MetaTable.BASES, { deleted: true, @@ -473,22 +510,23 @@ export default class Source implements SourceType { ); } - async getModels(ncMeta = Noco.ncMeta) { + async getModels(context: NcContext, ncMeta = Noco.ncMeta) { return await Model.list( + context, { base_id: this.base_id, source_id: this.id }, ncMeta, ); } - async shareErd(ncMeta = Noco.ncMeta) { + async shareErd(context: NcContext, ncMeta = Noco.ncMeta) { if (!this.erd_uuid) { const uuid = uuidv4(); this.erd_uuid = uuid; // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.BASES, { erd_uuid: this.erd_uuid, @@ -503,14 +541,14 @@ export default class Source implements SourceType { return this; } - async disableShareErd(ncMeta = Noco.ncMeta) { + async disableShareErd(context: NcContext, ncMeta = Noco.ncMeta) { if (this.erd_uuid) { this.erd_uuid = null; // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.BASES, { erd_uuid: this.erd_uuid, diff --git a/packages/nocodb/src/models/Store.ts b/packages/nocodb/src/models/Store.ts index 11c96ef58b..6a00217084 100644 --- a/packages/nocodb/src/models/Store.ts +++ b/packages/nocodb/src/models/Store.ts @@ -2,7 +2,12 @@ import type { SortType } from 'nocodb-sdk'; import { NcError } from '~/helpers/catchError'; import { extractProps } from '~/helpers/extractProps'; import Noco from '~/Noco'; -import { CacheGetType, CacheScope, MetaTable } from '~/utils/globals'; +import { + CacheGetType, + CacheScope, + MetaTable, + RootScopes, +} from '~/utils/globals'; import NocoCache from '~/cache/NocoCache'; // Store is used for storing key value pairs @@ -35,9 +40,14 @@ export default class Store { if (storeData) return storeData; } - const storeData = await ncMeta.metaGet(null, null, MetaTable.STORE, { - key, - }); + const storeData = await ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.STORE, + { + key, + }, + ); if (lookInCache) await NocoCache.set(`${CacheScope.STORE}:${key}`, storeData); @@ -60,11 +70,23 @@ export default class Store { const existing = await Store.get(store.key, false, ncMeta); if (existing) { - await ncMeta.metaUpdate(null, null, MetaTable.STORE, insertObj, { - key: store.key, - }); + await ncMeta.metaUpdate( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.STORE, + insertObj, + { + key: store.key, + }, + ); } else { - await ncMeta.metaInsert(null, null, MetaTable.STORE, insertObj); + await ncMeta.metaInsert2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.STORE, + insertObj, + true, + ); } if (store.key) await NocoCache.del(`${CacheScope.STORE}:${store.key}`); } diff --git a/packages/nocodb/src/models/SyncLogs.ts b/packages/nocodb/src/models/SyncLogs.ts index a83a13fbd8..f779a141fd 100644 --- a/packages/nocodb/src/models/SyncLogs.ts +++ b/packages/nocodb/src/models/SyncLogs.ts @@ -1,9 +1,11 @@ +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; import { extractProps } from '~/helpers/extractProps'; import { MetaTable } from '~/utils/globals'; export default class SyncLogs { id?: string; + fk_workspace_id?: string; base_id?: string; fk_sync_source_id?: string; time_taken?: string; @@ -14,19 +16,28 @@ export default class SyncLogs { Object.assign(this, syncLog); } - static async list(baseId: string, ncMeta = Noco.ncMeta) { - const syncLogs = await ncMeta.metaList(null, null, MetaTable.SYNC_LOGS, { - condition: { - base_id: baseId, - }, - orderBy: { - created_at: 'asc', + static async list(context: NcContext, baseId: string, ncMeta = Noco.ncMeta) { + const syncLogs = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.SYNC_LOGS, + { + condition: { + base_id: baseId, + }, + orderBy: { + created_at: 'asc', + }, }, - }); + ); return syncLogs?.map((h) => new SyncLogs(h)); } - public static async insert(syncLog: Partial, ncMeta = Noco.ncMeta) { + public static async insert( + context: NcContext, + syncLog: Partial, + ncMeta = Noco.ncMeta, + ) { const insertObj = extractProps(syncLog, [ 'base_id', 'fk_sync_source_id', @@ -36,15 +47,11 @@ export default class SyncLogs { ]); const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.SYNC_LOGS, insertObj, ); return new SyncLogs({ ...insertObj, id }); } - - static async delete(syncLogId: any, ncMeta = Noco.ncMeta) { - return await ncMeta.metaDelete(null, null, MetaTable.SYNC_LOGS, syncLogId); - } } diff --git a/packages/nocodb/src/models/SyncSource.ts b/packages/nocodb/src/models/SyncSource.ts index cace2a5244..2c3e42e698 100644 --- a/packages/nocodb/src/models/SyncSource.ts +++ b/packages/nocodb/src/models/SyncSource.ts @@ -1,3 +1,4 @@ +import type { NcContext } from '~/interface/config'; import User from '~/models/User'; import { NcError } from '~/helpers/catchError'; import Noco from '~/Noco'; @@ -11,6 +12,7 @@ export default class SyncSource { details?: any; deleted?: boolean; order?: number; + fk_workspace_id?: string; base_id?: string; source_id?: string; fk_user_id?: string; @@ -23,10 +25,14 @@ export default class SyncSource { return User.get(this.fk_user_id, ncMeta); } - public static async get(syncSourceId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + syncSourceId: string, + ncMeta = Noco.ncMeta, + ) { const syncSource = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.SYNC_SOURCE, syncSourceId, ); @@ -38,13 +44,18 @@ export default class SyncSource { return syncSource && new SyncSource(syncSource); } - static async list(baseId: string, sourceId?: string, ncMeta = Noco.ncMeta) { + static async list( + context: NcContext, + baseId: string, + sourceId?: string, + ncMeta = Noco.ncMeta, + ) { const condition = sourceId ? { base_id: baseId, source_id: sourceId } : { base_id: baseId }; - const syncSources = await ncMeta.metaList( - null, - null, + const syncSources = await ncMeta.metaList2( + context.workspace_id, + context.base_id, MetaTable.SYNC_SOURCE, { condition, @@ -65,6 +76,7 @@ export default class SyncSource { } public static async insert( + context: NcContext, syncSource: Partial, ncMeta = Noco.ncMeta, ) { @@ -83,16 +95,17 @@ export default class SyncSource { } const { id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.SYNC_SOURCE, insertObj, ); - return this.get(id, ncMeta); + return this.get(context, id, ncMeta); } public static async update( + context: NcContext, syncSourceId: string, syncSource: Partial, ncMeta = Noco.ncMeta, @@ -114,29 +127,39 @@ export default class SyncSource { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.SYNC_SOURCE, updateObj, syncSourceId, ); - return this.get(syncSourceId, ncMeta); + return this.get(context, syncSourceId, ncMeta); } - static async delete(syncSourceId: any, ncMeta = Noco.ncMeta) { + static async delete( + context: NcContext, + syncSourceId: any, + ncMeta = Noco.ncMeta, + ) { return await ncMeta.metaDelete( - null, - null, + context.workspace_id, + context.base_id, MetaTable.SYNC_SOURCE, syncSourceId, ); } - static async deleteByUserId(userId: string, ncMeta = Noco.ncMeta) { + static async deleteByUserId( + context: NcContext, + userId: string, + ncMeta = Noco.ncMeta, + ) { + throw new Error('Method not implemented.'); + if (!userId) NcError.badRequest('User Id is required'); - return await ncMeta.metaDelete(null, null, MetaTable.SYNC_SOURCE, { + return await ncMeta.metaDeleteAll(MetaTable.SYNC_SOURCE, { fk_user_id: userId, }); } diff --git a/packages/nocodb/src/models/User.ts b/packages/nocodb/src/models/User.ts index 348c6db438..1183662626 100644 --- a/packages/nocodb/src/models/User.ts +++ b/packages/nocodb/src/models/User.ts @@ -1,4 +1,5 @@ import { extractRolesObj, type UserType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import { NcError } from '~/helpers/catchError'; import Noco from '~/Noco'; import { extractProps } from '~/helpers/extractProps'; @@ -8,6 +9,7 @@ import { CacheGetType, CacheScope, MetaTable, + RootScopes, } from '~/utils/globals'; import { Base, BaseUser, UserRefreshToken } from '~/models'; import { sanitiseUserObj } from '~/utils'; @@ -64,8 +66,8 @@ export default class User implements UserType { } const { id } = await ncMeta.metaInsert2( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.USERS, insertObj, ); @@ -120,7 +122,13 @@ export default class User implements UserType { // delete the email-based cache to avoid unexpected behaviour since we can update email as well await NocoCache.del(`${CacheScope.USER}:${existingUser.email}`); - await ncMeta.metaUpdate(null, null, MetaTable.USERS, updateObj, id); + await ncMeta.metaUpdate( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + updateObj, + id, + ); // clear all user related cache await this.clearCache(id, ncMeta); @@ -137,16 +145,26 @@ export default class User implements UserType { CacheGetType.TYPE_OBJECT, )); if (!user) { - user = await ncMeta.metaGet2(null, null, MetaTable.USERS, { - email, - }); + user = await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + { + email, + }, + ); await NocoCache.set(`${CacheScope.USER}:${email}`, user); } return this.castType(user); } static async isFirst(ncMeta = Noco.ncMeta) { - return !(await ncMeta.metaGet2(null, null, MetaTable.USERS, {})); + return !(await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + {}, + )); } public static async count( @@ -174,7 +192,12 @@ export default class User implements UserType { CacheGetType.TYPE_OBJECT, )); if (!user) { - user = await ncMeta.metaGet2(null, null, MetaTable.USERS, userId); + user = await ncMeta.metaGet2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + userId, + ); await NocoCache.set(`${CacheScope.USER}:${userId}`, user); } return this.castType(user); @@ -191,8 +214,8 @@ export default class User implements UserType { } return await ncMeta.metaGet2( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.USERS, userRefreshToken.fk_user_id, ); @@ -261,10 +284,16 @@ export default class User implements UserType { // clear all user related cache await this.clearCache(userId, ncMeta); - return await ncMeta.metaDelete(null, null, MetaTable.USERS, userId); + return await ncMeta.metaDelete( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + userId, + ); } static async getWithRoles( + context: NcContext, userId: string, args: { user?: User; @@ -279,7 +308,7 @@ export default class User implements UserType { const baseRoles = await new Promise((resolve) => { if (args.baseId) { - BaseUser.get(args.baseId, user.id).then(async (baseUser) => { + BaseUser.get(context, args.baseId, user.id).then(async (baseUser) => { const roles = baseUser?.roles; // + (user.roles ? `,${user.roles}` : ''); if (roles) { diff --git a/packages/nocodb/src/models/UserRefreshToken.ts b/packages/nocodb/src/models/UserRefreshToken.ts index 79c2602f78..2d629c3e0c 100644 --- a/packages/nocodb/src/models/UserRefreshToken.ts +++ b/packages/nocodb/src/models/UserRefreshToken.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs'; import Noco from '~/Noco'; import { extractProps } from '~/helpers/extractProps'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; import { parseMetaProp, stringifyMetaProp } from '~/utils/modelUtils'; const NC_REFRESH_TOKEN_EXP_IN_DAYS = @@ -27,8 +27,8 @@ export default class UserRefreshToken { // clear old invalid tokens before inserting new one // todo: verify the populated sql query await ncMeta.metaDelete( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.USER_REFRESH_TOKENS, { fk_user_id: userRefreshToken.fk_user_id, @@ -59,8 +59,8 @@ export default class UserRefreshToken { } await ncMeta.metaInsert2( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.USER_REFRESH_TOKENS, insertObj, true, @@ -75,8 +75,8 @@ export default class UserRefreshToken { ncMeta = Noco.ncMeta, ) { return await ncMeta.metaUpdate( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.USER_REFRESH_TOKENS, { token: newToken, @@ -89,15 +89,25 @@ export default class UserRefreshToken { } static async deleteToken(token: string, ncMeta = Noco.ncMeta) { - return await ncMeta.metaDelete(null, null, MetaTable.USER_REFRESH_TOKENS, { - token, - }); + return await ncMeta.metaDelete( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USER_REFRESH_TOKENS, + { + token, + }, + ); } static async deleteAllUserToken(userId: string, ncMeta = Noco.ncMeta) { - return await ncMeta.metaDelete(null, null, MetaTable.USER_REFRESH_TOKENS, { - fk_user_id: userId, - }); + return await ncMeta.metaDelete( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USER_REFRESH_TOKENS, + { + fk_user_id: userId, + }, + ); } static async getByToken( @@ -105,8 +115,8 @@ export default class UserRefreshToken { ncMeta = Noco.ncMeta, ): Promise { const userToken = await ncMeta.metaGet2( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.USER_REFRESH_TOKENS, { token, diff --git a/packages/nocodb/src/models/View.ts b/packages/nocodb/src/models/View.ts index 584f2ec60e..26f665a859 100644 --- a/packages/nocodb/src/models/View.ts +++ b/packages/nocodb/src/models/View.ts @@ -1,5 +1,6 @@ import { isSystemColumn, UITypes, ViewTypes } from 'nocodb-sdk'; import type { BoolType, ColumnReqType, ViewType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import Model from '~/models/Model'; import FormView from '~/models/FormView'; import GridView from '~/models/GridView'; @@ -83,6 +84,7 @@ export default class View implements ViewType { sorts: Sort[]; filter: Filter; + fk_workspace_id?: string; base_id?: string; source_id?: string; show_system_fields?: boolean; @@ -92,7 +94,11 @@ export default class View implements ViewType { Object.assign(this, data); } - public static async get(viewId: string, ncMeta = Noco.ncMeta) { + public static async get( + context: NcContext, + viewId: string, + ncMeta = Noco.ncMeta, + ) { let view = viewId && (await NocoCache.get( @@ -100,7 +106,12 @@ export default class View implements ViewType { CacheGetType.TYPE_OBJECT, )); if (!view) { - view = await ncMeta.metaGet2(null, null, MetaTable.VIEWS, viewId); + view = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.VIEWS, + viewId, + ); if (view) { view.meta = parseMetaProp(view); await NocoCache.set(`${CacheScope.VIEW}:${view.id}`, view); @@ -111,6 +122,7 @@ export default class View implements ViewType { } public static async getByTitleOrId( + context: NcContext, { fk_model_id, titleOrId }: { titleOrId: string; fk_model_id: string }, ncMeta = Noco.ncMeta, ) { @@ -122,8 +134,8 @@ export default class View implements ViewType { )); if (!viewId) { const view = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, { fk_model_id }, null, @@ -157,10 +169,11 @@ export default class View implements ViewType { } return view && new View(view); } - return viewId && this.get(viewId?.id || viewId); + return viewId && this.get(context, viewId?.id || viewId); } public static async getDefaultView( + context: NcContext, fk_model_id: string, ncMeta = Noco.ncMeta, ) { @@ -172,8 +185,8 @@ export default class View implements ViewType { )); if (!view) { view = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, { fk_model_id, @@ -189,19 +202,28 @@ export default class View implements ViewType { return view && new View(view); } - public static async list(modelId: string, ncMeta = Noco.ncMeta) { + public static async list( + context: NcContext, + modelId: string, + ncMeta = Noco.ncMeta, + ) { const cachedList = await NocoCache.getList(CacheScope.VIEW, [modelId]); let { list: viewsList } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !viewsList.length) { - viewsList = await ncMeta.metaList2(null, null, MetaTable.VIEWS, { - condition: { - fk_model_id: modelId, - }, - orderBy: { - order: 'asc', + viewsList = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.VIEWS, + { + condition: { + fk_model_id: modelId, + }, + orderBy: { + order: 'asc', + }, }, - }); + ); for (const view of viewsList) { view.meta = parseMetaProp(view); } @@ -216,6 +238,7 @@ export default class View implements ViewType { } static async insert( + context: NcContext, view: Partial & Partial< FormView | GridView | GalleryView | KanbanView | MapView | CalendarView @@ -250,32 +273,37 @@ export default class View implements ViewType { insertObj.meta = stringifyMetaProp(insertObj); + const model = await Model.getByIdOrName( + context, + { id: view.fk_model_id }, + ncMeta, + ); + // get base and base id if missing - if (!(view.base_id && view.source_id)) { - const model = await Model.getByIdOrName({ id: view.fk_model_id }, ncMeta); - insertObj.base_id = model.base_id; + if (!view.source_id) { insertObj.source_id = model.source_id; } const copyFromView = - view.copy_from_id && (await View.get(view.copy_from_id, ncMeta)); - await copyFromView?.getView(); + view.copy_from_id && (await View.get(context, view.copy_from_id, ncMeta)); + await copyFromView?.getView(context); const { id: view_id } = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, insertObj, ); let columns: any[] = await ( - await Model.getByIdOrName({ id: view.fk_model_id }, ncMeta) - ).getColumns(ncMeta); + await Model.getByIdOrName(context, { id: view.fk_model_id }, ncMeta) + ).getColumns(context, ncMeta); // insert view metadata based on view type switch (view.type) { case ViewTypes.GRID: await GridView.insert( + context, { ...((copyFromView?.view as GridView) || {}), ...(view as GridView), @@ -286,6 +314,7 @@ export default class View implements ViewType { break; case ViewTypes.MAP: await MapView.insert( + context, { ...(view as MapView), fk_view_id: view_id, @@ -295,6 +324,7 @@ export default class View implements ViewType { break; case ViewTypes.GALLERY: await GalleryView.insert( + context, { ...(copyFromView?.view || {}), ...view, @@ -305,6 +335,7 @@ export default class View implements ViewType { break; case ViewTypes.FORM: await FormView.insert( + context, { heading: view.title, ...(copyFromView?.view || {}), @@ -319,6 +350,7 @@ export default class View implements ViewType { (view as KanbanView).fk_grp_col_id = view.fk_grp_col_id; await KanbanView.insert( + context, { ...(copyFromView?.view || {}), ...view, @@ -336,6 +368,7 @@ export default class View implements ViewType { }); await CalendarView.insert( + context, { ...(copyFromView?.view || {}), ...view, @@ -344,17 +377,18 @@ export default class View implements ViewType { ncMeta, ); - await CalendarRange.bulkInsert(calendarRange, ncMeta); + await CalendarRange.bulkInsert(context, calendarRange, ncMeta); } } if (copyFromView) { - const sorts = await copyFromView.getSorts(ncMeta); - const filters = await copyFromView.getFilters(ncMeta); - columns = await copyFromView.getColumns(ncMeta); + const sorts = await copyFromView.getSorts(context, ncMeta); + const filters = await copyFromView.getFilters(context, ncMeta); + columns = await copyFromView.getColumns(context, ncMeta); for (const sort of sorts) { await Sort.insert( + context, { ...extractProps(sort, [ 'fk_column_id', @@ -372,6 +406,7 @@ export default class View implements ViewType { for (const filter of filters.children) { await Filter.insert( + context, { ...extractProps(filter, [ 'id', @@ -400,7 +435,11 @@ export default class View implements ViewType { let calendarRanges: Array | null = null; if (view.type === ViewTypes.CALENDAR) { - calendarRanges = await View.getRangeColumnsAsArray(view_id, ncMeta); + calendarRanges = await View.getRangeColumnsAsArray( + context, + view_id, + ncMeta, + ); } if (view.type === ViewTypes.KANBAN && !copyFromView) { @@ -433,7 +472,7 @@ export default class View implements ViewType { const italic = false; if (view.type === ViewTypes.GALLERY) { - const galleryView = await GalleryView.get(view_id, ncMeta); + const galleryView = await GalleryView.get(context, view_id, ncMeta); if ( vCol.id === galleryView.fk_cover_image_col_id || vCol.pv || @@ -445,7 +484,7 @@ export default class View implements ViewType { show = false; } } else if (view.type === ViewTypes.KANBAN && !copyFromView) { - const kanbanView = await KanbanView.get(view_id, ncMeta); + const kanbanView = await KanbanView.get(context, view_id, ncMeta); if (vCol.id === kanbanView?.fk_grp_col_id) { // include grouping field if it exists show = true; @@ -462,14 +501,14 @@ export default class View implements ViewType { show = false; } } else if (view.type === ViewTypes.CALENDAR && !copyFromView) { - const calendarView = await CalendarView.get(view_id, ncMeta); + const calendarView = await CalendarView.get(context, view_id, ncMeta); if (calendarRanges && calendarRanges.includes(vCol.id)) { show = true; } else show = vCol.id === calendarView?.fk_cover_image_col_id || vCol.pv; // Show all Fields in Ranges } else if (view.type === ViewTypes.MAP && !copyFromView) { - const mapView = await MapView.get(view_id, ncMeta); + const mapView = await MapView.get(context, view_id, ncMeta); if (vCol.id === mapView?.fk_geo_data_col_id) { show = true; } @@ -477,11 +516,12 @@ export default class View implements ViewType { // if columns is list of virtual columns then get the parent column const col = vCol.fk_column_id - ? await Column.get({ colId: vCol.fk_column_id }, ncMeta) + ? await Column.get(context, { colId: vCol.fk_column_id }, ncMeta) : vCol; if (isSystemColumn(col)) show = false; await View.insertColumn( + context, { order: order++, ...col, @@ -500,11 +540,12 @@ export default class View implements ViewType { } await Model.getNonDefaultViewsCountAndReset( + context, { modelId: view.fk_model_id }, ncMeta, ); - return View.get(view_id, ncMeta).then(async (v) => { + return View.get(context, view_id, ncMeta).then(async (v) => { await NocoCache.appendToList( CacheScope.VIEW, [view.fk_model_id], @@ -514,8 +555,12 @@ export default class View implements ViewType { }); } - static async getRangeColumnsAsArray(viewId: string, ncMeta) { - const calRange = await CalendarRange.read(viewId, ncMeta); + static async getRangeColumnsAsArray( + context: NcContext, + viewId: string, + ncMeta, + ) { + const calRange = await CalendarRange.read(context, viewId, ncMeta); if (calRange) { const calIds: Set = new Set(); calRange.ranges.forEach((range) => { @@ -527,6 +572,7 @@ export default class View implements ViewType { } static async insertColumnToAllViews( + context: NcContext, param: { fk_column_id: any; fk_model_id: any; @@ -544,9 +590,10 @@ export default class View implements ViewType { order: param.order, show: param.column_show.show, }; - const views = await this.list(param.fk_model_id, ncMeta); + const views = await this.list(context, param.fk_model_id, ncMeta); const tableColumns = await Column.list( + context, { fk_model_id: param.fk_model_id }, ncMeta, ); @@ -567,14 +614,14 @@ export default class View implements ViewType { // if gallery/kanban view, show only 3 columns(excluding system columns) else if (view.type === ViewTypes.GALLERY) { const visibleColumnsCount = ( - await GalleryViewColumn.list(view.id, ncMeta) + await GalleryViewColumn.list(context, view.id, ncMeta) )?.filter( (c) => c.show && !isSystemColumn(colIdMap.get(c.fk_column_id)), ).length; modifiedInsertObj.show = visibleColumnsCount < 3; } else if (view.type === ViewTypes.KANBAN) { const visibleColumnsCount = ( - await KanbanViewColumn.list(view.id, ncMeta) + await KanbanViewColumn.list(context, view.id, ncMeta) )?.filter( (c) => c.show && !isSystemColumn(colIdMap.get(c.fk_column_id)), ).length; @@ -589,14 +636,15 @@ export default class View implements ViewType { switch (view.type) { case ViewTypes.GRID: - await GridViewColumn.insert(modifiedInsertObj, ncMeta); + await GridViewColumn.insert(context, modifiedInsertObj, ncMeta); break; case ViewTypes.GALLERY: - await GalleryViewColumn.insert(modifiedInsertObj, ncMeta); + await GalleryViewColumn.insert(context, modifiedInsertObj, ncMeta); break; case ViewTypes.MAP: await MapViewColumn.insert( + context, { ...insertObj, fk_view_id: view.id, @@ -605,10 +653,11 @@ export default class View implements ViewType { ); break; case ViewTypes.KANBAN: - await KanbanViewColumn.insert(modifiedInsertObj, ncMeta); + await KanbanViewColumn.insert(context, modifiedInsertObj, ncMeta); break; case ViewTypes.CALENDAR: await CalendarViewColumn.insert( + context, { ...insertObj, fk_view_id: view.id, @@ -617,13 +666,14 @@ export default class View implements ViewType { ); break; case ViewTypes.FORM: - await FormViewColumn.insert(modifiedInsertObj, ncMeta); + await FormViewColumn.insert(context, modifiedInsertObj, ncMeta); break; } } } static async insertColumn( + context: NcContext, param: { view_id: any; order; @@ -637,13 +687,14 @@ export default class View implements ViewType { Partial, ncMeta = Noco.ncMeta, ) { - const view = await this.get(param.view_id, ncMeta); + const view = await this.get(context, param.view_id, ncMeta); let col; switch (view.type) { case ViewTypes.GRID: { col = await GridViewColumn.insert( + context, { ...param, fk_view_id: view.id, @@ -655,6 +706,7 @@ export default class View implements ViewType { case ViewTypes.GALLERY: { col = await GalleryViewColumn.insert( + context, { ...param, fk_view_id: view.id, @@ -666,6 +718,7 @@ export default class View implements ViewType { case ViewTypes.MAP: { col = await MapViewColumn.insert( + context, { ...param, fk_view_id: view.id, @@ -677,6 +730,7 @@ export default class View implements ViewType { case ViewTypes.FORM: { col = await FormViewColumn.insert( + context, { ...param, fk_view_id: view.id, @@ -688,6 +742,7 @@ export default class View implements ViewType { case ViewTypes.KANBAN: { col = await KanbanViewColumn.insert( + context, { ...param, fk_view_id: view.id, @@ -699,6 +754,7 @@ export default class View implements ViewType { case ViewTypes.CALENDAR: { col = await CalendarViewColumn.insert( + context, { ...param, fk_view_id: view.id, @@ -712,15 +768,20 @@ export default class View implements ViewType { return col; } - static async listWithInfo(id: string, ncMeta = Noco.ncMeta) { - const list = await this.list(id, ncMeta); + static async listWithInfo( + context: NcContext, + id: string, + ncMeta = Noco.ncMeta, + ) { + const list = await this.list(context, id, ncMeta); for (const item of list) { - await item.getViewWithInfo(ncMeta); + await item.getViewWithInfo(context, ncMeta); } return list; } static async getColumns( + context: NcContext, viewId: string, ncMeta = Noco.ncMeta, ): Promise< @@ -734,27 +795,27 @@ export default class View implements ViewType { > > { let columns: Array = []; - const view = await this.get(viewId, ncMeta); + const view = await this.get(context, viewId, ncMeta); // todo: just get - order & show props switch (view.type) { case ViewTypes.GRID: - columns = await GridViewColumn.list(viewId, ncMeta); + columns = await GridViewColumn.list(context, viewId, ncMeta); break; case ViewTypes.GALLERY: - columns = await GalleryViewColumn.list(viewId, ncMeta); + columns = await GalleryViewColumn.list(context, viewId, ncMeta); break; case ViewTypes.MAP: - columns = await MapViewColumn.list(viewId, ncMeta); + columns = await MapViewColumn.list(context, viewId, ncMeta); break; case ViewTypes.FORM: - columns = await FormViewColumn.list(viewId, ncMeta); + columns = await FormViewColumn.list(context, viewId, ncMeta); break; case ViewTypes.KANBAN: - columns = await KanbanViewColumn.list(viewId, ncMeta); + columns = await KanbanViewColumn.list(context, viewId, ncMeta); break; case ViewTypes.CALENDAR: - columns = await CalendarViewColumn.list(viewId, ncMeta); + columns = await CalendarViewColumn.list(context, viewId, ncMeta); break; } @@ -762,6 +823,7 @@ export default class View implements ViewType { } static async getViewColumnId( + context: NcContext, { viewId, colId, @@ -771,7 +833,7 @@ export default class View implements ViewType { }, ncMeta = Noco.ncMeta, ) { - const view = await this.get(viewId); + const view = await this.get(context, viewId); if (!view) return undefined; let tableName; @@ -813,10 +875,15 @@ export default class View implements ViewType { const o = await NocoCache.get(key, CacheGetType.TYPE_STRING); if (o) return o; - const viewColumn = await ncMeta.metaGet2(null, null, tableName, { - fk_view_id: viewId, - fk_column_id: colId, - }); + const viewColumn = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + tableName, + { + fk_view_id: viewId, + fk_column_id: colId, + }, + ); if (!viewColumn) return undefined; await NocoCache.set(key, viewColumn.id); @@ -825,6 +892,7 @@ export default class View implements ViewType { } static async updateColumn( + context: NcContext, viewId: string, colId: string, colData: { @@ -836,7 +904,7 @@ export default class View implements ViewType { }, ncMeta = Noco.ncMeta, ) { - const view = await this.get(viewId, ncMeta); + const view = await this.get(context, viewId, ncMeta); let table; let cacheScope; switch (view.type) { @@ -869,8 +937,8 @@ export default class View implements ViewType { // keep primary_value_column always visible and first in grid view if (view.type === ViewTypes.GRID) { const primary_value_column_meta = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, { fk_model_id: view.fk_model_id, @@ -879,8 +947,8 @@ export default class View implements ViewType { ); const primary_value_column = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, { fk_view_id: view.id, @@ -901,17 +969,24 @@ export default class View implements ViewType { } // set meta - const res = await ncMeta.metaUpdate(null, null, table, updateObj, colId); + const res = await ncMeta.metaUpdate( + context.workspace_id, + context.base_id, + table, + updateObj, + colId, + ); await NocoCache.update(`${cacheScope}:${colId}`, updateObj); // on view column update, delete corresponding single query cache - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + await View.clearSingleQueryCache(context, view.fk_model_id, [view], ncMeta); return res; } static async insertOrUpdateColumn( + context: NcContext, viewId: string, fkColId: string, colData: { @@ -927,18 +1002,23 @@ export default class View implements ViewType { | MapViewColumn | any > { - const view = await this.get(viewId); + const view = await this.get(context, viewId, ncMeta); const table = this.extractViewColumnsTableName(view); - const existingCol = await ncMeta.metaGet2(null, null, table, { - fk_view_id: viewId, - fk_column_id: fkColId, - }); + const existingCol = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + table, + { + fk_view_id: viewId, + fk_column_id: fkColId, + }, + ); if (existingCol) { await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, table, { order: colData.order, @@ -948,68 +1028,112 @@ export default class View implements ViewType { ); // on view column update, delete any optimised single query cache - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + await View.clearSingleQueryCache( + context, + view.fk_model_id, + [view], + ncMeta, + ); return { ...existingCol, ...colData }; } else { switch (view.type) { case ViewTypes.GRID: - return await GridViewColumn.insert({ - fk_view_id: viewId, - fk_column_id: fkColId, - order: colData.order, - show: colData.show, - }); + return await GridViewColumn.insert( + context, + { + fk_view_id: viewId, + fk_column_id: fkColId, + order: colData.order, + show: colData.show, + }, + ncMeta, + ); case ViewTypes.GALLERY: - return await GalleryViewColumn.insert({ - fk_view_id: viewId, - fk_column_id: fkColId, - order: colData.order, - show: colData.show, - }); + return await GalleryViewColumn.insert( + context, + { + fk_view_id: viewId, + fk_column_id: fkColId, + order: colData.order, + show: colData.show, + }, + ncMeta, + ); case ViewTypes.KANBAN: - return await KanbanViewColumn.insert({ - fk_view_id: viewId, - fk_column_id: fkColId, - order: colData.order, - show: colData.show, - }); + return await KanbanViewColumn.insert( + context, + { + fk_view_id: viewId, + fk_column_id: fkColId, + order: colData.order, + show: colData.show, + }, + ncMeta, + ); case ViewTypes.MAP: - return await MapViewColumn.insert({ - fk_view_id: viewId, - fk_column_id: fkColId, - order: colData.order, - show: colData.show, - }); + return await MapViewColumn.insert( + context, + { + fk_view_id: viewId, + fk_column_id: fkColId, + order: colData.order, + show: colData.show, + }, + ncMeta, + ); case ViewTypes.FORM: - return await FormViewColumn.insert({ - fk_view_id: viewId, - fk_column_id: fkColId, - order: colData.order, - show: colData.show, - }); + return await FormViewColumn.insert( + context, + { + fk_view_id: viewId, + fk_column_id: fkColId, + order: colData.order, + show: colData.show, + }, + ncMeta, + ); case ViewTypes.CALENDAR: - return await CalendarViewColumn.insert({ - fk_view_id: viewId, - fk_column_id: fkColId, - order: colData.order, - show: colData.show, - }); + return await CalendarViewColumn.insert( + context, + { + fk_view_id: viewId, + fk_column_id: fkColId, + order: colData.order, + show: colData.show, + }, + ncMeta, + ); } - return await ncMeta.metaInsert2(view.base_id, view.source_id, table, { - fk_view_id: viewId, - fk_column_id: fkColId, - order: colData.order, - show: colData.show, - }); + return await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + table, + { + source_id: view.source_id, + fk_view_id: viewId, + fk_column_id: fkColId, + order: colData.order, + show: colData.show, + }, + ); } } // todo: cache - static async getByUUID(uuid: string, ncMeta = Noco.ncMeta) { - const view = await ncMeta.metaGet2(null, null, MetaTable.VIEWS, { - uuid, - }); + static async getByUUID( + context: NcContext, + uuid: string, + ncMeta = Noco.ncMeta, + ) { + const view = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.VIEWS, + { + uuid, + }, + ); if (view) { view.meta = parseMetaProp(view); @@ -1018,16 +1142,16 @@ export default class View implements ViewType { return view && new View(view); } - static async share(viewId, ncMeta = Noco.ncMeta) { - const view = await this.get(viewId); + static async share(context: NcContext, viewId, ncMeta = Noco.ncMeta) { + const view = await this.get(context, viewId); if (!view.uuid) { const uuid = uuidv4(); view.uuid = uuid; // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, { uuid: view.uuid, @@ -1048,8 +1172,8 @@ export default class View implements ViewType { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, prepareForDb({ meta: defaultMeta, @@ -1068,14 +1192,15 @@ export default class View implements ViewType { } static async passwordUpdate( + context: NcContext, viewId: string, { password }: { password: string }, ncMeta = Noco.ncMeta, ) { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, { password, @@ -1088,11 +1213,15 @@ export default class View implements ViewType { }); } - static async sharedViewDelete(viewId, ncMeta = Noco.ncMeta) { + static async sharedViewDelete( + context: NcContext, + viewId, + ncMeta = Noco.ncMeta, + ) { // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, { uuid: null, @@ -1106,6 +1235,7 @@ export default class View implements ViewType { } static async update( + context: NcContext, viewId: string, body: { title?: string; @@ -1128,12 +1258,12 @@ export default class View implements ViewType { 'uuid', ]); - const oldView = await this.get(viewId, ncMeta); + const oldView = await this.get(context, viewId, ncMeta); // set meta await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, prepareForDb(updateObj), viewId, @@ -1156,37 +1286,47 @@ export default class View implements ViewType { ); } - const view = await this.get(viewId); + const view = await this.get(context, viewId, ncMeta); if (view.type === ViewTypes.GRID) { if ('show_system_fields' in updateObj) { - await View.fixPVColumnForView(viewId, ncMeta); + await View.fixPVColumnForView(context, viewId, ncMeta); } } // on update, delete any optimised single query cache - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + await View.clearSingleQueryCache(context, view.fk_model_id, [view], ncMeta); return view; } // @ts-ignore - static async delete(viewId, ncMeta = Noco.ncMeta) { - const view = await this.get(viewId, ncMeta); - await Sort.deleteAll(viewId, ncMeta); - await Filter.deleteAll(viewId, ncMeta); + static async delete(context: NcContext, viewId, ncMeta = Noco.ncMeta) { + const view = await this.get(context, viewId, ncMeta); + await Sort.deleteAll(context, viewId, ncMeta); + await Filter.deleteAll(context, viewId, ncMeta); const table = this.extractViewTableName(view); const tableScope = this.extractViewTableNameScope(view); const columnTable = this.extractViewColumnsTableName(view); const columnTableScope = this.extractViewColumnsTableNameScope(view); - await ncMeta.metaDelete(null, null, columnTable, { - fk_view_id: viewId, - }); - await ncMeta.metaDelete(null, null, table, { + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + columnTable, + { + fk_view_id: viewId, + }, + ); + await ncMeta.metaDelete(context.workspace_id, context.base_id, table, { fk_view_id: viewId, }); - await ncMeta.metaDelete(null, null, MetaTable.VIEWS, viewId); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.VIEWS, + viewId, + ); await NocoCache.deepDel( `${tableScope}:${viewId}`, CacheDelDirection.CHILD_TO_PARENT, @@ -1194,9 +1334,14 @@ export default class View implements ViewType { // For Calendar View, delete the range associated with viewId if (view.type === ViewTypes.CALENDAR) { - await ncMeta.metaDelete(null, null, MetaTable.CALENDAR_VIEW_RANGE, { - fk_view_id: viewId, - }); + await ncMeta.metaDelete( + context.workspace_id, + context.base_id, + MetaTable.CALENDAR_VIEW_RANGE, + { + fk_view_id: viewId, + }, + ); await NocoCache.deepDel( `${CacheScope.CALENDAR_VIEW_RANGE}:${viewId}`, CacheDelDirection.CHILD_TO_PARENT, @@ -1218,8 +1363,8 @@ export default class View implements ViewType { if (view?.id) { // get all Links associated with the view and remove the view from the link const links = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_RELATIONS, { condition: { @@ -1229,33 +1374,35 @@ export default class View implements ViewType { ); for (const link of links) { - await LinkToAnotherRecordColumn.update(link.fk_column_id, { + await LinkToAnotherRecordColumn.update(context, link.fk_column_id, { fk_target_view_id: null, }); } } // on update, delete any optimised single query cache - await View.clearSingleQueryCache(view.fk_model_id, [view], ncMeta); + await View.clearSingleQueryCache(context, view.fk_model_id, [view], ncMeta); await Model.getNonDefaultViewsCountAndReset( + context, { modelId: view.fk_model_id }, ncMeta, ); } static async showAllColumns( + context: NcContext, viewId, ignoreColdIds = [], ncMeta = Noco.ncMeta, ) { - const view = await this.get(viewId); + const view = await this.get(context, viewId); const table = this.extractViewColumnsTableName(view); const scope = this.extractViewColumnsTableNameScope(view); const columns = await view - .getModel(ncMeta) - .then((meta) => meta.getColumns()); - const viewColumns = await this.getColumns(viewId, ncMeta); + .getModel(context, ncMeta) + .then((meta) => meta.getColumns(context, ncMeta)); + const viewColumns = await this.getColumns(context, viewId, ncMeta); const availableColumnsInView = viewColumns.map( (column) => column.fk_column_id, ); @@ -1282,6 +1429,7 @@ export default class View implements ViewType { const colIndex = availableColumnsInView.indexOf(col.id); if (colIndex > -1) { await this.updateColumn( + context, viewId, viewColumns[colIndex].id, { show: true }, @@ -1289,6 +1437,7 @@ export default class View implements ViewType { ); } else { await this.insertColumn( + context, { view_id: viewId, order: await ncMeta.metaGetNextOrder(table, { @@ -1302,8 +1451,8 @@ export default class View implements ViewType { } // return await ncMeta.metaUpdate( - // null, - // null, + // context.workspace_id, + // context.base_id, // table, // { show: true }, // { @@ -1323,18 +1472,19 @@ export default class View implements ViewType { } static async hideAllColumns( + context: NcContext, viewId, ignoreColdIds = [], ncMeta = Noco.ncMeta, ) { - const view = await this.get(viewId); + const view = await this.get(context, viewId, ncMeta); const table = this.extractViewColumnsTableName(view); const scope = this.extractViewColumnsTableNameScope(view); if (view.type === ViewTypes.GRID) { const primary_value_column = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, { fk_model_id: view.fk_model_id, @@ -1355,7 +1505,7 @@ export default class View implements ViewType { const colsEssentialForView = view.type === ViewTypes.MAP - ? [(await MapView.get(viewId)).fk_geo_data_col_id] + ? [(await MapView.get(context, viewId, ncMeta)).fk_geo_data_col_id] : []; const mergedIgnoreColdIds = [...ignoreColdIds, ...colsEssentialForView]; @@ -1375,8 +1525,8 @@ export default class View implements ViewType { } // set meta return await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, table, { show: false }, { @@ -1394,34 +1544,47 @@ export default class View implements ViewType { ); } - static async shareViewList(tableId, ncMeta = Noco.ncMeta) { + static async shareViewList( + context: NcContext, + tableId, + ncMeta = Noco.ncMeta, + ) { const cachedList = await NocoCache.getList(CacheScope.VIEW, [tableId]); let { list: sharedViews } = cachedList; const { isNoneList } = cachedList; if (!isNoneList && !sharedViews.length) { - sharedViews = await ncMeta.metaList2(null, null, MetaTable.VIEWS, { - xcCondition: { - fk_model_id: { - eq: tableId, - }, - _not: { - uuid: { - eq: null, + sharedViews = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.VIEWS, + { + xcCondition: { + fk_model_id: { + eq: tableId, + }, + _not: { + uuid: { + eq: null, + }, }, }, }, - }); + ); await NocoCache.setList(CacheScope.VIEW, [tableId], sharedViews); } sharedViews = sharedViews.filter((v) => v.uuid !== null); return sharedViews?.map((v) => new View(v)); } - static async fixPVColumnForView(viewId, ncMeta = Noco.ncMeta) { + static async fixPVColumnForView( + context: NcContext, + viewId, + ncMeta = Noco.ncMeta, + ) { // get a list of view columns sorted by order const view_columns = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, { condition: { @@ -1437,8 +1600,8 @@ export default class View implements ViewType { // get column meta for each view column for (const col of view_columns) { const col_meta = await ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COLUMNS, col.fk_column_id, ); @@ -1460,8 +1623,8 @@ export default class View implements ViewType { // if primary_value_column is not visible, make it visible if (!primary_value_column.show) { await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, { show: true }, primary_value_column.id, @@ -1488,8 +1651,8 @@ export default class View implements ViewType { // update order of all columns in view to match the order in array for (let i = 0; i < view_columns.length; i++) { await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, { order: i + 1 }, view_columns[i].id, @@ -1503,8 +1666,8 @@ export default class View implements ViewType { } const views = await ncMeta.metaList2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, { condition: { @@ -1519,6 +1682,7 @@ export default class View implements ViewType { } public static async clearSingleQueryCache( + context: NcContext, modelId: string, views?: { id?: string }[], ncMeta = Noco.ncMeta, @@ -1530,11 +1694,16 @@ export default class View implements ViewType { views || (await NocoCache.getList(CacheScope.VIEW, [modelId])).list; if (!views && !viewsList?.length) { - viewsList = await ncMeta.metaList2(null, null, MetaTable.VIEWS, { - condition: { - fk_model_id: modelId, + viewsList = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.VIEWS, + { + condition: { + fk_model_id: modelId, + }, }, - }); + ); } const deleteKeys = []; @@ -1557,6 +1726,7 @@ export default class View implements ViewType { } static async bulkColumnInsertToViews( + context: NcContext, { columns, viewColumns, @@ -1614,7 +1784,7 @@ export default class View implements ViewType { } } else { if (!columns) { - columns = await Column.list({ fk_model_id: view.fk_model_id }); + columns = await Column.list(context, { fk_model_id: view.fk_model_id }); } // todo: avoid duplicate code @@ -1648,7 +1818,11 @@ export default class View implements ViewType { let calendarRangeColumns; if (view.type == ViewTypes.CALENDAR) { - const calendarRange = await CalendarRange.read(view.id, ncMeta); + const calendarRange = await CalendarRange.read( + context, + view.id, + ncMeta, + ); if (calendarRange) { calendarRangeColumns = calendarRange.ranges .map((range) => [ @@ -1665,7 +1839,7 @@ export default class View implements ViewType { let show = 'show' in column ? column.show : true; if (view.type === ViewTypes.GALLERY) { - const galleryView = await GalleryView.get(view.id, ncMeta); + const galleryView = await GalleryView.get(context, view.id, ncMeta); if ( column.id === galleryView.fk_cover_image_col_id || column.pv || @@ -1677,7 +1851,7 @@ export default class View implements ViewType { show = false; } } else if (view.type === ViewTypes.KANBAN && !copyFromView) { - const kanbanView = await KanbanView.get(view.id, ncMeta); + const kanbanView = await KanbanView.get(context, view.id, ncMeta); if (column.id === kanbanView?.fk_grp_col_id) { // include grouping field if it exists show = true; @@ -1697,7 +1871,7 @@ export default class View implements ViewType { show = false; } } else if (view.type === ViewTypes.MAP && !copyFromView) { - const mapView = await MapView.get(view.id, ncMeta); + const mapView = await MapView.get(context, view.id, ncMeta); if (column.id === mapView?.fk_geo_data_col_id) { show = true; } @@ -1724,48 +1898,48 @@ export default class View implements ViewType { switch (view.type) { case ViewTypes.GRID: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GRID_VIEW_COLUMNS, insertObjs, ); break; case ViewTypes.GALLERY: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.GALLERY_VIEW_COLUMNS, insertObjs, ); break; case ViewTypes.MAP: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.MAP_VIEW_COLUMNS, insertObjs, ); break; case ViewTypes.KANBAN: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.KANBAN_VIEW_COLUMNS, insertObjs, ); break; case ViewTypes.FORM: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FORM_VIEW_COLUMNS, insertObjs, ); break; case ViewTypes.CALENDAR: await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.CALENDAR_VIEW_COLUMNS, insertObjs, ); @@ -1773,6 +1947,7 @@ export default class View implements ViewType { } static async insertMetaOnly( + context: NcContext, view: Partial & Partial< FormView | GridView | GalleryView | KanbanView | MapView | CalendarView @@ -1782,7 +1957,7 @@ export default class View implements ViewType { calendar_range?: Partial[]; }, model: { - getColumns: () => Promise; + getColumns: (context: NcContext, ncMeta?) => Promise; }, ncMeta = Noco.ncMeta, ) { @@ -1813,19 +1988,23 @@ export default class View implements ViewType { insertObj.meta = stringifyMetaProp(insertObj); const copyFromView = - view.copy_from_id && (await View.get(view.copy_from_id, ncMeta)); - await copyFromView?.getView(); + view.copy_from_id && (await View.get(context, view.copy_from_id, ncMeta)); + await copyFromView?.getView(context); + + const table = await Model.getByIdOrName( + context, + { id: view.fk_model_id }, + ncMeta, + ); // get base and base id if missing - if (!(view.base_id && view.source_id)) { - const model = await Model.getByIdOrName({ id: view.fk_model_id }, ncMeta); - insertObj.base_id = model.base_id; - insertObj.source_id = model.source_id; + if (!view.source_id) { + insertObj.source_id = table.source_id; } const insertedView = await ncMeta.metaInsert2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.VIEWS, insertObj, ); @@ -1836,6 +2015,7 @@ export default class View implements ViewType { switch (view.type) { case ViewTypes.GRID: await GridView.insert( + context, { ...((copyFromView?.view as GridView) || {}), ...(view as GridView), @@ -1846,6 +2026,7 @@ export default class View implements ViewType { break; case ViewTypes.MAP: await MapView.insert( + context, { ...(view as MapView), fk_view_id: view_id, @@ -1855,6 +2036,7 @@ export default class View implements ViewType { break; case ViewTypes.GALLERY: await GalleryView.insert( + context, { ...(copyFromView?.view || {}), ...view, @@ -1865,6 +2047,7 @@ export default class View implements ViewType { break; case ViewTypes.FORM: await FormView.insert( + context, { heading: view.title, ...(copyFromView?.view || {}), @@ -1879,6 +2062,7 @@ export default class View implements ViewType { (view as KanbanView).fk_grp_col_id = view.fk_grp_col_id; await KanbanView.insert( + context, { ...(copyFromView?.view || {}), ...view, @@ -1895,8 +2079,9 @@ export default class View implements ViewType { range.fk_view_id = view_id; }); - await CalendarRange.bulkInsert(calendarRange, ncMeta); + await CalendarRange.bulkInsert(context, calendarRange, ncMeta); await CalendarView.insert( + context, { ...(copyFromView?.view || {}), ...view, @@ -1911,12 +2096,13 @@ export default class View implements ViewType { // copy from view if (copyFromView) { - const sorts = await copyFromView.getSorts(ncMeta); + const sorts = await copyFromView.getSorts(context, ncMeta); const filters = await Filter.rootFilterList( + context, { viewId: copyFromView.id }, ncMeta, ); - const viewColumns = await copyFromView.getColumns(ncMeta); + const viewColumns = await copyFromView.getColumns(context, ncMeta); const sortInsertObjs = []; const filterInsertObjs = []; @@ -1957,7 +2143,7 @@ export default class View implements ViewType { }); if (filter.is_group) await Promise.all( - ((await filter.getChildren()) || []).map(async (child) => { + ((await filter.getChildren(context)) || []).map(async (child) => { await fn(child, generatedId); }), ); @@ -1966,11 +2152,16 @@ export default class View implements ViewType { await fn(filter); } - await ncMeta.bulkMetaInsert(null, null, MetaTable.SORT, sortInsertObjs); + await ncMeta.bulkMetaInsert( + context.workspace_id, + context.base_id, + MetaTable.SORT, + sortInsertObjs, + ); await ncMeta.bulkMetaInsert( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FILTER_EXP, filterInsertObjs, true, @@ -1978,18 +2169,21 @@ export default class View implements ViewType { // populate view columns await View.bulkColumnInsertToViews( + context, { viewColumns, copyFromView }, insertedView, ); } else { // populate view columns await View.bulkColumnInsertToViews( - { columns: (await model.getColumns()) as any[] }, + context, + { columns: (await model.getColumns(context, ncMeta)) as any[] }, insertedView, ); } await Model.getNonDefaultViewsCountAndReset( + context, { modelId: view.fk_model_id }, ncMeta, ); @@ -2097,72 +2291,79 @@ export default class View implements ViewType { return scope; } - async getModel(ncMeta = Noco.ncMeta): Promise { + async getModel(context: NcContext, ncMeta = Noco.ncMeta): Promise { return (this.model = await Model.getByIdOrName( + context, { id: this.fk_model_id }, ncMeta, )); } - async getModelWithInfo(ncMeta = Noco.ncMeta): Promise { + async getModelWithInfo( + context: NcContext, + ncMeta = Noco.ncMeta, + ): Promise { return (this.model = await Model.getWithInfo( + context, { id: this.fk_model_id }, ncMeta, )); } - async getView(): Promise { + async getView(context: NcContext, ncMeta = Noco.ncMeta): Promise { switch (this.type) { case ViewTypes.GRID: - this.view = await GridView.get(this.id); + this.view = await GridView.get(context, this.id, ncMeta); break; case ViewTypes.KANBAN: - this.view = await KanbanView.get(this.id); + this.view = await KanbanView.get(context, this.id, ncMeta); break; case ViewTypes.GALLERY: - this.view = await GalleryView.get(this.id); + this.view = await GalleryView.get(context, this.id, ncMeta); break; case ViewTypes.MAP: - this.view = await MapView.get(this.id); + this.view = await MapView.get(context, this.id, ncMeta); break; case ViewTypes.FORM: - this.view = await FormView.get(this.id); + this.view = await FormView.get(context, this.id, ncMeta); break; case ViewTypes.CALENDAR: - this.view = await CalendarView.get(this.id); + this.view = await CalendarView.get(context, this.id, ncMeta); break; } return this.view; } async getViewWithInfo( + context: NcContext, ncMeta = Noco.ncMeta, ): Promise { switch (this.type) { case ViewTypes.GRID: - this.view = await GridView.getWithInfo(this.id, ncMeta); + this.view = await GridView.getWithInfo(context, this.id, ncMeta); break; case ViewTypes.KANBAN: - this.view = await KanbanView.get(this.id, ncMeta); + this.view = await KanbanView.get(context, this.id, ncMeta); break; case ViewTypes.GALLERY: - this.view = await GalleryView.get(this.id, ncMeta); + this.view = await GalleryView.get(context, this.id, ncMeta); break; case ViewTypes.MAP: - this.view = await MapView.get(this.id, ncMeta); + this.view = await MapView.get(context, this.id, ncMeta); break; case ViewTypes.FORM: - this.view = await FormView.get(this.id, ncMeta); + this.view = await FormView.get(context, this.id, ncMeta); break; case ViewTypes.CALENDAR: - this.view = await CalendarView.get(this.id, ncMeta); + this.view = await CalendarView.get(context, this.id, ncMeta); break; } return this.view; } - public async getFilters(ncMeta = Noco.ncMeta) { + public async getFilters(context: NcContext, ncMeta = Noco.ncMeta) { return (this.filter = (await Filter.getFilterObject( + context, { viewId: this.id, }, @@ -2170,15 +2371,15 @@ export default class View implements ViewType { )) as any); } - public async getSorts(ncMeta = Noco.ncMeta) { - return (this.sorts = await Sort.list({ viewId: this.id }, ncMeta)); + public async getSorts(context: NcContext, ncMeta = Noco.ncMeta) { + return (this.sorts = await Sort.list(context, { viewId: this.id }, ncMeta)); } - async getColumns(ncMeta = Noco.ncMeta) { - return (this.columns = await View.getColumns(this.id, ncMeta)); + async getColumns(context: NcContext, ncMeta = Noco.ncMeta) { + return (this.columns = await View.getColumns(context, this.id, ncMeta)); } - async delete(ncMeta = Noco.ncMeta) { - await View.delete(this.id, ncMeta); + async delete(context: NcContext, ncMeta = Noco.ncMeta) { + await View.delete(context, this.id, ncMeta); } } diff --git a/packages/nocodb/src/modules/auth/auth.controller.ts b/packages/nocodb/src/modules/auth/auth.controller.ts index 7fa29d475a..3cc846b43f 100644 --- a/packages/nocodb/src/modules/auth/auth.controller.ts +++ b/packages/nocodb/src/modules/auth/auth.controller.ts @@ -9,7 +9,7 @@ import { Res, UseGuards, } from '@nestjs/common'; -import { Request, Response } from 'express'; +import { Response } from 'express'; import { AuthGuard } from '@nestjs/passport'; import { ConfigService } from '@nestjs/config'; import { extractRolesObj } from 'nocodb-sdk'; @@ -24,6 +24,7 @@ import { NcError } from '~/helpers/catchError'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { PublicApiLimiterGuard } from '~/guards/public-api-limiter.guard'; +import { NcRequest } from '~/interface/config'; @Controller() export class AuthController { @@ -40,7 +41,7 @@ export class AuthController { ]) @UseGuards(PublicApiLimiterGuard) @HttpCode(200) - async signup(@Req() req: Request, @Res() res: Response): Promise { + async signup(@Req() req: NcRequest, @Res() res: Response): Promise { if (this.config.get('auth', { infer: true }).disableEmailAuth) { NcError.forbidden('Email authentication is disabled'); } @@ -60,7 +61,10 @@ export class AuthController { ]) @UseGuards(PublicApiLimiterGuard) @HttpCode(200) - async refreshToken(@Req() req: Request, @Res() res: Response): Promise { + async refreshToken( + @Req() req: NcRequest, + @Res() res: Response, + ): Promise { res.json( await this.usersService.refreshToken({ body: req.body, @@ -77,7 +81,7 @@ export class AuthController { ]) @UseGuards(PublicApiLimiterGuard, AuthGuard('local')) @HttpCode(200) - async signin(@Req() req: Request, @Res() res: Response) { + async signin(@Req() req: NcRequest, @Res() res: Response) { if (this.config.get('auth', { infer: true }).disableEmailAuth) { NcError.forbidden('Email authentication is disabled'); } @@ -88,7 +92,7 @@ export class AuthController { @UseGuards(GlobalGuard) @Post('/api/v1/auth/user/signout') @HttpCode(200) - async signOut(@Req() req: Request, @Res() res: Response): Promise { + async signOut(@Req() req: NcRequest, @Res() res: Response): Promise { if (!(req as any).isAuthenticated?.()) { NcError.forbidden('Not allowed'); } @@ -103,7 +107,7 @@ export class AuthController { @Post(`/auth/google/genTokenByCode`) @HttpCode(200) @UseGuards(PublicApiLimiterGuard, AuthGuard('google')) - async googleSignin(@Req() req: Request, @Res() res: Response) { + async googleSignin(@Req() req: NcRequest, @Res() res: Response) { await this.setRefreshToken({ req, res }); res.json(await this.usersService.login(req.user, req)); } @@ -116,7 +120,7 @@ export class AuthController { @Get(['/auth/user/me', '/api/v1/db/auth/user/me', '/api/v1/auth/user/me']) @UseGuards(MetaApiLimiterGuard, GlobalGuard) - async me(@Req() req: Request) { + async me(@Req() req: NcRequest) { const user = { ...req.user, roles: extractRolesObj(req.user.roles), @@ -136,7 +140,7 @@ export class AuthController { scope: 'org', }) @HttpCode(200) - async passwordChange(@Req() req: Request): Promise { + async passwordChange(@Req() req: NcRequest): Promise { if (!(req as any).isAuthenticated?.()) { NcError.forbidden('Not allowed'); } @@ -157,7 +161,7 @@ export class AuthController { ]) @UseGuards(PublicApiLimiterGuard) @HttpCode(200) - async passwordForgot(@Req() req: Request): Promise { + async passwordForgot(@Req() req: NcRequest): Promise { await this.usersService.passwordForgot({ siteUrl: (req as any).ncSiteUrl, body: req.body, @@ -189,7 +193,7 @@ export class AuthController { @UseGuards(PublicApiLimiterGuard) @HttpCode(200) async passwordReset( - @Req() req: Request, + @Req() req: NcRequest, @Param('tokenId') tokenId: string, @Body() body: any, ): Promise { @@ -209,7 +213,7 @@ export class AuthController { @UseGuards(PublicApiLimiterGuard) @HttpCode(200) async emailVerification( - @Req() req: Request, + @Req() req: NcRequest, @Param('tokenId') tokenId: string, ): Promise { await this.usersService.emailVerification({ @@ -226,7 +230,7 @@ export class AuthController { ]) @UseGuards(PublicApiLimiterGuard) async renderPasswordReset( - @Req() req: Request, + @Req() req: NcRequest, @Res() res: Response, @Param('tokenId') tokenId: string, ): Promise { diff --git a/packages/nocodb/src/modules/jobs/jobs.controller.ts b/packages/nocodb/src/modules/jobs/jobs.controller.ts index eaf0d25127..f504d06002 100644 --- a/packages/nocodb/src/modules/jobs/jobs.controller.ts +++ b/packages/nocodb/src/modules/jobs/jobs.controller.ts @@ -20,6 +20,8 @@ import { CacheGetType, CacheScope } from '~/utils/globals'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { IJobsService } from '~/modules/jobs/jobs-service.interface'; import { JobsRedis } from '~/modules/jobs/redis/jobs-redis'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14); const POLLING_INTERVAL = 30000; @@ -39,7 +41,7 @@ export class JobsController { @HttpCode(200) async listen( @Res() res: Response & { resId?: string }, - @Req() req: Request, + @Req() req: NcRequest, @Body() body: { _mid: number; data: { id: string } }, ) { const { _mid = 0, data } = body; diff --git a/packages/nocodb/src/modules/jobs/jobs/at-import/at-import.controller.ts b/packages/nocodb/src/modules/jobs/jobs/at-import/at-import.controller.ts index 8ef3b98a13..5530bfd248 100644 --- a/packages/nocodb/src/modules/jobs/jobs/at-import/at-import.controller.ts +++ b/packages/nocodb/src/modules/jobs/jobs/at-import/at-import.controller.ts @@ -14,6 +14,8 @@ import { NcError } from '~/helpers/catchError'; import { JobTypes } from '~/interface/Jobs'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { IJobsService } from '~/modules/jobs/jobs-service.interface'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -28,7 +30,7 @@ export class AtImportController { ]) @Acl('airtableImport') @HttpCode(200) - async triggerSync(@Req() req: Request) { + async triggerSync(@TenantContext() context: NcContext, @Req() req: Request) { const jobs = await this.jobsService.jobList(); const fnd = jobs.find((j) => j.data.syncId === req.params.syncId); @@ -36,7 +38,7 @@ export class AtImportController { NcError.badRequest('Sync already in progress'); } - const syncSource = await SyncSource.get(req.params.syncId); + const syncSource = await SyncSource.get(context, req.params.syncId); const user = await syncSource.getUser(); @@ -50,6 +52,7 @@ export class AtImportController { } const job = await this.jobsService.add(JobTypes.AtImport, { + context, syncId: req.params.syncId, ...(syncSource?.details || {}), baseId: syncSource.base_id, diff --git a/packages/nocodb/src/modules/jobs/jobs/at-import/at-import.processor.ts b/packages/nocodb/src/modules/jobs/jobs/at-import/at-import.processor.ts index b3e9f5c1d3..c8bed3b305 100644 --- a/packages/nocodb/src/modules/jobs/jobs/at-import/at-import.processor.ts +++ b/packages/nocodb/src/modules/jobs/jobs/at-import/at-import.processor.ts @@ -114,8 +114,15 @@ export class AtImportProcessor { async job(job: Job) { this.debugLog(`job started for ${job.id}`); + const context = job.data.context; + const syncDB = job.data; + const req = { + user: syncDB.user.email, + clientIp: syncDB.clientIp, + } as any; + const sMapEM = new EntityMap('aTblId', 'ncId', 'ncName', 'ncParent'); await sMapEM.init(); const userRole = syncDB.user.roles @@ -617,7 +624,7 @@ export class AtImportProcessor { logDetailed(`NC API: base.tableCreate ${tables[idx].title}`); let _perfStart = recordPerfStart(); - const table = await this.tablesService.tableCreate({ + const table = await this.tablesService.tableCreate(context, { sourceId: syncDB.sourceId, baseId: ncCreatedProjectSchema.id, table: tables[idx], @@ -647,7 +654,7 @@ export class AtImportProcessor { logDetailed(`NC API: dbView.list ${table.id}`); _perfStart = recordPerfStart(); const view = { list: [] }; - view['list'] = await this.viewsService.viewList({ + view['list'] = await this.viewsService.viewList(context, { tableId: table.id, user: { roles: userRole, @@ -663,11 +670,11 @@ export class AtImportProcessor { `NC API: dbView.update ${view.list[0].id} ${aTbl_grid.name}`, ); _perfStart = recordPerfStart(); - await this.viewsService.viewUpdate({ + await this.viewsService.viewUpdate(context, { viewId: view.list[0].id, view: { title: aTbl_grid.name }, user: syncDB.user, - req: {}, + req, }); recordPerfStats(_perfStart, 'dbView.update'); @@ -732,7 +739,7 @@ export class AtImportProcessor { // check if already a column exists with this name? let _perfStart = recordPerfStart(); const srcTbl: any = - await this.tablesService.getTableWithAccessibleViews({ + await this.tablesService.getTableWithAccessibleViews(context, { tableId: srcTableId, user: { ...syncDB.user, base_roles: { owner: true } }, }); @@ -752,7 +759,7 @@ export class AtImportProcessor { `NC API: dbTableColumn.create LinkToAnotherRecord ${ncName.title}`, ); _perfStart = recordPerfStart(); - const ncTbl: any = await this.columnsService.columnAdd({ + const ncTbl: any = await this.columnsService.columnAdd(context, { tableId: srcTableId, column: { uidt: UITypes.Links, @@ -762,10 +769,7 @@ export class AtImportProcessor { childId: childTableId, type: 'mm', }, - req: { - user: syncDB.user.email, - clientIp: '', - }, + req, user: syncDB.user, }); recordPerfStats(_perfStart, 'dbTableColumn.create'); @@ -816,7 +820,7 @@ export class AtImportProcessor { let _perfStart = recordPerfStart(); const childTblSchema: any = - await this.tablesService.getTableWithAccessibleViews({ + await this.tablesService.getTableWithAccessibleViews(context, { tableId: ncLinkMappingTable[x].nc.childId, user: { ...syncDB.user, base_roles: { owner: true } }, }); @@ -824,7 +828,7 @@ export class AtImportProcessor { _perfStart = recordPerfStart(); const parentTblSchema: any = - await this.tablesService.getTableWithAccessibleViews({ + await this.tablesService.getTableWithAccessibleViews(context, { tableId: ncLinkMappingTable[x].nc.parentId, user: { ...syncDB.user, base_roles: { owner: true } }, }); @@ -893,15 +897,18 @@ export class AtImportProcessor { `NC API: dbTableColumn.update rename symmetric column ${ncName.title}`, ); _perfStart = recordPerfStart(); - const ncTbl: any = await this.columnsService.columnUpdate({ - columnId: childLinkColumn.id, - column: { - ...childLinkColumn, - title: ncName.title, - column_name: ncName.column_name, + const ncTbl: any = await this.columnsService.columnUpdate( + context, + { + columnId: childLinkColumn.id, + column: { + ...childLinkColumn, + title: ncName.title, + column_name: ncName.column_name, + }, + user: syncDB.user, }, - user: syncDB.user, - }); + ); recordPerfStats(_perfStart, 'dbTableColumn.update'); updateNcTblSchema(ncTbl); @@ -978,7 +985,7 @@ export class AtImportProcessor { logDetailed(`NC API: dbTableColumn.create LOOKUP ${ncName.title}`); const _perfStart = recordPerfStart(); - const ncTbl: any = await this.columnsService.columnAdd({ + const ncTbl: any = await this.columnsService.columnAdd(context, { tableId: srcTableId, column: { uidt: UITypes.Lookup, @@ -987,10 +994,7 @@ export class AtImportProcessor { fk_relation_column_id: ncRelationColumnId, fk_lookup_column_id: ncLookupColumnId, }, - req: { - user: syncDB.user.email, - clientIp: '', - }, + req, user: syncDB.user, }); recordPerfStats(_perfStart, 'dbTableColumn.create'); @@ -1064,7 +1068,7 @@ export class AtImportProcessor { logDetailed(`NC API: dbTableColumn.create LOOKUP ${ncName.title}`); const _perfStart = recordPerfStart(); - const ncTbl: any = await this.columnsService.columnAdd({ + const ncTbl: any = await this.columnsService.columnAdd(context, { tableId: srcTableId, column: { uidt: UITypes.Lookup, @@ -1076,7 +1080,7 @@ export class AtImportProcessor { req: { user: syncDB.user.email, clientIp: '', - }, + } as any, user: syncDB.user, }); recordPerfStats(_perfStart, 'dbTableColumn.create'); @@ -1230,7 +1234,7 @@ export class AtImportProcessor { logDetailed(`NC API: dbTableColumn.create ROLLUP ${ncName.title}`); const _perfStart = recordPerfStart(); try { - const ncTbl: any = await this.columnsService.columnAdd({ + const ncTbl: any = await this.columnsService.columnAdd(context, { tableId: srcTableId, column: { uidt: UITypes.Rollup, @@ -1240,10 +1244,7 @@ export class AtImportProcessor { fk_rollup_column_id: ncRollupColumnId, rollup_function: ncRollupFn, }, - req: { - user: syncDB.user.email, - clientIp: '', - }, + req, user: syncDB.user, }); recordPerfStats(_perfStart, 'dbTableColumn.create'); @@ -1301,7 +1302,7 @@ export class AtImportProcessor { logDetailed(`NC API: dbTableColumn.create LOOKUP ${ncName.title}`); const _perfStart = recordPerfStart(); - const ncTbl: any = await this.columnsService.columnAdd({ + const ncTbl: any = await this.columnsService.columnAdd(context, { tableId: srcTableId, column: { uidt: UITypes.Lookup, @@ -1310,10 +1311,7 @@ export class AtImportProcessor { fk_relation_column_id: ncRelationColumnId, fk_lookup_column_id: ncLookupColumnId, }, - req: { - user: syncDB.user.email, - clientIp: '', - }, + req, user: syncDB.user, }); recordPerfStats(_perfStart, 'dbTableColumn.create'); @@ -1350,7 +1348,9 @@ export class AtImportProcessor { if (ncColId) { logDetailed(`NC API: dbTableColumn.primaryColumnSet`); const _perfStart = recordPerfStart(); - await this.columnsService.columnSetAsPrimary({ columnId: ncColId }); + await this.columnsService.columnSetAsPrimary(context, { + columnId: ncColId, + }); recordPerfStats(_perfStart, 'dbTableColumn.primaryColumnSet'); // update schema @@ -1368,16 +1368,18 @@ export class AtImportProcessor { const _perfStart = recordPerfStart(); if (viewType === 'form') { viewDetails = ( - await this.formsService.formViewGet({ formViewId: viewId }) + await this.formsService.formViewGet(context, { formViewId: viewId }) ).columns; recordPerfStats(_perfStart, 'dbView.formRead'); } else if (viewType === 'gallery') { viewDetails = ( - await this.galleriesService.galleryViewGet({ galleryViewId: viewId }) + await this.galleriesService.galleryViewGet(context, { + galleryViewId: viewId, + }) ).columns; recordPerfStats(_perfStart, 'dbView.galleryRead'); } else { - viewDetails = await this.viewColumnsService.columnList({ + viewDetails = await this.viewColumnsService.columnList(context, { viewId: viewId, }); recordPerfStats(_perfStart, 'dbView.gridColumnsList'); @@ -1521,7 +1523,7 @@ export class AtImportProcessor { size: attachment.size, mimetype: attachment.type, })), - req: {}, + req, }); } catch (e) { logger.log(e); @@ -1569,7 +1571,7 @@ export class AtImportProcessor { ncCreatedProjectSchema = await this.basesService.baseCreate({ base: { title: projName }, user: { id: syncDB.user.id }, - req: {}, + req, }); recordPerfStats(_perfStart, 'base.create'); @@ -1579,9 +1581,12 @@ export class AtImportProcessor { // create empty base (XC-DB) logDetailed(`Getting base meta: ${projId}`); const _perfStart = recordPerfStart(); - ncCreatedProjectSchema = await this.basesService.getProjectWithInfo({ - baseId: projId, - }); + ncCreatedProjectSchema = await this.basesService.getProjectWithInfo( + context, + { + baseId: projId, + }, + ); recordPerfStats(_perfStart, 'base.read'); }; @@ -1614,13 +1619,13 @@ export class AtImportProcessor { logDetailed(`NC API dbView.galleryCreate :: ${viewName}`); const _perfStart = recordPerfStart(); - await this.galleriesService.galleryViewCreate({ + await this.galleriesService.galleryViewCreate(context, { tableId: tblId, gallery: { title: viewName, }, user: syncDB.user, - req: {}, + req, }); recordPerfStats(_perfStart, 'dbView.galleryCreate'); @@ -1683,11 +1688,11 @@ export class AtImportProcessor { logDetailed(`NC API dbView.formCreate :: ${viewName}`); const _perfStart = recordPerfStart(); // const f = await api.dbView.formCreate(tblId, formData); - const f = await this.formsService.formViewCreate({ + const f = await this.formsService.formViewCreate(context, { tableId: tblId, body: formData, user: syncDB.user, - req: {}, + req, }); recordPerfStats(_perfStart, 'dbView.formCreate'); @@ -1739,7 +1744,7 @@ export class AtImportProcessor { const _perfStart = recordPerfStart(); // const viewList: any = await api.dbView.list(tblId); const viewList = { list: [] }; - viewList['list'] = await this.viewsService.viewList({ + viewList['list'] = await this.viewsService.viewList(context, { tableId: tblId, user: { roles: userRole, @@ -1762,13 +1767,16 @@ export class AtImportProcessor { if (i > 0) { logDetailed(`NC API dbView.gridCreate :: ${viewName}`); const _perfStart = recordPerfStart(); - const viewCreated = await this.gridsService.gridViewCreate({ - tableId: tblId, - grid: { - title: viewName, + const viewCreated = await this.gridsService.gridViewCreate( + context, + { + tableId: tblId, + grid: { + title: viewName, + }, + req, }, - req: {}, - }); + ); recordPerfStats(_perfStart, 'dbView.gridCreate'); await updateNcTblSchemaById(tblId); @@ -1836,14 +1844,20 @@ export class AtImportProcessor { ); const _perfStart = recordPerfStart(); await this.baseUsersService - .userInvite({ - baseId: ncCreatedProjectSchema.id, - baseUser: { - email: value.email, - roles: userRoles[value.permissionLevel], + .userInvite( + { + workspace_id: context.workspace_id, + base_id: ncCreatedProjectSchema.id, }, - req: { user: syncDB.user, clientIp: '' }, - }) + { + baseId: ncCreatedProjectSchema.id, + baseUser: { + email: value.email, + roles: userRoles[value.permissionLevel], + }, + req, + }, + ) .catch((e) => { if (e.message) { // TODO enable after fixing user invite role issue @@ -1870,10 +1884,13 @@ export class AtImportProcessor { const updateNcTblSchemaById = async (tblId) => { const _perfStart = recordPerfStart(); - const ncTbl: any = await this.tablesService.getTableWithAccessibleViews({ - tableId: tblId, - user: { ...syncDB.user, base_roles: { owner: true } }, - }); + const ncTbl: any = await this.tablesService.getTableWithAccessibleViews( + context, + { + tableId: tblId, + user: { ...syncDB.user, base_roles: { owner: true } }, + }, + ); recordPerfStats(_perfStart, 'dbTable.read'); updateNcTblSchema(ncTbl); @@ -2141,11 +2158,11 @@ export class AtImportProcessor { for (let i = 0; i < ncFilters.length; i++) { const _perfStart = recordPerfStart(); try { - await this.filtersService.filterCreate({ + await this.filtersService.filterCreate(context, { viewId: viewId, filter: ncFilters[i], user: syncDB.user, - req: {}, + req, }); } catch (e) { logWarning(`Skipped creating filter for ${viewId} :: ${e.message}`); @@ -2211,7 +2228,7 @@ export class AtImportProcessor { } // insert group - const viewDetails = await this.viewColumnsService.columnList({ + const viewDetails = await this.viewColumnsService.columnList(context, { viewId: viewId, }); for (let i = 0; i < ncGroup.length; i++) { @@ -2219,7 +2236,7 @@ export class AtImportProcessor { (x) => x.fk_column_id === ncGroup[i].group_column_id, )?.id; try { - await this.gridColumnService.gridColumnUpdate({ + await this.gridColumnService.gridColumnUpdate(context, { gridViewColumnId: ncViewColumnId, grid: { group_by: true, @@ -2227,7 +2244,7 @@ export class AtImportProcessor { group_by_sort: ncGroup[i].direction === 'ascending' ? 'asc' : 'desc', }, - req: {}, + req, }); } catch (e) { // ignore @@ -2243,13 +2260,13 @@ export class AtImportProcessor { if (columnId) { const _perfStart = recordPerfStart(); - await this.sortsService.sortCreate({ + await this.sortsService.sortCreate(context, { viewId: viewId, sort: { fk_column_id: columnId, direction: s.sortSet[i].ascending ? 'asc' : 'desc', }, - req: {}, + req, }); recordPerfStats(_perfStart, 'dbTableSort.create'); } @@ -2278,18 +2295,18 @@ export class AtImportProcessor { const _perfStart = recordPerfStart(); if (viewType === 'form') { viewDetails = ( - await this.formsService.formViewGet({ formViewId: viewId }) + await this.formsService.formViewGet(context, { formViewId: viewId }) ).columns; recordPerfStats(_perfStart, 'dbView.formRead'); } else if (viewType === 'gallery') { viewDetails = ( - await this.galleriesService.galleryViewGet({ + await this.galleriesService.galleryViewGet(context, { galleryViewId: viewId, }) ).columns; recordPerfStats(_perfStart, 'dbView.galleryRead'); } else { - viewDetails = await this.viewColumnsService.columnList({ + viewDetails = await this.viewColumnsService.columnList(context, { viewId: viewId, }); recordPerfStats(_perfStart, 'dbView.gridColumnsList'); @@ -2307,14 +2324,14 @@ export class AtImportProcessor { // first two positions held by record id & record hash const _perfStart = recordPerfStart(); - await this.viewColumnsService.columnUpdate({ + await this.viewColumnsService.columnUpdate(context, { viewId: viewId, columnId: ncViewColumnId, column: { show: false, order: j + 1 + c.length, }, - req: {}, + req, }); recordPerfStats(_perfStart, 'dbViewColumn.update'); } @@ -2339,20 +2356,20 @@ export class AtImportProcessor { if (x?.required) formData[`required`] = x.required; if (x?.description) formData[`description`] = x.description; const _perfStart = recordPerfStart(); - await this.formColumnsService.columnUpdate({ + await this.formColumnsService.columnUpdate(context, { formViewColumnId: ncViewColumnId, formViewColumn: formData, - req: {}, + req, }); recordPerfStats(_perfStart, 'dbView.formColumnUpdate'); } } const _perfStart = recordPerfStart(); - await this.viewColumnsService.columnUpdate({ + await this.viewColumnsService.columnUpdate(context, { viewId: viewId, columnId: ncViewColumnId, column: configData, - req: {}, + req, }); recordPerfStats(_perfStart, 'dbViewColumn.update'); } @@ -2364,13 +2381,13 @@ export class AtImportProcessor { // clear all tables if debug mode if (debugMode) { - const tables = await this.tablesService.getAccessibleTables({ + const tables = await this.tablesService.getAccessibleTables(context, { baseId: syncDB.baseId, sourceId: syncDB.sourceId, roles: { ...userRole, owner: true }, }); for (const table of tables) { - await this.tablesService.tableDelete({ + await this.tablesService.tableDelete(context, { tableId: table.id, user: syncDB.user, forceDeleteRelations: true, @@ -2457,13 +2474,16 @@ export class AtImportProcessor { try { const _perfStart = recordPerfStart(); const ncTblList = { list: [] }; - ncTblList['list'] = await this.tablesService.getAccessibleTables({ - baseId: ncCreatedProjectSchema.id, - sourceId: syncDB.sourceId, - roles: { ...userRole, owner: true }, - }); + ncTblList['list'] = await this.tablesService.getAccessibleTables( + context, + { + baseId: ncCreatedProjectSchema.id, + sourceId: syncDB.sourceId, + roles: { ...userRole, owner: true }, + }, + ); - const source = await Source.get(syncDB.sourceId); + const source = await Source.get(context, syncDB.sourceId); recordPerfStats(_perfStart, 'base.tableList'); @@ -2479,13 +2499,13 @@ export class AtImportProcessor { const _perfStart = recordPerfStart(); const ncTbl: any = - await this.tablesService.getTableWithAccessibleViews({ + await this.tablesService.getTableWithAccessibleViews(context, { tableId: ncTblList.list[i].id, user: { ...syncDB.user, base_roles: { owner: true } }, }); recordPerfStats(_perfStart, 'dbTable.read'); - const importStats = await importData({ + const importStats = await importData(context, { baseName: syncDB.baseId, table: ncTbl, atBase, @@ -2522,7 +2542,7 @@ export class AtImportProcessor { } catch (e) { // delete tables that were created for (const table of ncSchema.tables) { - await this.tablesService.tableDelete({ + await this.tablesService.tableDelete(context, { tableId: table.id, user: syncDB.user, forceDeleteRelations: true, diff --git a/packages/nocodb/src/modules/jobs/jobs/at-import/helpers/readAndProcessData.ts b/packages/nocodb/src/modules/jobs/jobs/at-import/helpers/readAndProcessData.ts index 61287e5547..0bf5339a4b 100644 --- a/packages/nocodb/src/modules/jobs/jobs/at-import/helpers/readAndProcessData.ts +++ b/packages/nocodb/src/modules/jobs/jobs/at-import/helpers/readAndProcessData.ts @@ -9,6 +9,7 @@ import type { TablesService } from '~/services/tables.service'; import type { AirtableBase } from 'airtable/lib/airtable_base'; import type { TableType } from 'nocodb-sdk'; import type { Source } from '~/models'; +import type { NcContext } from '~/interface/config'; const logger = new Logger('at-import:readAndProcessData'); @@ -106,43 +107,46 @@ async function readAllData({ }); } -export async function importData({ - baseName, - table, - atBase, - nocoBaseDataProcessing_v2, - syncDB, - source, - logBasic = (_str) => {}, - logDetailed = (_str) => {}, - logWarning = (_str) => {}, - services, - // link related props start - insertedAssocRef = {}, - atNcAliasRef, - ncLinkMappingTable, -}: { - baseName: string; - table: { title?: string; id?: string }; - fields?; - atBase: AirtableBase; - source: Source; - logBasic: (string) => void; - logDetailed: (string) => void; - logWarning: (string) => void; - nocoBaseDataProcessing_v2; - // link related props start - insertedAssocRef: { [assocTableId: string]: boolean }; - atNcAliasRef: { - [ncTableId: string]: { - [ncTitle: string]: string; +export async function importData( + context: NcContext, + { + baseName, + table, + atBase, + nocoBaseDataProcessing_v2, + syncDB, + source, + logBasic = (_str) => {}, + logDetailed = (_str) => {}, + logWarning = (_str) => {}, + services, + // link related props start + insertedAssocRef = {}, + atNcAliasRef, + ncLinkMappingTable, + }: { + baseName: string; + table: { title?: string; id?: string }; + fields?; + atBase: AirtableBase; + source: Source; + logBasic: (string) => void; + logDetailed: (string) => void; + logWarning: (string) => void; + nocoBaseDataProcessing_v2; + // link related props start + insertedAssocRef: { [assocTableId: string]: boolean }; + atNcAliasRef: { + [ncTableId: string]: { + [ncTitle: string]: string; + }; }; - }; - ncLinkMappingTable: Record>[]; - // link related props end - syncDB; - services: AirtableImportContext; -}): Promise<{ + ncLinkMappingTable: Record>[]; + // link related props end + syncDB; + services: AirtableImportContext; + }, +): Promise<{ nestedLinkCount: number; importedCount: number; }> { @@ -173,7 +177,7 @@ export async function importData({ return new Promise(async (resolve) => { const queue = new PQueue({ concurrency: BULK_PARALLEL_PROCESS }); - const ltarPromise = importLTARData({ + const ltarPromise = importLTARData(context, { table, baseName, insertedAssocRef, @@ -218,7 +222,7 @@ export async function importData({ if (sizeof(tempData) >= BULK_DATA_BATCH_SIZE) { let insertArray = tempData.splice(0, tempData.length); - await services.bulkDataService.bulkDataInsert({ + await services.bulkDataService.bulkDataInsert(context, { baseName, tableName: table.id, body: insertArray, @@ -264,7 +268,7 @@ export async function importData({ // insert remaining data if (tempData.length > 0) { - await services.bulkDataService.bulkDataInsert({ + await services.bulkDataService.bulkDataInsert(context, { baseName, tableName: table.id, body: tempData, @@ -305,38 +309,41 @@ export async function importData({ } } -export async function importLTARData({ - table, - baseName, - insertedAssocRef = {}, - dataStream, - atNcAliasRef, - ncLinkMappingTable, - syncDB, - source, - services, - queue, - logBasic = (_str) => {}, - logWarning = (_str) => {}, -}: { - baseName: string; - table: { title?: string; id?: string }; - insertedAssocRef: { [assocTableId: string]: boolean }; - dataStream?: Readable; - atNcAliasRef: { - [ncTableId: string]: { - [ncTitle: string]: string; +export async function importLTARData( + context: NcContext, + { + table, + baseName, + insertedAssocRef = {}, + dataStream, + atNcAliasRef, + ncLinkMappingTable, + syncDB, + source, + services, + queue, + logBasic = (_str) => {}, + logWarning = (_str) => {}, + }: { + baseName: string; + table: { title?: string; id?: string }; + insertedAssocRef: { [assocTableId: string]: boolean }; + dataStream?: Readable; + atNcAliasRef: { + [ncTableId: string]: { + [ncTitle: string]: string; + }; }; - }; - ncLinkMappingTable: Record>[]; - syncDB; - source: Source; - services: AirtableImportContext; - queue: PQueue; - logBasic: (string) => void; - logDetailed: (string) => void; - logWarning: (string) => void; -}): Promise { + ncLinkMappingTable: Record>[]; + syncDB; + source: Source; + services: AirtableImportContext; + queue: PQueue; + logBasic: (string) => void; + logDetailed: (string) => void; + logWarning: (string) => void; + }, +): Promise { const assocTableMetas: Array<{ modelMeta: { id?: string; title?: string }; colMeta: { title?: string }; @@ -345,7 +352,7 @@ export async function importLTARData({ }> = []; const modelMeta: any = - await services.tableService.getTableWithAccessibleViews({ + await services.tableService.getTableWithAccessibleViews(context, { tableId: table.id, user: syncDB.user, }); @@ -369,7 +376,7 @@ export async function importLTARData({ insertedAssocRef[colMeta.colOptions.fk_mm_model_id] = true; const assocModelMeta: TableType = - (await services.tableService.getTableWithAccessibleViews({ + (await services.tableService.getTableWithAccessibleViews(context, { tableId: colMeta.colOptions.fk_mm_model_id, user: syncDB.user, })) as any; @@ -434,7 +441,7 @@ export async function importLTARData({ }`, ); - await services.bulkDataService.bulkDataInsert({ + await services.bulkDataService.bulkDataInsert(context, { baseName, tableName: assocMeta.modelMeta.id, body: insertArray, @@ -477,7 +484,7 @@ export async function importLTARData({ }`, ); - await services.bulkDataService.bulkDataInsert({ + await services.bulkDataService.bulkDataInsert(context, { baseName, tableName: assocMeta.modelMeta.id, body: assocTableData[assocMeta.modelMeta.id], diff --git a/packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.controller.ts b/packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.controller.ts index 213042b83d..9c0fe816c2 100644 --- a/packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.controller.ts +++ b/packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.controller.ts @@ -8,7 +8,6 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { ProjectStatus } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; @@ -18,6 +17,8 @@ import { generateUniqueName } from '~/helpers/exportImportHelpers'; import { JobTypes } from '~/interface/Jobs'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { IJobsService } from '~/modules/jobs/jobs-service.interface'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -36,7 +37,8 @@ export class DuplicateController { scope: 'org', }) public async duplicateSharedBase( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('workspaceId') _workspaceId: string, @Param('sharedBaseId') sharedBaseId: string, @Body() @@ -48,7 +50,7 @@ export class DuplicateController { base?: any; }, ) { - const base = await Base.getByUuid(sharedBaseId); + const base = await Base.getByUuid(context, sharedBaseId); if (!base) { throw new Error(`Base not found for id '${sharedBaseId}'`); @@ -78,6 +80,7 @@ export class DuplicateController { }); const job = await this.jobsService.add(JobTypes.DuplicateBase, { + context, baseId: base.id, sourceId: source.id, dupProjectId: dupProject.id, @@ -103,7 +106,8 @@ export class DuplicateController { @HttpCode(200) @Acl('duplicateBase') async duplicateBase( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseId') baseId: string, @Param('sourceId') sourceId?: string, @Body() @@ -117,14 +121,14 @@ export class DuplicateController { base?: any; }, ) { - const base = await Base.get(baseId); + const base = await Base.get(context, baseId); if (!base) { throw new Error(`Base not found for id '${baseId}'`); } const source = sourceId - ? await Source.get(sourceId) + ? await Source.get(context, sourceId) : (await base.getSources())[0]; if (!source) { @@ -149,6 +153,7 @@ export class DuplicateController { }); const job = await this.jobsService.add(JobTypes.DuplicateBase, { + context, baseId: base.id, sourceId: source.id, dupProjectId: dupProject.id, @@ -170,7 +175,8 @@ export class DuplicateController { @HttpCode(200) @Acl('duplicateModel') async duplicateModel( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseId') baseId: string, @Param('modelId') modelId?: string, @Body() @@ -182,21 +188,21 @@ export class DuplicateController { }; }, ) { - const base = await Base.get(baseId); + const base = await Base.get(context, baseId); if (!base) { throw new Error(`Base not found for id '${baseId}'`); } - const model = await Model.get(modelId); + const model = await Model.get(context, modelId); if (!model) { throw new Error(`Model not found!`); } - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const models = await source.getModels(); + const models = await source.getModels(context); const uniqueTitle = generateUniqueName( `${model.title} copy`, @@ -204,6 +210,7 @@ export class DuplicateController { ); const job = await this.jobsService.add(JobTypes.DuplicateModel, { + context, baseId: base.id, sourceId: source.id, modelId: model.id, @@ -226,7 +233,8 @@ export class DuplicateController { @HttpCode(200) @Acl('duplicateColumn') async duplicateColumn( - @Req() req: Request, + @TenantContext() context: NcContext, + @Req() req: NcRequest, @Param('baseId') baseId: string, @Param('columnId') columnId?: string, @Body() @@ -237,13 +245,13 @@ export class DuplicateController { extra?: any; }, ) { - const base = await Base.get(baseId); + const base = await Base.get(context, baseId); if (!base) { throw new Error(`Base not found for id '${baseId}'`); } - const column = await Column.get({ + const column = await Column.get(context, { source_id: base.id, colId: columnId, }); @@ -252,13 +260,14 @@ export class DuplicateController { throw new Error(`Column not found!`); } - const model = await Model.get(column.fk_model_id); + const model = await Model.get(context, column.fk_model_id); if (!model) { throw new Error(`Model not found!`); } const job = await this.jobsService.add(JobTypes.DuplicateColumn, { + context, baseId: base.id, sourceId: column.source_id, modelId: model.id, diff --git a/packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.processor.ts b/packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.processor.ts index c540a789c0..c29282361d 100644 --- a/packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.processor.ts +++ b/packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.processor.ts @@ -4,6 +4,7 @@ import { Job } from 'bull'; import papaparse from 'papaparse'; import debug from 'debug'; import { isLinksOrLTAR, isVirtualCol, RelationTypes } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import { Base, Column, Model, Source } from '~/models'; import { BasesService } from '~/services/bases.service'; import { @@ -35,15 +36,22 @@ export class DuplicateProcessor { const hrTime = initTime(); - const { baseId, sourceId, dupProjectId, req, options } = job.data; + const { context, sourceId, dupProjectId, req, options } = job.data; + + const baseId = context.base_id; const excludeData = options?.excludeData || false; const excludeHooks = options?.excludeHooks || false; const excludeViews = options?.excludeViews || false; - const base = await Base.get(baseId); - const dupProject = await Base.get(dupProjectId); - const source = await Source.get(sourceId); + const base = await Base.get(context, baseId); + const dupProject = await Base.get(context, dupProjectId); + const source = await Source.get(context, sourceId); + + const targetContext = { + ...context, + base_id: dupProject.id, + }; try { if (!base || !dupProject || !source) { @@ -52,12 +60,12 @@ export class DuplicateProcessor { const user = (req as any).user; - const models = (await source.getModels()).filter( + const models = (await source.getModels(context)).filter( // TODO revert this when issue with cache is fixed (m) => m.source_id === source.id && !m.mm && m.type === 'table', ); - const exportedModels = await this.exportService.serializeModels({ + const exportedModels = await this.exportService.serializeModels(context, { modelIds: models.map((m) => m.id), excludeViews, excludeHooks, @@ -78,7 +86,7 @@ export class DuplicateProcessor { const dupBase = dupProject.sources[0]; - const idMap = await this.importService.importModels({ + const idMap = await this.importService.importModels(targetContext, { user, baseId: dupProject.id, sourceId: dupBase.id, @@ -93,7 +101,7 @@ export class DuplicateProcessor { } if (!excludeData) { - await this.importModelsData({ + await this.importModelsData(targetContext, { idMap, sourceProject: base, sourceModels: models, @@ -103,7 +111,7 @@ export class DuplicateProcessor { }); } - await this.projectsService.baseUpdate({ + await this.projectsService.baseUpdate(targetContext, { baseId: dupProject.id, base: { status: null, @@ -113,7 +121,7 @@ export class DuplicateProcessor { }); } catch (e) { if (dupProject?.id) { - await this.projectsService.baseSoftDelete({ + await this.projectsService.baseSoftDelete(targetContext, { baseId: dupProject.id, user: req.user, req, @@ -131,24 +139,26 @@ export class DuplicateProcessor { const hrTime = initTime(); - const { baseId, sourceId, modelId, title, req, options } = job.data; + const { context, sourceId, modelId, title, req, options } = job.data; + + const baseId = context.base_id; const excludeData = options?.excludeData || false; const excludeHooks = options?.excludeHooks || false; const excludeViews = options?.excludeViews || false; - const base = await Base.get(baseId); - const source = await Source.get(sourceId); + const base = await Base.get(context, baseId); + const source = await Source.get(context, sourceId); const user = (req as any).user; - const models = (await source.getModels()).filter( + const models = (await source.getModels(context)).filter( (m) => !m.mm && m.type === 'table', ); const sourceModel = models.find((m) => m.id === modelId); - await sourceModel.getColumns(); + await sourceModel.getColumns(context); const relatedModelIds = sourceModel.columns .filter((col) => isLinksOrLTAR(col)) @@ -158,7 +168,7 @@ export class DuplicateProcessor { const relatedModels = models.filter((m) => relatedModelIds.includes(m.id)); const exportedModel = ( - await this.exportService.serializeModels({ + await this.exportService.serializeModels(context, { modelIds: [modelId], excludeViews, excludeHooks, @@ -179,7 +189,7 @@ export class DuplicateProcessor { exportedModel.model.title = title; exportedModel.model.table_name = title.toLowerCase().replace(/ /g, '_'); - const idMap = await this.importService.importModels({ + const idMap = await this.importService.importModels(context, { baseId, sourceId, data: [exportedModel], @@ -215,7 +225,7 @@ export class DuplicateProcessor { } } - await this.importModelsData({ + await this.importModelsData(context, { idMap, sourceProject: base, sourceModels: [sourceModel], @@ -231,7 +241,7 @@ export class DuplicateProcessor { this.debugLog(`job completed for ${job.id} (${JobTypes.DuplicateModel})`); - return await Model.get(findWithIdentifier(idMap, sourceModel.id)); + return await Model.get(context, findWithIdentifier(idMap, sourceModel.id)); } @Process(JobTypes.DuplicateColumn) @@ -240,28 +250,30 @@ export class DuplicateProcessor { const hrTime = initTime(); - const { baseId, sourceId, columnId, extra, req, options } = job.data; + const { context, sourceId, columnId, extra, req, options } = job.data; + + const baseId = context.base_id; const excludeData = options?.excludeData || false; - const base = await Base.get(baseId); + const base = await Base.get(context, baseId); - const sourceColumn = await Column.get({ + const sourceColumn = await Column.get(context, { source_id: sourceId, colId: columnId, }); const user = (req as any).user; - const source = await Source.get(sourceColumn.source_id); + const source = await Source.get(context, sourceColumn.source_id); - const models = (await source.getModels()).filter( + const models = (await source.getModels(context)).filter( (m) => !m.mm && m.type === 'table', ); const sourceModel = models.find((m) => m.id === sourceColumn.fk_model_id); - const columns = await sourceModel.getColumns(); + const columns = await sourceModel.getColumns(context); const title = generateUniqueName( `${sourceColumn.title} copy`, @@ -276,7 +288,7 @@ export class DuplicateProcessor { const relatedModels = models.filter((m) => relatedModelIds.includes(m.id)); const exportedModel = ( - await this.exportService.serializeModels({ + await this.exportService.serializeModels(context, { modelIds: [sourceModel.id, ...relatedModelIds], excludeData, excludeHooks: true, @@ -309,7 +321,7 @@ export class DuplicateProcessor { Object.assign(replacedColumn, extra); - const idMap = await this.importService.importModels({ + const idMap = await this.importService.importModels(context, { baseId, sourceId: source.id, data: [exportedModel], @@ -350,7 +362,7 @@ export class DuplicateProcessor { } } - await this.importModelsData({ + await this.importModelsData(context, { idMap, sourceProject: base, sourceModels: [], @@ -367,14 +379,14 @@ export class DuplicateProcessor { elapsedTime(hrTime, 'import model data', 'duplicateColumn'); } - const destColumn = await Column.get({ + const destColumn = await Column.get(context, { source_id: base.id, colId: findWithIdentifier(idMap, sourceColumn.id), }); // update cdf if (!isVirtualCol(destColumn)) { - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: findWithIdentifier(idMap, sourceColumn.id), column: { ...destColumn, @@ -386,22 +398,25 @@ export class DuplicateProcessor { this.debugLog(`job completed for ${job.id} (${JobTypes.DuplicateModel})`); - return await Column.get({ + return await Column.get(context, { source_id: base.id, colId: findWithIdentifier(idMap, sourceColumn.id), }); } - async importModelsData(param: { - idMap: Map; - sourceProject: Base; - sourceModels: Model[]; - destProject: Base; - destBase: Source; - hrTime: { hrTime: [number, number] }; - modelFieldIds?: Record; - externalModels?: Model[]; - }) { + async importModelsData( + context: NcContext, + param: { + idMap: Map; + sourceProject: Base; + sourceModels: Model[]; + destProject: Base; + destBase: Source; + hrTime: { hrTime: [number, number] }; + modelFieldIds?: Record; + externalModels?: Model[]; + }, + ) { const { idMap, sourceProject, @@ -429,7 +444,7 @@ export class DuplicateProcessor { }); this.exportService - .streamModelDataAsCsv({ + .streamModelDataAsCsv(context, { dataStream, linkStream, baseId: sourceProject.id, @@ -443,9 +458,12 @@ export class DuplicateProcessor { error = e; }); - const model = await Model.get(findWithIdentifier(idMap, sourceModel.id)); + const model = await Model.get( + context, + findWithIdentifier(idMap, sourceModel.id), + ); - await this.importService.importDataFromCsvStream({ + await this.importService.importDataFromCsvStream(context, { idMap, dataStream, destProject, @@ -453,7 +471,7 @@ export class DuplicateProcessor { destModel: model, }); - handledLinks = await this.importService.importLinkFromCsvStream({ + handledLinks = await this.importService.importLinkFromCsvStream(context, { idMap, linkStream, destProject, @@ -488,7 +506,7 @@ export class DuplicateProcessor { let error = null; this.exportService - .streamModelDataAsCsv({ + .streamModelDataAsCsv(context, { dataStream, linkStream, baseId: sourceProject.id, @@ -506,7 +524,7 @@ export class DuplicateProcessor { const headers: string[] = []; let chunk = []; - const model = await Model.get(sourceModel.id); + const model = await Model.get(context, sourceModel.id); await new Promise((resolve) => { papaparse.parse(dataStream, { @@ -517,7 +535,7 @@ export class DuplicateProcessor { for (const header of results.data as any) { const id = idMap.get(header); if (id) { - const col = await Column.get({ + const col = await Column.get(context, { source_id: destBase.id, colId: id, }); @@ -527,7 +545,7 @@ export class DuplicateProcessor { (col.colOptions?.type === RelationTypes.ONE_TO_ONE && col.meta?.bt) ) { - const childCol = await Column.get({ + const childCol = await Column.get(context, { source_id: destBase.id, colId: col.colOptions.fk_child_column_id, }); @@ -567,7 +585,7 @@ export class DuplicateProcessor { // remove empty rows (only pk is present) chunk = chunk.filter((r) => Object.keys(r).length > 1); if (chunk.length > 0) { - await this.bulkDataService.bulkDataUpdate({ + await this.bulkDataService.bulkDataUpdate(context, { baseName: destProject.id, tableName: model.id, body: chunk, @@ -590,7 +608,7 @@ export class DuplicateProcessor { // remove empty rows (only pk is present) chunk = chunk.filter((r) => Object.keys(r).length > 1); if (chunk.length > 0) { - await this.bulkDataService.bulkDataUpdate({ + await this.bulkDataService.bulkDataUpdate(context, { baseName: destProject.id, tableName: model.id, body: chunk, @@ -610,13 +628,16 @@ export class DuplicateProcessor { if (error) throw error; - handledLinks = await this.importService.importLinkFromCsvStream({ - idMap, - linkStream, - destProject, - destBase, - handledLinks, - }); + handledLinks = await this.importService.importLinkFromCsvStream( + context, + { + idMap, + linkStream, + destProject, + destBase, + handledLinks, + }, + ); elapsedTime( hrTime, 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 74450fcf93..dbe1b49f40 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 @@ -5,9 +5,9 @@ import debug from 'debug'; import { Injectable } from '@nestjs/common'; import { elapsedTime, initTime } from '../../helpers'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; +import type { NcContext } from '~/interface/config'; import type { LinkToAnotherRecordColumn } from '~/models'; -import { View } from '~/models'; -import { Base, Filter, Hook, Model, Source } from '~/models'; +import { Base, Filter, Hook, Model, Source, View } from '~/models'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; import { getViewAndModelByAliasOrId } from '~/helpers/dataHelpers'; import { @@ -26,12 +26,15 @@ export class ExportService { constructor(private datasService: DatasService) {} - async serializeModels(param: { - modelIds: string[]; - excludeViews?: boolean; - excludeHooks?: boolean; - excludeData?: boolean; - }) { + async serializeModels( + context: NcContext, + param: { + modelIds: string[]; + excludeViews?: boolean; + excludeHooks?: boolean; + excludeData?: boolean; + }, + ) { const { modelIds } = param; const excludeData = param?.excludeData || false; @@ -48,27 +51,30 @@ export class ExportService { const modelsMap = new Map(); for (const modelId of modelIds) { - const model = await Model.get(modelId); + const model = await Model.get(context, modelId); let pgSerialLastVal; 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)); + const base = fndProject || (await Base.get(context, model.base_id)); const fndBase = sources.find((b) => b.id === model.source_id); - const source = fndBase || (await Source.get(model.source_id)); + const source = fndBase || (await Source.get(context, model.source_id)); if (!fndProject) bases.push(base); if (!fndBase) sources.push(source); if (!modelsMap.has(source.id)) { - modelsMap.set(source.id, await generateBaseIdMap(source, idMap)); + modelsMap.set( + source.id, + await generateBaseIdMap(context, source, idMap), + ); } - await model.getColumns(); - await model.getViews(); + await model.getColumns(context); + await model.getViews(context); // if views are excluded, filter all views except default if (excludeViews) { @@ -76,14 +82,14 @@ export class ExportService { } for (const column of model.columns) { - await column.getColOptions(); + await column.getColOptions(context); // if data is not excluded, get currval for ai column (pg) if (!excludeData) { if (source.type === 'pg') { if (column.ai) { try { - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: null, dbDriver: await NcConnectionMgrv2.get(source), @@ -129,7 +135,7 @@ export class ExportService { break; case 'fk_target_view_id': if (v) { - const view = await View.get(v as string); + const view = await View.get(context, v as string); idMap.set( view.id, `${source.base_id}::${source.id}::${getEntityIdentifier( @@ -189,7 +195,7 @@ export class ExportService { // Link column filters if (isLinksOrLTAR(column)) { const colOptions = column.colOptions as LinkToAnotherRecordColumn; - colOptions.filter = (await Filter.getFilterObject({ + colOptions.filter = (await Filter.getFilterObject(context, { linkColId: column.id, })) as any; if (colOptions.filter?.children?.length) { @@ -223,9 +229,9 @@ export class ExportService { for (const view of model.views) { idMap.set(view.id, `${idMap.get(model.id)}::${view.id}`); - await view.getColumns(); - await view.getFilters(); - await view.getSorts(); + await view.getColumns(context); + await view.getFilters(context); + await view.getSorts(context); if (view.filter) { const export_filters = []; for (const fl of view.filter.children) { @@ -317,12 +323,12 @@ export class ExportService { const serializedHooks = []; if (!excludeHooks) { - const hooks = await Hook.list({ fk_model_id: model.id }); + const hooks = await Hook.list(context, { fk_model_id: model.id }); for (const hook of hooks) { idMap.set(hook.id, `${idMap.get(hook.fk_model_id)}::${hook.id}`); - const hookFilters = await hook.getFilters(); + const hookFilters = await hook.getFilters(context); const export_filters = []; if (hookFilters) { @@ -428,26 +434,29 @@ export class ExportService { return serializedModels; } - async streamModelDataAsCsv(param: { - dataStream: Readable; - linkStream: Readable; - baseId: string; - modelId: string; - viewId?: string; - handledMmList?: string[]; - _fieldIds?: string[]; - }) { + async streamModelDataAsCsv( + context: NcContext, + param: { + dataStream: Readable; + linkStream: Readable; + baseId: string; + modelId: string; + viewId?: string; + handledMmList?: string[]; + _fieldIds?: string[]; + }, + ) { const { dataStream, linkStream, handledMmList } = param; - const { model, view } = await getViewAndModelByAliasOrId({ + const { model, view } = await getViewAndModelByAliasOrId(context, { baseName: param.baseId, tableName: param.modelId, viewName: param.viewId, }); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - await model.getColumns(); + await model.getColumns(context); const btMap = new Map(); @@ -457,7 +466,7 @@ export class ExportService { (col.colOptions?.type === RelationTypes.BELONGS_TO || (col.colOptions?.type === RelationTypes.ONE_TO_ONE && col.meta?.bt)), )) { - await column.getColOptions(); + await column.getColOptions(context); const fkCol = model.columns.find( (c) => c.id === column.colOptions?.fk_child_column_id, ); @@ -552,7 +561,7 @@ export class ExportService { return { data }; }; - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -563,6 +572,7 @@ export class ExportService { try { await this.recursiveRead( + context, formatData, baseModel, dataStream, @@ -586,9 +596,9 @@ export class ExportService { for (const mm of mmColumns) { if (handledMmList.includes(mm.colOptions?.fk_mm_model_id)) continue; - const mmModel = await Model.get(mm.colOptions?.fk_mm_model_id); + const mmModel = await Model.get(context, mm.colOptions?.fk_mm_model_id); - await mmModel.getColumns(); + await mmModel.getColumns(context); const childColumn = mmModel.columns.find( (col) => col.id === mm.colOptions?.fk_mm_child_column_id, @@ -624,15 +634,16 @@ export class ExportService { const mmBase = mmModel.source_id === source.id ? source - : await Source.get(mmModel.source_id); + : await Source.get(context, mmModel.source_id); - const mmBaseModel = await Model.getBaseModelSQL({ + const mmBaseModel = await Model.getBaseModelSQL(context, { id: mmModel.id, dbDriver: await NcConnectionMgrv2.get(mmBase), }); try { await this.recursiveLinkRead( + context, mmFormatData, mmBaseModel, linkStream, @@ -661,6 +672,7 @@ export class ExportService { } async recursiveRead( + context: NcContext, formatter: (data: any) => { data: any }, baseModel: BaseModelSqlv2, stream: Readable, @@ -673,7 +685,7 @@ export class ExportService { ): Promise { return new Promise((resolve, reject) => { this.datasService - .getDataList({ + .getDataList(context, { model, view, query: { limit, offset, fields }, @@ -693,6 +705,7 @@ export class ExportService { resolve(); } else { this.recursiveRead( + context, formatter, baseModel, stream, @@ -714,6 +727,7 @@ export class ExportService { } async recursiveLinkRead( + context: NcContext, formatter: (data: any) => { data: any }, baseModel: BaseModelSqlv2, linkStream: Readable, @@ -726,7 +740,7 @@ export class ExportService { ): Promise { return new Promise((resolve, reject) => { this.datasService - .getDataList({ + .getDataList(context, { model, view, query: { limit, offset, fields }, @@ -745,6 +759,7 @@ export class ExportService { resolve(); } else { this.recursiveLinkRead( + context, formatter, baseModel, linkStream, @@ -765,21 +780,24 @@ export class ExportService { }); } - async exportBase(param: { path: string; sourceId: string }) { + async exportBase( + context: NcContext, + param: { path: string; sourceId: string }, + ) { const hrTime = initTime(); - const source = await Source.get(param.sourceId); + const source = await Source.get(context, param.sourceId); if (!source) NcError.sourceNotFound(param.sourceId); - const base = await Base.get(source.base_id); + const base = await Base.get(context, source.base_id); - const models = (await source.getModels()).filter( + const models = (await source.getModels(context)).filter( // TODO revert this when issue with cache is fixed (m) => m.source_id === source.id && !m.mm && m.type === 'table', ); - const exportedModels = await this.serializeModels({ + const exportedModels = await this.serializeModels(context, { modelIds: models.map((m) => m.id), }); @@ -857,7 +875,7 @@ export class ExportService { let error = null; - this.streamModelDataAsCsv({ + this.streamModelDataAsCsv(context, { dataStream, linkStream, baseId: 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 4fd4566717..5261a83c43 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 @@ -18,7 +18,7 @@ import type { User, View, } from '~/models'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { Base, Column, Model, Source } from '~/models'; import { findWithIdentifier, @@ -72,18 +72,21 @@ export class ImportService { private viewsService: ViewsService, ) {} - async importModels(param: { - user: User; - baseId: string; - sourceId: string; - data: - | { models: { model: any; views: any[]; hooks?: any[] }[] } - | { model: any; views: any[]; hooks?: any[] }[]; - req: NcRequest; - externalModels?: Model[]; - existingModel?: Model; - importColumnIds?: string[]; - }) { + async importModels( + context: NcContext, + param: { + user: User; + baseId: string; + sourceId: string; + data: + | { models: { model: any; views: any[]; hooks?: any[] }[] } + | { model: any; views: any[]; hooks?: any[] }[]; + req: NcRequest; + externalModels?: Model[]; + existingModel?: Model; + importColumnIds?: string[]; + }, + ) { const hrTime = initTime(); // structured id to db id @@ -94,11 +97,11 @@ export class ImportService { return idMap.get(k) || externalIdMap.get(k); }; - const base = await Base.get(param.baseId); + const base = await Base.get(context, param.baseId); if (!base) return NcError.baseNotFound(param.baseId); - const source = await Source.get(param.sourceId); + const source = await Source.get(context, param.sourceId); if (!source) return NcError.sourceNotFound(param.sourceId); @@ -119,8 +122,8 @@ export class ImportService { model.id, ); - await model.getColumns(); - await model.getViews(); + await model.getColumns(context); + await model.getViews(context); const primaryKey = model.primaryKey; if (primaryKey) { @@ -164,7 +167,7 @@ export class ImportService { // create table with static columns const table = param.existingModel || - (await this.tablesService.tableCreate({ + (await this.tablesService.tableCreate(context, { baseId: base.id, sourceId: source.id, user: param.user, @@ -179,14 +182,17 @@ export class ImportService { if (param.existingModel) { if (reducedColumnSet.length) { for (const col of reducedColumnSet) { - const freshModelData = await this.columnsService.columnAdd({ - tableId: getIdOrExternalId(getParentIdentifier(col.id)), - column: withoutId({ - ...col, - }) as any, - req: param.req, - user: param.user, - }); + const freshModelData = await this.columnsService.columnAdd( + context, + { + tableId: getIdOrExternalId(getParentIdentifier(col.id)), + column: withoutId({ + ...col, + }) as any, + req: param.req, + user: param.user, + }, + ); for (const nColumn of freshModelData.columns) { if (nColumn.title === col.title) { @@ -211,7 +217,7 @@ export class ImportService { if (source.type === 'pg') { if (modelData.pgSerialLastVal) { if (col.ai) { - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: table.id, viewId: null, dbDriver: await NcConnectionMgrv2.get(source), @@ -263,29 +269,32 @@ export class ImportService { // delete col.column_name as it is not required and will cause ajv error (null for LTAR) delete col.column_name; - const freshModelData = await this.columnsService.columnAdd({ - tableId: table.id, - column: withoutId({ - ...col, - ...{ - parentId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_child_column_id), - ), - childId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_parent_column_id), - ), - type: colOptions.type, - virtual: colOptions.virtual, - ur: colOptions.ur, - dr: colOptions.dr, - childViewId: - colOptions.fk_target_view_id && - getIdOrExternalId(colOptions.fk_target_view_id), - }, - }), - req: param.req, - user: param.user, - }); + const freshModelData = await this.columnsService.columnAdd( + context, + { + tableId: table.id, + column: withoutId({ + ...col, + ...{ + parentId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_child_column_id), + ), + childId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_parent_column_id), + ), + type: colOptions.type, + virtual: colOptions.virtual, + ur: colOptions.ur, + dr: colOptions.dr, + childViewId: + colOptions.fk_target_view_id && + getIdOrExternalId(colOptions.fk_target_view_id), + }, + }), + req: param.req, + user: param.user, + }, + ); for (const nColumn of freshModelData.columns) { if (nColumn.title === col.title) { @@ -298,11 +307,12 @@ export class ImportService { } } - const childModel = + const childModel: Model = getParentIdentifier(colOptions.fk_parent_column_id) === modelData.id ? freshModelData : await Model.get( + context, getIdOrExternalId( getParentIdentifier(colOptions.fk_parent_column_id), ), @@ -312,7 +322,7 @@ export class ImportService { getParentIdentifier(colOptions.fk_parent_column_id) !== modelData.id ) - await childModel.getColumns(); + await childModel.getColumns(context); const childColumn = param.data .find( @@ -345,7 +355,7 @@ export class ImportService { ); } - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: nColumn.id, column: { ...nColumn, @@ -366,29 +376,32 @@ export class ImportService { // delete col.column_name as it is not required and will cause ajv error (null for LTAR) delete col.column_name; - const freshModelData = await this.columnsService.columnAdd({ - tableId: table.id, - column: withoutId({ - ...col, - ...{ - parentId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_parent_column_id), - ), - childId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_child_column_id), - ), - type: colOptions.type, - virtual: colOptions.virtual, - ur: colOptions.ur, - dr: colOptions.dr, - childViewId: - colOptions.fk_target_view_id && - getIdOrExternalId(colOptions.fk_target_view_id), - }, - }), - req: param.req, - user: param.user, - }); + const freshModelData = await this.columnsService.columnAdd( + context, + { + tableId: table.id, + column: withoutId({ + ...col, + ...{ + parentId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_parent_column_id), + ), + childId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_child_column_id), + ), + type: colOptions.type, + virtual: colOptions.virtual, + ur: colOptions.ur, + dr: colOptions.dr, + childViewId: + colOptions.fk_target_view_id && + getIdOrExternalId(colOptions.fk_target_view_id), + }, + }), + req: param.req, + user: param.user, + }, + ); for (const nColumn of freshModelData.columns) { if (nColumn.title === col.title) { @@ -405,15 +418,16 @@ export class ImportService { } } - const childModel = + const childModel: Model = colOptions.fk_related_model_id === modelData.id ? freshModelData : await Model.get( + context, getIdOrExternalId(colOptions.fk_related_model_id), ); if (colOptions.fk_related_model_id !== modelData.id) - await childModel.getColumns(); + await childModel.getColumns(context); const childColumn = param.data .find((a) => a.model.id === colOptions.fk_related_model_id) @@ -450,7 +464,7 @@ export class ImportService { ); } - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: nColumn.id, column: { ...nColumn, @@ -487,7 +501,7 @@ export class ImportService { ); } - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: nColumn.id, column: { ...nColumn, @@ -507,29 +521,32 @@ export class ImportService { // delete col.column_name as it is not required and will cause ajv error (null for LTAR) delete col.column_name; - const freshModelData = await this.columnsService.columnAdd({ - tableId: table.id, - column: withoutId({ - ...col, - ...{ - parentId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_child_column_id), - ), - childId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_parent_column_id), - ), - type: colOptions.type, - virtual: colOptions.virtual, - ur: colOptions.ur, - dr: colOptions.dr, - childViewId: - colOptions.fk_target_view_id && - getIdOrExternalId(colOptions.fk_target_view_id), - }, - }) as any, - req: param.req, - user: param.user, - }); + const freshModelData = await this.columnsService.columnAdd( + context, + { + tableId: table.id, + column: withoutId({ + ...col, + ...{ + parentId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_child_column_id), + ), + childId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_parent_column_id), + ), + type: colOptions.type, + virtual: colOptions.virtual, + ur: colOptions.ur, + dr: colOptions.dr, + childViewId: + colOptions.fk_target_view_id && + getIdOrExternalId(colOptions.fk_target_view_id), + }, + }) as any, + req: param.req, + user: param.user, + }, + ); for (const nColumn of freshModelData.columns) { if (nColumn.title === col.title) { @@ -542,11 +559,12 @@ export class ImportService { } } - const childModel = + const childModel: Model = getParentIdentifier(colOptions.fk_parent_column_id) === modelData.id ? freshModelData : await Model.get( + context, getIdOrExternalId( getParentIdentifier(colOptions.fk_parent_column_id), ), @@ -556,7 +574,7 @@ export class ImportService { getParentIdentifier(colOptions.fk_parent_column_id) !== modelData.id ) - await childModel.getColumns(); + await childModel.getColumns(context); const childColumn = ( param.data.find( @@ -607,7 +625,7 @@ export class ImportService { ); } - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: nColumn.id, column: { ...nColumn, @@ -633,29 +651,32 @@ export class ImportService { // delete col.column_name as it is not required and will cause ajv error (null for LTAR) delete col.column_name; - const freshModelData = await this.columnsService.columnAdd({ - tableId: table.id, - column: withoutId({ - ...col, - ...{ - parentId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_parent_column_id), - ), - childId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_child_column_id), - ), - type: colOptions.type, - virtual: colOptions.virtual, - ur: colOptions.ur, - dr: colOptions.dr, - childViewId: - colOptions.fk_target_view_id && - getIdOrExternalId(colOptions.fk_target_view_id), - }, - }) as any, - req: param.req, - user: param.user, - }); + const freshModelData = await this.columnsService.columnAdd( + context, + { + tableId: table.id, + column: withoutId({ + ...col, + ...{ + parentId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_parent_column_id), + ), + childId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_child_column_id), + ), + type: colOptions.type, + virtual: colOptions.virtual, + ur: colOptions.ur, + dr: colOptions.dr, + childViewId: + colOptions.fk_target_view_id && + getIdOrExternalId(colOptions.fk_target_view_id), + }, + }) as any, + req: param.req, + user: param.user, + }, + ); linkMap.set( `${colOptions.fk_parent_column_id}::${colOptions.fk_child_column_id}`, @@ -677,15 +698,16 @@ export class ImportService { } } - const childModel = + const childModel: Model = colOptions.fk_related_model_id === modelData.id ? freshModelData : await Model.get( + context, getIdOrExternalId(colOptions.fk_related_model_id), ); if (colOptions.fk_related_model_id !== modelData.id) - await childModel.getColumns(); + await childModel.getColumns(context); const childColumn = ( param.data.find( @@ -741,7 +763,7 @@ export class ImportService { ); } - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: nColumn.id, column: { ...nColumn, @@ -779,7 +801,7 @@ export class ImportService { ); } - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: nColumn.id, column: { ...nColumn, @@ -806,29 +828,32 @@ export class ImportService { // delete col.column_name as it is not required and will cause ajv error (null for LTAR) delete col.column_name; - const freshModelData = await this.columnsService.columnAdd({ - tableId: table.id, - column: withoutId({ - ...col, - ...{ - parentId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_parent_column_id), - ), - childId: getIdOrExternalId( - getParentIdentifier(colOptions.fk_child_column_id), - ), - type: colOptions.type, - virtual: colOptions.virtual, - ur: colOptions.ur, - dr: colOptions.dr, - childViewId: - colOptions.fk_target_view_id && - getIdOrExternalId(colOptions.fk_target_view_id), - }, - }) as any, - req: param.req, - user: param.user, - }); + const freshModelData = await this.columnsService.columnAdd( + context, + { + tableId: table.id, + column: withoutId({ + ...col, + ...{ + parentId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_parent_column_id), + ), + childId: getIdOrExternalId( + getParentIdentifier(colOptions.fk_child_column_id), + ), + type: colOptions.type, + virtual: colOptions.virtual, + ur: colOptions.ur, + dr: colOptions.dr, + childViewId: + colOptions.fk_target_view_id && + getIdOrExternalId(colOptions.fk_target_view_id), + }, + }) as any, + req: param.req, + user: param.user, + }, + ); linkMap.set( `${colOptions.fk_parent_column_id}::${colOptions.fk_child_column_id}`, @@ -850,15 +875,16 @@ export class ImportService { } } - const childModel = + const childModel: Model = colOptions.fk_related_model_id === modelData.id ? freshModelData : await Model.get( + context, getIdOrExternalId(colOptions.fk_related_model_id), ); if (colOptions.fk_related_model_id !== modelData.id) - await childModel.getColumns(); + await childModel.getColumns(context); const childColumn = ( param.data.find( @@ -914,7 +940,7 @@ export class ImportService { ); } - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: nColumn.id, column: { ...nColumn, @@ -953,7 +979,7 @@ export class ImportService { ); } - await this.columnsService.columnUpdate({ + await this.columnsService.columnUpdate(context, { columnId: nColumn.id, column: { ...nColumn, @@ -977,7 +1003,7 @@ export class ImportService { const filters = colOptions.filter?.children; for (const fl of filters) { - const fg = await this.filtersService.linkFilterCreate({ + const fg = await this.filtersService.linkFilterCreate(context, { columnId: getIdOrExternalId(col.id), filter: withoutId({ ...fl, @@ -1071,7 +1097,7 @@ export class ImportService { const { colOptions, ...flatCol } = col; if (col.uidt === UITypes.Lookup) { if (!getIdOrExternalId(colOptions.fk_relation_column_id)) continue; - const freshModelData = await this.columnsService.columnAdd({ + const freshModelData = await this.columnsService.columnAdd(context, { tableId: getIdOrExternalId(getParentIdentifier(col.id)), column: withoutId({ ...flatCol, @@ -1096,7 +1122,7 @@ export class ImportService { } } else if (col.uidt === UITypes.Rollup) { if (!getIdOrExternalId(colOptions.fk_relation_column_id)) continue; - const freshModelData = await this.columnsService.columnAdd({ + const freshModelData = await this.columnsService.columnAdd(context, { tableId: getIdOrExternalId(getParentIdentifier(col.id)), column: withoutId({ ...flatCol, @@ -1121,7 +1147,7 @@ export class ImportService { } } } else if (col.uidt === UITypes.Formula) { - const freshModelData = await this.columnsService.columnAdd({ + const freshModelData = await this.columnsService.columnAdd(context, { tableId: getIdOrExternalId(getParentIdentifier(col.id)), column: withoutId({ ...flatCol, @@ -1146,7 +1172,7 @@ export class ImportService { col.uidt === UITypes.LastModifiedBy ) { if (col.system) continue; - const freshModelData = await this.columnsService.columnAdd({ + const freshModelData = await this.columnsService.columnAdd(context, { tableId: getIdOrExternalId(getParentIdentifier(col.id)), column: withoutId({ ...flatCol, @@ -1166,7 +1192,7 @@ export class ImportService { } } } else if (col.uidt === UITypes.QrCode) { - const freshModelData = await this.columnsService.columnAdd({ + const freshModelData = await this.columnsService.columnAdd(context, { tableId: getIdOrExternalId(getParentIdentifier(col.id)), column: withoutId({ ...flatCol, @@ -1188,7 +1214,7 @@ export class ImportService { } } else if (col.uidt === UITypes.Barcode) { flatCol.validate = null; - const freshModelData = await this.columnsService.columnAdd({ + const freshModelData = await this.columnsService.columnAdd(context, { tableId: getIdOrExternalId(getParentIdentifier(col.id)), column: withoutId({ ...flatCol, @@ -1223,7 +1249,7 @@ export class ImportService { const table = tableReferences.get(modelData.id); // get default view - await table.getViews(); + await table.getViews(context); for (const view of viewsData) { const viewData = withoutId({ @@ -1231,6 +1257,7 @@ export class ImportService { }); const vw = await this.createView( + context, idMap, table, viewData, @@ -1247,7 +1274,7 @@ export class ImportService { const filters = view.filter.children; for (const fl of filters) { - const fg = await this.filtersService.filterCreate({ + const fg = await this.filtersService.filterCreate(context, { viewId: vw.id, filter: withoutId({ ...fl, @@ -1263,7 +1290,7 @@ export class ImportService { // create sorts for (const sr of view.sorts) { - await this.sortsService.sortCreate({ + await this.sortsService.sortCreate(context, { viewId: vw.id, sort: withoutId({ ...sr, @@ -1274,7 +1301,7 @@ export class ImportService { } // update view columns - const vwColumns = await this.viewColumnsService.columnList({ + const vwColumns = await this.viewColumnsService.columnList(context, { viewId: vw.id, }); @@ -1291,7 +1318,7 @@ export class ImportService { underline: fcl.underline, } : {}; - await this.viewColumnsService.columnUpdate({ + await this.viewColumnsService.columnUpdate(context, { viewId: vw.id, columnId: cl.id, column: { @@ -1311,7 +1338,7 @@ export class ImportService { ); if (!fcl) continue; const { fk_column_id, ...rest } = fcl; - await this.gridColumnsService.gridColumnUpdate({ + await this.gridColumnsService.gridColumnUpdate(context, { gridViewColumnId: cl.id, grid: { ...withoutNull(rest), @@ -1327,7 +1354,7 @@ export class ImportService { ); if (!fcl) continue; const { fk_column_id, ...rest } = fcl; - await this.formColumnsService.columnUpdate({ + await this.formColumnsService.columnUpdate(context, { formViewColumnId: cl.id, formViewColumn: { ...withoutNull(rest), @@ -1344,7 +1371,7 @@ export class ImportService { // fix view order (view insert will always put it at the end) if (view.order !== vw.order) { - await this.viewsService.viewUpdate({ + await this.viewsService.viewUpdate(context, { viewId: vw.id, view: { order: view.order, @@ -1374,7 +1401,7 @@ export class ImportService { ...rest, }); - const hk = await this.hooksService.hookCreate({ + const hk = await this.hooksService.hookCreate(context, { tableId: table.id, hook: { ...hookData, @@ -1388,7 +1415,7 @@ export class ImportService { // create filters for (const fl of filters) { - const fg = await this.filtersService.hookFilterCreate({ + const fg = await this.filtersService.hookFilterCreate(context, { hookId: hk.id, filter: withoutId({ ...fl, @@ -1417,6 +1444,7 @@ export class ImportService { } async createView( + context: NcContext, idMap: Map, md: Model, vw: Partial, @@ -1429,7 +1457,7 @@ export class ImportService { if (view) { const gridData = withoutNull(vw.view); if (gridData) { - await this.gridsService.gridViewUpdate({ + await this.gridsService.gridViewUpdate(context, { viewId: view.id, grid: gridData, req, @@ -1441,14 +1469,14 @@ export class ImportService { switch (vw.type) { case ViewTypes.GRID: { - const gview = await this.gridsService.gridViewCreate({ + const gview = await this.gridsService.gridViewCreate(context, { tableId: md.id, grid: vw as ViewCreateReqType, req, }); const gridData = withoutNull(vw.view); if (gridData) { - await this.gridsService.gridViewUpdate({ + await this.gridsService.gridViewUpdate(context, { viewId: gview.id, grid: gridData, req, @@ -1457,7 +1485,7 @@ export class ImportService { return gview; } case ViewTypes.FORM: { - const fview = await this.formsService.formViewCreate({ + const fview = await this.formsService.formViewCreate(context, { tableId: md.id, body: vw as ViewCreateReqType, user, @@ -1465,7 +1493,7 @@ export class ImportService { }); const formData = withoutNull(vw.view); if (formData) { - await this.formsService.formViewUpdate({ + await this.formsService.formViewUpdate(context, { formViewId: fview.id, form: formData, req, @@ -1474,7 +1502,7 @@ export class ImportService { return fview; } case ViewTypes.CALENDAR: { - return await this.calendarsService.calendarViewCreate({ + return await this.calendarsService.calendarViewCreate(context, { tableId: md.id, calendar: { ...vw, @@ -1490,7 +1518,7 @@ export class ImportService { }); } case ViewTypes.GALLERY: { - const glview = await this.galleriesService.galleryViewCreate({ + const glview = await this.galleriesService.galleryViewCreate(context, { tableId: md.id, gallery: vw as ViewCreateReqType, user, @@ -1505,7 +1533,7 @@ export class ImportService { break; } } - await this.galleriesService.galleryViewUpdate({ + await this.galleriesService.galleryViewUpdate(context, { galleryViewId: glview.id, gallery: galleryData, req, @@ -1514,7 +1542,7 @@ export class ImportService { return glview; } case ViewTypes.KANBAN: { - const kview = await this.kanbansService.kanbanViewCreate({ + const kview = await this.kanbansService.kanbanViewCreate(context, { tableId: md.id, kanban: vw as ViewCreateReqType, user, @@ -1522,7 +1550,7 @@ export class ImportService { }); const kanbanData = withoutNull(vw.view); if (kanbanData) { - const grpCol = await Column.get({ + const grpCol = await Column.get(context, { source_id: md.source_id, colId: idMap.get(kanbanData['fk_grp_col_id']), }); @@ -1561,7 +1589,7 @@ export class ImportService { } } } - await this.kanbansService.kanbanViewUpdate({ + await this.kanbansService.kanbanViewUpdate(context, { kanbanViewId: kview.id, kanban: kanbanData, req, @@ -1574,24 +1602,27 @@ export class ImportService { return null; } - async importBase(param: { - user: User; - baseId: string; - sourceId: string; - src: { - type: 'local' | 'url' | 'file'; - path?: string; - url?: string; - file?: any; - }; - req: NcRequest; - }) { + async importBase( + context: NcContext, + param: { + user: User; + baseId: string; + sourceId: string; + src: { + type: 'local' | 'url' | 'file'; + path?: string; + url?: string; + file?: any; + }; + req: NcRequest; + }, + ) { const hrTime = initTime(); const { user, baseId, sourceId, src, req } = param; - const destProject = await Base.get(baseId); - const destBase = await Source.get(sourceId); + const destProject = await Base.get(context, baseId); + const destBase = await Source.get(context, sourceId); if (!destProject) return NcError.baseNotFound(baseId); if (!destBase) return NcError.sourceNotFound(sourceId); @@ -1612,7 +1643,7 @@ export class ImportService { // store fk_mm_model_id (mm) to link once let handledLinks = []; - const idMap = await this.importModels({ + const idMap = await this.importModels(context, { user, baseId, sourceId, @@ -1641,11 +1672,11 @@ export class ImportService { file.replace(/\.csv$/, ''), ); - const model = await Model.get(modelId); + const model = await Model.get(context, modelId); this.debugLog(`Importing ${model.title}...`); - await this.importDataFromCsvStream({ + await this.importDataFromCsvStream(context, { idMap, dataStream: readStream, destProject, @@ -1668,7 +1699,7 @@ export class ImportService { ).fileReadByStream(linkFile); // eslint-disable-next-line @typescript-eslint/no-unused-vars - handledLinks = await this.importLinkFromCsvStream({ + handledLinks = await this.importLinkFromCsvStream(context, { idMap, linkStream: linkReadStream, destProject, @@ -1690,13 +1721,16 @@ export class ImportService { } } - importDataFromCsvStream(param: { - idMap: Map; - dataStream: Readable; - destProject: Base; - destBase: Source; - destModel: Model; - }): Promise { + importDataFromCsvStream( + context: NcContext, + param: { + idMap: Map; + dataStream: Readable; + destProject: Base; + destBase: Source; + destModel: Model; + }, + ): Promise { const { idMap, dataStream, destBase, destProject, destModel } = param; const headers: string[] = []; @@ -1711,7 +1745,7 @@ export class ImportService { for (const header of results.data as any) { const id = idMap.get(header); if (id) { - const col = await Column.get({ + const col = await Column.get(context, { source_id: destBase.id, colId: id, }); @@ -1721,7 +1755,7 @@ export class ImportService { (col.colOptions?.type === RelationTypes.ONE_TO_ONE && col.meta?.bt) ) { - const childCol = await Column.get({ + const childCol = await Column.get(context, { source_id: destBase.id, colId: col.colOptions.fk_child_column_id, }); @@ -1760,7 +1794,7 @@ export class ImportService { if (chunk.length > 1000) { parser.pause(); try { - await this.bulkDataService.bulkDataInsert({ + await this.bulkDataService.bulkDataInsert(context, { baseName: destProject.id, tableName: destModel.id, body: chunk, @@ -1781,7 +1815,7 @@ export class ImportService { complete: async () => { if (chunk.length > 0) { try { - await this.bulkDataService.bulkDataInsert({ + await this.bulkDataService.bulkDataInsert(context, { baseName: destProject.id, tableName: destModel.id, body: chunk, @@ -1802,13 +1836,16 @@ export class ImportService { } // import links and return handled links - async importLinkFromCsvStream(param: { - idMap: Map; - linkStream: Readable; - destProject: Base; - destBase: Source; - handledLinks: string[]; - }): Promise { + async importLinkFromCsvStream( + context: NcContext, + param: { + idMap: Map; + linkStream: Readable; + destProject: Base; + destBase: Source; + handledLinks: string[]; + }, + ): Promise { const { idMap, linkStream, destBase, destProject, handledLinks } = param; const lChunks: Record = {}; // fk_mm_model_id: { rowId, childId }[] @@ -1817,7 +1854,7 @@ export class ImportService { for (const [k, v] of Object.entries(lChunks)) { try { if (v.length === 0) continue; - await this.bulkDataService.bulkDataInsert({ + await this.bulkDataService.bulkDataInsert(context, { baseName: destProject.id, tableName: k, body: v, @@ -1878,17 +1915,23 @@ export class ImportService { await insertChunks(); - const col = await Column.get({ + const col = await Column.get(context, { source_id: destBase.id, colId: findWithIdentifier(idMap, columnId), }); if (col) { const colOptions = - await col.getColOptions(); + await col.getColOptions( + context, + ); - const vChildCol = await colOptions.getMMChildColumn(); - const vParentCol = await colOptions.getMMParentColumn(); + const vChildCol = await colOptions.getMMChildColumn( + context, + ); + const vParentCol = await colOptions.getMMParentColumn( + context, + ); mmParentChild[col.colOptions.fk_mm_model_id] = { parent: vParentCol.column_name, diff --git a/packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.controller.ts b/packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.controller.ts index dfccac10d5..6870110522 100644 --- a/packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.controller.ts +++ b/packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.controller.ts @@ -7,13 +7,14 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { NcError } from '~/helpers/catchError'; import { JobTypes } from '~/interface/Jobs'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { IJobsService } from '~/modules/jobs/jobs-service.interface'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -28,7 +29,11 @@ export class MetaSyncController { ]) @HttpCode(200) @Acl('metaDiffSync') - async metaDiffSync(@Param('baseId') baseId: string, @Req() req: Request) { + async metaDiffSync( + @TenantContext() context: NcContext, + @Param('baseId') baseId: string, + @Req() req: NcRequest, + ) { const jobs = await this.jobsService.jobList(); const fnd = jobs.find( (j) => j.name === JobTypes.MetaSync && j.data.baseId === baseId, @@ -39,6 +44,7 @@ export class MetaSyncController { } const job = await this.jobsService.add(JobTypes.MetaSync, { + context, baseId, sourceId: 'all', user: req.user, @@ -59,9 +65,10 @@ export class MetaSyncController { @HttpCode(200) @Acl('baseMetaDiffSync') async baseMetaDiffSync( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Param('sourceId') sourceId: string, - @Req() req: Request, + @Req() req: NcRequest, ) { const jobs = await this.jobsService.jobList(); const fnd = jobs.find( @@ -76,6 +83,7 @@ export class MetaSyncController { } const job = await this.jobsService.add(JobTypes.MetaSync, { + context, baseId, sourceId, user: req.user, diff --git a/packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.processor.ts b/packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.processor.ts index df403e1c00..56f09bfe21 100644 --- a/packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.processor.ts +++ b/packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.processor.ts @@ -1,7 +1,7 @@ import debug from 'debug'; import { Process, Processor } from '@nestjs/bull'; import { Job } from 'bull'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { JOBS_QUEUE, JobTypes } from '~/interface/Jobs'; import { MetaDiffsService } from '~/services/meta-diffs.service'; @@ -16,20 +16,23 @@ export class MetaSyncProcessor { this.debugLog(`job started for ${job.id}`); const info: { - baseId: string; + context: NcContext; sourceId: string; user: any; req: NcRequest; } = job.data; + const context = info.context; + const baseId = context.base_id; + if (info.sourceId === 'all') { - await this.metaDiffsService.metaDiffSync({ - baseId: info.baseId, + await this.metaDiffsService.metaDiffSync(context, { + baseId: baseId, req: info.req, }); } else { - await this.metaDiffsService.baseMetaDiffSync({ - baseId: info.baseId, + await this.metaDiffsService.baseMetaDiffSync(context, { + baseId: baseId, sourceId: info.sourceId, req: info.req, }); diff --git a/packages/nocodb/src/modules/jobs/jobs/source-create/source-create.controller.ts b/packages/nocodb/src/modules/jobs/jobs/source-create/source-create.controller.ts index e262c121ed..99d7a1985a 100644 --- a/packages/nocodb/src/modules/jobs/jobs/source-create/source-create.controller.ts +++ b/packages/nocodb/src/modules/jobs/jobs/source-create/source-create.controller.ts @@ -8,7 +8,6 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { BaseReqType } from 'nocodb-sdk'; import { GlobalGuard } from '~/guards/global/global.guard'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; @@ -16,6 +15,8 @@ import { NcError } from '~/helpers/catchError'; import { JobTypes } from '~/interface/Jobs'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { IJobsService } from '~/modules/jobs/jobs-service.interface'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -31,9 +32,10 @@ export class SourceCreateController { @HttpCode(200) @Acl('baseCreate') async baseCreate( + @TenantContext() context: NcContext, @Param('baseId') baseId: string, @Body() body: BaseReqType, - @Req() req: Request, + @Req() req: NcRequest, ) { const jobs = await this.jobsService.jobList(); const fnd = jobs.find( @@ -47,6 +49,7 @@ export class SourceCreateController { } const job = await this.jobsService.add(JobTypes.SourceCreate, { + context, baseId, source: body, req: { diff --git a/packages/nocodb/src/modules/jobs/jobs/source-create/source-create.processor.ts b/packages/nocodb/src/modules/jobs/jobs/source-create/source-create.processor.ts index 09ed262b94..dfeaa495c3 100644 --- a/packages/nocodb/src/modules/jobs/jobs/source-create/source-create.processor.ts +++ b/packages/nocodb/src/modules/jobs/jobs/source-create/source-create.processor.ts @@ -18,7 +18,7 @@ export class SourceCreateProcessor { async job(job: Job) { this.debugLog(`job started for ${job.id}`); - const { baseId, source, req } = job.data; + const { context, baseId, source, req } = job.data; const logBasic = (log) => { this.jobsLogService.sendLog(job, { message: log }); @@ -26,7 +26,7 @@ export class SourceCreateProcessor { }; const { source: createdSource, error } = - await this.sourcesService.baseCreate({ + await this.sourcesService.baseCreate(context, { baseId, source, logger: logBasic, @@ -34,7 +34,7 @@ export class SourceCreateProcessor { }); if (error) { - await this.sourcesService.baseDelete({ + await this.sourcesService.baseDelete(context, { sourceId: createdSource.id, req: {}, }); diff --git a/packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.controller.ts b/packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.controller.ts index f86d9ad8d7..f6b4d0e777 100644 --- a/packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.controller.ts +++ b/packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.controller.ts @@ -6,7 +6,6 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { Request } from 'express'; import { GlobalGuard } from '~/guards/global/global.guard'; import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware'; import { NcError } from '~/helpers/catchError'; @@ -14,6 +13,8 @@ import { JobTypes } from '~/interface/Jobs'; import { SourcesService } from '~/services/sources.service'; import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard'; import { IJobsService } from '~/modules/jobs/jobs-service.interface'; +import { TenantContext } from '~/decorators/tenant-context.decorator'; +import { NcContext, NcRequest } from '~/interface/config'; @Controller() @UseGuards(MetaApiLimiterGuard, GlobalGuard) @@ -28,7 +29,11 @@ export class SourceDeleteController { '/api/v2/meta/bases/:baseId/sources/:sourceId', ]) @Acl('baseDelete') - async baseDelete(@Param('sourceId') sourceId: string, @Req() req: Request) { + async baseDelete( + @TenantContext() context: NcContext, + @Param('sourceId') sourceId: string, + @Req() req: NcRequest, + ) { const jobs = await this.jobsService.jobList(); const fnd = jobs.find( (j) => j.name === JobTypes.SourceDelete && j.data.sourceId === sourceId, @@ -38,9 +43,10 @@ export class SourceDeleteController { NcError.badRequest('There is already a job running to delete this base.'); } - await this.sourcesService.baseSoftDelete({ sourceId }); + await this.sourcesService.baseSoftDelete(context, { sourceId }); const job = await this.jobsService.add(JobTypes.SourceDelete, { + context, sourceId, req: { user: req.user, diff --git a/packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.processor.ts b/packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.processor.ts index 6547bc2d22..5cc31e7ca0 100644 --- a/packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.processor.ts +++ b/packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.processor.ts @@ -14,9 +14,9 @@ export class SourceDeleteProcessor { async job(job: Job) { this.debugLog(`job started for ${job.id}`); - const { sourceId, req } = job.data; + const { context, sourceId, req } = job.data; - await this.sourcesService.baseDelete({ + await this.sourcesService.baseDelete(context, { sourceId, req, }); diff --git a/packages/nocodb/src/modules/jobs/jobs/webhook-handler/webhook-handler.processor.ts b/packages/nocodb/src/modules/jobs/jobs/webhook-handler/webhook-handler.processor.ts index 8fe5b04414..dc51844619 100644 --- a/packages/nocodb/src/modules/jobs/jobs/webhook-handler/webhook-handler.processor.ts +++ b/packages/nocodb/src/modules/jobs/jobs/webhook-handler/webhook-handler.processor.ts @@ -17,23 +17,24 @@ export class WebhookHandlerProcessor { @Process(JobTypes.HandleWebhook) async job(job: Job) { - const { hookId, modelId, viewId, prevData, newData, user } = job.data; + const { context, hookId, modelId, viewId, prevData, newData, user } = + job.data; - const hook = await Hook.get(hookId); + const hook = await Hook.get(context, hookId); if (!hook) { this.logger.error(`Hook not found for id: ${hookId}`); return; } - const model = await Model.get(modelId); + const model = await Model.get(context, modelId); if (!model) { this.logger.error(`Model not found for id: ${modelId}`); return; } - const view = viewId ? await View.get(viewId) : null; + const view = viewId ? await View.get(context, viewId) : null; - await invokeWebhook({ + await invokeWebhook(context, { hook, model, view, diff --git a/packages/nocodb/src/schema/swagger-v2.json b/packages/nocodb/src/schema/swagger-v2.json index 7ce1cd46f2..6e2c729b6d 100644 --- a/packages/nocodb/src/schema/swagger-v2.json +++ b/packages/nocodb/src/schema/swagger-v2.json @@ -16355,6 +16355,11 @@ "example": "p_124hhlkbeasewh", "type": "string" }, + "fk_workspace_id": { + "description": "Workspace ID", + "example": "ws_123456", + "type": "string" + }, "is_meta": { "$ref": "#/components/schemas/Bool" }, diff --git a/packages/nocodb/src/schema/swagger.json b/packages/nocodb/src/schema/swagger.json index 6da4113e60..24af650cd1 100644 --- a/packages/nocodb/src/schema/swagger.json +++ b/packages/nocodb/src/schema/swagger.json @@ -22692,6 +22692,11 @@ "example": "p_124hhlkbeasewh", "type": "string" }, + "fk_workspace_id": { + "description": "Workspace ID", + "example": "ws_123456", + "type": "string" + }, "is_meta": { "$ref": "#/components/schemas/Bool" }, 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 f2e2a0ebf8..aaf61e8697 100644 --- a/packages/nocodb/src/services/api-docs/api-docs.service.ts +++ b/packages/nocodb/src/services/api-docs/api-docs.service.ts @@ -1,22 +1,26 @@ import { Injectable } from '@nestjs/common'; import getSwaggerJSON from './swagger/getSwaggerJSON'; import getSwaggerJSONV2 from './swaggerV2/getSwaggerJSONV2'; +import type { NcContext } from '~/interface/config'; import { NcError } from '~/helpers/catchError'; import { Base, Model } from '~/models'; @Injectable() export class ApiDocsService { - async swaggerJson(param: { baseId: string; siteUrl: string }) { - const base = await Base.get(param.baseId); + async swaggerJson( + context: NcContext, + param: { baseId: string; siteUrl: string }, + ) { + const base = await Base.get(context, param.baseId); if (!base) NcError.baseNotFound(param.baseId); - const models = await Model.list({ + const models = await Model.list(context, { base_id: param.baseId, source_id: null, }); - const swagger = await getSwaggerJSON(base, models); + const swagger = await getSwaggerJSON(context, base, models); swagger.servers = [ { @@ -35,17 +39,20 @@ export class ApiDocsService { return swagger; } - async swaggerJsonV2(param: { baseId: string; siteUrl: string }) { - const base = await Base.get(param.baseId); + async swaggerJsonV2( + context: NcContext, + param: { baseId: string; siteUrl: string }, + ) { + const base = await Base.get(context, param.baseId); if (!base) NcError.baseNotFound(param.baseId); - const models = await Model.list({ + const models = await Model.list(context, { base_id: param.baseId, source_id: null, }); - const swagger = await getSwaggerJSONV2(base, models); + const swagger = await getSwaggerJSONV2(context, base, models); swagger.servers = [ { diff --git a/packages/nocodb/src/services/api-docs/swagger/getPaths.ts b/packages/nocodb/src/services/api-docs/swagger/getPaths.ts index ee43085100..d6d46ec697 100644 --- a/packages/nocodb/src/services/api-docs/swagger/getPaths.ts +++ b/packages/nocodb/src/services/api-docs/swagger/getPaths.ts @@ -2,9 +2,11 @@ import { getModelPaths, getViewPaths } from './templates/paths'; import type { Base, Model } from '~/models'; import type { SwaggerColumn } from './getSwaggerColumnMetas'; import type { SwaggerView } from './getSwaggerJSON'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; export default async function getPaths( + context: NcContext, { base, model, @@ -18,7 +20,7 @@ export default async function getPaths( }, _ncMeta = Noco.ncMeta, ) { - const swaggerPaths = await getModelPaths({ + const swaggerPaths = await getModelPaths(context, { tableName: model.title, type: model.type, orgs: 'v1', @@ -32,7 +34,7 @@ export default async function getPaths( ); Object.assign( swaggerPaths, - await getViewPaths({ + await getViewPaths(context, { tableName: model.title, viewName: view.title, type: model.type, diff --git a/packages/nocodb/src/services/api-docs/swagger/getSwaggerColumnMetas.ts b/packages/nocodb/src/services/api-docs/swagger/getSwaggerColumnMetas.ts index 5540eecf97..0683e609cd 100644 --- a/packages/nocodb/src/services/api-docs/swagger/getSwaggerColumnMetas.ts +++ b/packages/nocodb/src/services/api-docs/swagger/getSwaggerColumnMetas.ts @@ -1,9 +1,11 @@ import { RelationTypes, UITypes } from 'nocodb-sdk'; import type { Base, Column, LinkToAnotherRecordColumn } from '~/models'; +import type { NcContext } from '~/interface/config'; import SwaggerTypes from '~/db/sql-mgr/code/routers/xc-ts/SwaggerTypes'; import Noco from '~/Noco'; export default async ( + context: NcContext, columns: Column[], base: Base, ncMeta = Noco.ncMeta, @@ -22,10 +24,11 @@ export default async ( case UITypes.LinkToAnotherRecord: { const colOpt = await c.getColOptions( + context, ncMeta, ); if (colOpt) { - const relTable = await colOpt.getRelatedTable(ncMeta); + const relTable = await colOpt.getRelatedTable(context, ncMeta); if (colOpt.type === RelationTypes.BELONGS_TO) { field.type = undefined; field.$ref = `#/components/schemas/${relTable.title}Request`; diff --git a/packages/nocodb/src/services/api-docs/swagger/getSwaggerJSON.ts b/packages/nocodb/src/services/api-docs/swagger/getSwaggerJSON.ts index 178a366cf2..b3afa52471 100644 --- a/packages/nocodb/src/services/api-docs/swagger/getSwaggerJSON.ts +++ b/packages/nocodb/src/services/api-docs/swagger/getSwaggerJSON.ts @@ -11,9 +11,11 @@ import type { Model, View, } from '~/models'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; export default async function getSwaggerJSON( + context: NcContext, base: Base, models: Model[], ncMeta = Noco.ncMeta, @@ -33,24 +35,25 @@ export default async function getSwaggerJSON( let paths = {}; const columns = await getSwaggerColumnMetas( - await model.getColumns(ncMeta), + context, + await model.getColumns(context, ncMeta), base, ncMeta, ); const views: SwaggerView[] = []; - for (const view of (await model.getViews(false, ncMeta)) || []) { + for (const view of (await model.getViews(context, false, ncMeta)) || []) { if (view.type !== ViewTypes.GRID) continue; views.push({ view, - columns: await view.getColumns(ncMeta), + columns: await view.getColumns(context, ncMeta), }); } // skip mm tables if (!model.mm) - paths = await getPaths({ base, model, columns, views }, ncMeta); + paths = await getPaths(context, { base, model, columns, views }, ncMeta); const schemas = await getSchemas({ base, model, columns, views }, ncMeta); diff --git a/packages/nocodb/src/services/api-docs/swagger/templates/params.ts b/packages/nocodb/src/services/api-docs/swagger/templates/params.ts index 65c466a3d5..c8373573ce 100644 --- a/packages/nocodb/src/services/api-docs/swagger/templates/params.ts +++ b/packages/nocodb/src/services/api-docs/swagger/templates/params.ts @@ -1,6 +1,7 @@ import { isLinksOrLTAR, RelationTypes, UITypes } from 'nocodb-sdk'; import type { LinkToAnotherRecordColumn } from '~/models'; import type { SwaggerColumn } from '../getSwaggerColumnMetas'; +import type { NcContext } from '~/interface/config'; export const rowIdParam = { schema: { @@ -193,6 +194,7 @@ export const nestedOffsetParam = (colName) => ({ }); export const getNestedParams = async ( + context: NcContext, columns: SwaggerColumn[], ): Promise => { return await columns.reduce(async (paramsArr, { column }) => { @@ -201,7 +203,9 @@ export const getNestedParams = async ( if (column.system) { return paramsArr; } - const colOpt = await column.getColOptions(); + const colOpt = await column.getColOptions( + context, + ); if (colOpt.type !== RelationTypes.BELONGS_TO) { return [ ...(await paramsArr), diff --git a/packages/nocodb/src/services/api-docs/swagger/templates/paths.ts b/packages/nocodb/src/services/api-docs/swagger/templates/paths.ts index a95bd752b6..a52d8807ae 100644 --- a/packages/nocodb/src/services/api-docs/swagger/templates/paths.ts +++ b/packages/nocodb/src/services/api-docs/swagger/templates/paths.ts @@ -17,14 +17,18 @@ import { } from './params'; import { csvExportResponseHeader } from './headers'; import type { SwaggerColumn } from '../getSwaggerColumnMetas'; +import type { NcContext } from '~/interface/config'; -export const getModelPaths = async (ctx: { - tableName: string; - orgs: string; - type: ModelTypes; - columns: SwaggerColumn[]; - baseName: string; -}): Promise<{ [path: string]: any }> => ({ +export const getModelPaths = async ( + context: NcContext, + ctx: { + tableName: string; + orgs: string; + type: ModelTypes; + columns: SwaggerColumn[]; + baseName: string; + }, +): Promise<{ [path: string]: any }> => ({ [`/api/v1/db/data/${ctx.orgs}/${ctx.baseName}/${ctx.tableName}`]: { get: { summary: `${ctx.tableName} list`, @@ -38,7 +42,7 @@ export const getModelPaths = async (ctx: { limitParam, shuffleParam, offsetParam, - ...(await getNestedParams(ctx.columns)), + ...(await getNestedParams(context, ctx.columns)), ], responses: { '200': { @@ -471,14 +475,17 @@ export const getModelPaths = async (ctx: { }, }); -export const getViewPaths = async (ctx: { - tableName: string; - viewName: string; - type: ModelTypes; - orgs: string; - baseName: string; - columns: SwaggerColumn[]; -}): Promise => ({ +export const getViewPaths = async ( + context: NcContext, + ctx: { + tableName: string; + viewName: string; + type: ModelTypes; + orgs: string; + baseName: string; + columns: SwaggerColumn[]; + }, +): Promise => ({ [`/api/v1/db/data/${ctx.orgs}/${ctx.baseName}/${ctx.tableName}/views/${ctx.viewName}`]: { get: { @@ -490,7 +497,7 @@ export const getViewPaths = async (ctx: { fieldsParam, sortParam, whereParam, - ...(await getNestedParams(ctx.columns)), + ...(await getNestedParams(context, ctx.columns)), ], responses: { '200': { diff --git a/packages/nocodb/src/services/api-docs/swaggerV2/getPaths.ts b/packages/nocodb/src/services/api-docs/swaggerV2/getPaths.ts index cfed2722cc..f1ae96b4b2 100644 --- a/packages/nocodb/src/services/api-docs/swaggerV2/getPaths.ts +++ b/packages/nocodb/src/services/api-docs/swaggerV2/getPaths.ts @@ -2,9 +2,11 @@ import { getModelPaths } from './templates/paths'; import type { Model } from '~/models'; import type { SwaggerColumn } from './getSwaggerColumnMetas'; import type { SwaggerView } from './getSwaggerJSONV2'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; export default async function getPaths( + context: NcContext, { model, columns, @@ -16,7 +18,7 @@ export default async function getPaths( }, _ncMeta = Noco.ncMeta, ) { - const swaggerPaths = await getModelPaths({ + const swaggerPaths = await getModelPaths(context, { tableName: model.title, tableId: model.id, views, diff --git a/packages/nocodb/src/services/api-docs/swaggerV2/getSwaggerColumnMetas.ts b/packages/nocodb/src/services/api-docs/swaggerV2/getSwaggerColumnMetas.ts index d945c16c19..ec150c7199 100644 --- a/packages/nocodb/src/services/api-docs/swaggerV2/getSwaggerColumnMetas.ts +++ b/packages/nocodb/src/services/api-docs/swaggerV2/getSwaggerColumnMetas.ts @@ -1,9 +1,11 @@ import { UITypes } from 'nocodb-sdk'; import type { Base, Column, LinkToAnotherRecordColumn } from '~/models'; +import type { NcContext } from '~/interface/config'; import SwaggerTypes from '~/db/sql-mgr/code/routers/xc-ts/SwaggerTypes'; import Noco from '~/Noco'; export default async ( + context: NcContext, columns: Column[], base: Base, ncMeta = Noco.ncMeta, @@ -22,10 +24,11 @@ export default async ( case UITypes.LinkToAnotherRecord: { const colOpt = await c.getColOptions( + context, ncMeta, ); if (colOpt) { - const relTable = await colOpt.getRelatedTable(ncMeta); + const relTable = await colOpt.getRelatedTable(context, ncMeta); field.type = undefined; field.$ref = `#/components/schemas/${relTable.title}Request`; } diff --git a/packages/nocodb/src/services/api-docs/swaggerV2/getSwaggerJSONV2.ts b/packages/nocodb/src/services/api-docs/swaggerV2/getSwaggerJSONV2.ts index 4f20436791..b07474eecf 100644 --- a/packages/nocodb/src/services/api-docs/swaggerV2/getSwaggerJSONV2.ts +++ b/packages/nocodb/src/services/api-docs/swaggerV2/getSwaggerJSONV2.ts @@ -11,9 +11,11 @@ import type { Model, View, } from '~/models'; +import type { NcContext } from '~/interface/config'; import Noco from '~/Noco'; export default async function getSwaggerJSONV2( + context: NcContext, base: Base, models: Model[], ncMeta = Noco.ncMeta, @@ -33,23 +35,25 @@ export default async function getSwaggerJSONV2( let paths = {}; const columns = await getSwaggerColumnMetas( - await model.getColumns(ncMeta), + context, + await model.getColumns(context, ncMeta), base, ncMeta, ); const views: SwaggerView[] = []; - for (const view of (await model.getViews(false, ncMeta)) || []) { + for (const view of (await model.getViews(context, false, ncMeta)) || []) { if (view.type !== ViewTypes.GRID) continue; views.push({ view, - columns: await view.getColumns(ncMeta), + columns: await view.getColumns(context, ncMeta), }); } // skip mm tables - if (!model.mm) paths = await getPaths({ model, columns, views }, ncMeta); + if (!model.mm) + paths = await getPaths(context, { model, columns, views }, ncMeta); const schemas = await getSchemas({ base, model, columns, views }, ncMeta); diff --git a/packages/nocodb/src/services/api-docs/swaggerV2/templates/params.ts b/packages/nocodb/src/services/api-docs/swaggerV2/templates/params.ts index 7805bfa819..9f0e88a856 100644 --- a/packages/nocodb/src/services/api-docs/swaggerV2/templates/params.ts +++ b/packages/nocodb/src/services/api-docs/swaggerV2/templates/params.ts @@ -2,6 +2,7 @@ import { isLinksOrLTAR, RelationTypes, UITypes } from 'nocodb-sdk'; import type { LinkToAnotherRecordColumn } from '~/models'; import type { SwaggerColumn } from '../getSwaggerColumnMetas'; import type { SwaggerView } from '~/services/api-docs/swaggerV2/getSwaggerJSONV2'; +import type { NcContext } from '~/interface/config'; export const recordIdParam = { schema: { @@ -213,11 +214,14 @@ export const nestedOffsetParam = (colName) => ({ }); export const getNestedParams = async ( + context: NcContext, columns: SwaggerColumn[], ): Promise => { return await columns.reduce(async (paramsArr, { column }) => { if (column.uidt === UITypes.LinkToAnotherRecord && !column.system) { - const colOpt = await column.getColOptions(); + const colOpt = await column.getColOptions( + context, + ); if (colOpt.type !== RelationTypes.BELONGS_TO) { return [ ...(await paramsArr), diff --git a/packages/nocodb/src/services/api-docs/swaggerV2/templates/paths.ts b/packages/nocodb/src/services/api-docs/swaggerV2/templates/paths.ts index 80bfddc3f3..320d2b32f0 100644 --- a/packages/nocodb/src/services/api-docs/swaggerV2/templates/paths.ts +++ b/packages/nocodb/src/services/api-docs/swaggerV2/templates/paths.ts @@ -13,15 +13,19 @@ import { } from './params'; import type { SwaggerColumn } from '../getSwaggerColumnMetas'; import type { SwaggerView } from '~/services/api-docs/swaggerV2/getSwaggerJSONV2'; +import type { NcContext } from '~/interface/config'; import { isRelationExist } from '~/services/api-docs/swagger/templates/paths'; -export const getModelPaths = async (ctx: { - tableName: string; - type: ModelTypes; - columns: SwaggerColumn[]; - tableId: string; - views: SwaggerView[]; -}): Promise<{ [path: string]: any }> => ({ +export const getModelPaths = async ( + context: NcContext, + ctx: { + tableName: string; + type: ModelTypes; + columns: SwaggerColumn[]; + tableId: string; + views: SwaggerView[]; + }, +): Promise<{ [path: string]: any }> => ({ [`/api/v2/tables/${ctx.tableId}/records`]: { get: { summary: `${ctx.tableName} list`, @@ -36,7 +40,7 @@ export const getModelPaths = async (ctx: { limitParam, shuffleParam, offsetParam, - ...(await getNestedParams(ctx.columns)), + ...(await getNestedParams(context, ctx.columns)), ], responses: { '200': { diff --git a/packages/nocodb/src/services/api-tokens.service.ts b/packages/nocodb/src/services/api-tokens.service.ts index caed7622a7..43b5f5db9e 100644 --- a/packages/nocodb/src/services/api-tokens.service.ts +++ b/packages/nocodb/src/services/api-tokens.service.ts @@ -38,7 +38,7 @@ export class ApiTokensService { } async apiTokenDelete(param: { token; user: User; req: NcRequest }) { - const apiToken = await ApiToken.getByToken(param.token); + const apiToken = await ApiToken.getByToken(context, param.token); if ( !extractRolesObj(param.user.roles)[OrgUserRoles.SUPER_ADMIN] && apiToken.fk_user_id !== param.user.id @@ -53,6 +53,6 @@ export class ApiTokensService { }); // todo: verify token belongs to the user - return await ApiToken.delete(param.token); + return await ApiToken.delete(context, param.token); } } diff --git a/packages/nocodb/src/services/app-hooks-listener.service.ts b/packages/nocodb/src/services/app-hooks-listener.service.ts index f39135495e..44efb07864 100644 --- a/packages/nocodb/src/services/app-hooks-listener.service.ts +++ b/packages/nocodb/src/services/app-hooks-listener.service.ts @@ -64,6 +64,7 @@ export class AppHooksListenerService implements OnModuleInit, OnModuleDestroy { const param = data as ProjectUserUpdateEvent; await this.auditInsert({ + base_id: param.base.id, op_type: AuditOperationTypes.AUTHENTICATION, op_sub_type: AuditOperationSubTypes.ROLES_MANAGEMENT, user: param.updatedBy.email, diff --git a/packages/nocodb/src/services/audits.service.ts b/packages/nocodb/src/services/audits.service.ts index 3f39cbbb09..fccd57ae5a 100644 --- a/packages/nocodb/src/services/audits.service.ts +++ b/packages/nocodb/src/services/audits.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import DOMPurify from 'isomorphic-dompurify'; import { AuditOperationSubTypes, AuditOperationTypes } from 'nocodb-sdk'; import type { AuditRowUpdateReqType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import { AppHooksListenerService } from '~/services/app-hooks-listener.service'; import { validatePayload } from '~/helpers'; import { Audit, Model } from '~/models'; @@ -14,13 +15,18 @@ export class AuditsService { protected readonly appHooksService: AppHooksService, ) {} - async auditRowUpdate(param: { rowId: string; body: AuditRowUpdateReqType }) { + async auditRowUpdate( + context: NcContext, + param: { rowId: string; body: AuditRowUpdateReqType }, + ) { validatePayload( 'swagger.json#/components/schemas/AuditRowUpdateReq', param.body, ); - const model = await Model.getByIdOrName({ id: param.body.fk_model_id }); + const model = await Model.getByIdOrName(context, { + id: param.body.fk_model_id, + }); return await Audit.insert({ fk_model_id: param.body.fk_model_id, row_id: param.rowId, 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 5a96fb007a..a873e46e7f 100644 --- a/packages/nocodb/src/services/base-users/base-users.service.ts +++ b/packages/nocodb/src/services/base-users/base-users.service.ts @@ -10,7 +10,7 @@ import { v4 as uuidv4 } from 'uuid'; import * as ejs from 'ejs'; import validator from 'validator'; import type { ProjectUserReqType, UserType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { validatePayload } from '~/helpers'; import Noco from '~/Noco'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; @@ -28,8 +28,11 @@ import { sanitiseEmailContent } from '~/utils'; export class BaseUsersService { constructor(protected appHooksService: AppHooksService) {} - async userList(param: { baseId: string; mode?: 'full' | 'viewer' }) { - const baseUsers = await BaseUser.getUsersList({ + async userList( + context: NcContext, + param: { baseId: string; mode?: 'full' | 'viewer' }, + ) { + const baseUsers = await BaseUser.getUsersList(context, { base_id: param.baseId, mode: param.mode, }); @@ -39,11 +42,14 @@ export class BaseUsersService { }); } - async userInvite(param: { - baseId: string; - baseUser: ProjectUserReqType; - req: NcRequest; - }): Promise { + async userInvite( + context: NcContext, + param: { + baseId: string; + baseUser: ProjectUserReqType; + req: NcRequest; + }, + ): Promise { validatePayload( 'swagger.json#/components/schemas/ProjectUserReq', param.baseUser, @@ -90,7 +96,7 @@ export class BaseUsersService { // add user to base if user already exist const user = await User.getByEmail(email); - const base = await Base.get(param.baseId); + const base = await Base.get(context, param.baseId); if (!base) { return NcError.baseNotFound(param.baseId); @@ -98,9 +104,9 @@ export class BaseUsersService { if (user) { // check if this user has been added to this base - const baseUser = await BaseUser.get(param.baseId, user.id); + const baseUser = await BaseUser.get(context, param.baseId, user.id); - const base = await Base.get(param.baseId); + const base = await Base.get(context, param.baseId); if (!base) { return NcError.baseNotFound(param.baseId); @@ -112,7 +118,7 @@ export class BaseUsersService { ); } - await BaseUser.insert({ + await BaseUser.insert(context, { base_id: param.baseId, fk_user_id: user.id, roles: param.baseUser.roles || 'editor', @@ -137,7 +143,7 @@ export class BaseUsersService { }); // add user to base - await BaseUser.insert({ + await BaseUser.insert(context, { base_id: param.baseId, fk_user_id: user.id, roles: param.baseUser.roles, @@ -181,14 +187,17 @@ export class BaseUsersService { } } - async baseUserUpdate(param: { - userId: string; - // todo: update swagger - baseUser: ProjectUserReqType & { base_id: string }; - // todo: refactor - req: any; - baseId: string; - }): Promise { + async baseUserUpdate( + context: NcContext, + param: { + userId: string; + // todo: update swagger + baseUser: ProjectUserReqType & { base_id: string }; + // todo: refactor + req: any; + baseId: string; + }, + ): Promise { validatePayload( 'swagger.json#/components/schemas/ProjectUserReq', param.baseUser, @@ -198,7 +207,7 @@ export class BaseUsersService { NcError.badRequest('Missing base id'); } - const base = await Base.get(param.baseId); + const base = await Base.get(context, param.baseId); if (!base) { return NcError.baseNotFound(param.baseId); @@ -226,7 +235,7 @@ export class BaseUsersService { NcError.badRequest(`User with id '${param.userId}' doesn't exist`); } - const targetUser = await User.getWithRoles(param.userId, { + const targetUser = await User.getWithRoles(context, param.userId, { user, baseId: param.baseId, }); @@ -244,6 +253,7 @@ export class BaseUsersService { } await BaseUser.updateRoles( + context, param.baseId, param.userId, param.baseUser.roles, @@ -263,12 +273,15 @@ export class BaseUsersService { }; } - async baseUserDelete(param: { - baseId: string; - userId: string; - // todo: refactor - req: any; - }): Promise { + async baseUserDelete( + context: NcContext, + param: { + baseId: string; + userId: string; + // todo: refactor + req: any; + }, + ): Promise { const base_id = param.baseId; if (param.req.user?.id === param.userId) { @@ -282,29 +295,32 @@ export class BaseUsersService { 'Insufficient privilege to delete a super admin user.', ); - const baseUser = await BaseUser.get(base_id, param.userId); + const baseUser = await BaseUser.get(context, base_id, param.userId); if (baseUser?.roles?.split(',').includes('owner')) NcError.forbidden('Insufficient privilege to delete a owner user.'); } - await BaseUser.delete(base_id, param.userId); + await BaseUser.delete(context, base_id, param.userId); return true; } - async baseUserInviteResend(param: { - userId: string; - baseUser: ProjectUserReqType; - baseId: string; - // todo: refactor - req: any; - }): Promise { + async baseUserInviteResend( + context: NcContext, + param: { + userId: string; + baseUser: ProjectUserReqType; + baseId: string; + // todo: refactor + req: any; + }, + ): Promise { const user = await User.get(param.userId); if (!user) { NcError.badRequest(`User with id '${param.userId}' not found`); } - const base = await Base.get(param.baseId); + const base = await Base.get(context, param.baseId); if (!base) { return NcError.baseNotFound(param.baseId); @@ -318,8 +334,8 @@ export class BaseUsersService { }); const pluginData = await Noco.ncMeta.metaGet2( - null, - null, + context.workspace_id, + context.base_id, MetaTable.PLUGIN, { category: PluginCategory.EMAIL, @@ -385,11 +401,14 @@ export class BaseUsersService { } } - async baseUserMetaUpdate(param: { - body: any; - baseId: string; - user: UserType; - }) { + async baseUserMetaUpdate( + context: NcContext, + param: { + body: any; + baseId: string; + user: UserType; + }, + ) { // update base user data const baseUserData = extractProps(param.body, [ 'starred', @@ -399,14 +418,19 @@ export class BaseUsersService { if (Object.keys(baseUserData).length) { // create new base user if it doesn't exist - if (!(await BaseUser.get(param.baseId, param.user?.id))) { - await BaseUser.insert({ + if (!(await BaseUser.get(context, param.baseId, param.user?.id))) { + await BaseUser.insert(context, { ...baseUserData, base_id: param.baseId, fk_user_id: param.user?.id, }); } else { - await BaseUser.update(param.baseId, param.user?.id, baseUserData); + await BaseUser.update( + context, + param.baseId, + param.user?.id, + baseUserData, + ); } } diff --git a/packages/nocodb/src/services/bases.service.ts b/packages/nocodb/src/services/bases.service.ts index 635f6cdba0..1e4a30fab9 100644 --- a/packages/nocodb/src/services/bases.service.ts +++ b/packages/nocodb/src/services/bases.service.ts @@ -13,7 +13,8 @@ import type { ProjectUpdateReqType, UserType, } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { Request } from 'express'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { populateMeta, validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -23,7 +24,7 @@ import { Base, BaseUser } from '~/models'; import Noco from '~/Noco'; import { getToolDir } from '~/utils/nc-config'; import { MetaService } from '~/meta/meta.service'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; import { TablesService } from '~/services/tables.service'; const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 4); @@ -36,10 +37,13 @@ export class BasesService { protected tablesService: TablesService, ) {} - async baseList(param: { - user: { id: string; roles?: string | Record }; - query?: any; - }) { + async baseList( + context: NcContext, + param: { + user: { id: string; roles?: string | Record }; + query?: any; + }, + ) { const bases = extractRolesObj(param.user?.roles)[OrgUserRoles.SUPER_ADMIN] ? await Base.list(param.query) : await BaseUser.getProjectsList(param.user.id, param.query); @@ -47,8 +51,8 @@ export class BasesService { return bases; } - async getProjectWithInfo(param: { baseId: string }) { - const base = await Base.getWithInfo(param.baseId); + async getProjectWithInfo(context: NcContext, param: { baseId: string }) { + const base = await Base.getWithInfo(context, param.baseId); return base; } @@ -60,18 +64,21 @@ export class BasesService { return sanitizedProject; } - async baseUpdate(param: { - baseId: string; - base: ProjectUpdateReqType; - user: UserType; - req: NcRequest; - }) { + async baseUpdate( + context: NcContext, + param: { + baseId: string; + base: ProjectUpdateReqType; + user: UserType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ProjectUpdateReq', param.base, ); - const base = await Base.getWithInfo(param.baseId); + const base = await Base.getWithInfo(context, param.baseId); const data: Partial = extractPropsAndSanitize(param?.base as Base, [ 'title', @@ -80,13 +87,13 @@ export class BasesService { 'status', 'order', ]); - await this.validateProjectTitle(data, base); + await this.validateProjectTitle(context, data, base); if (data?.order !== undefined) { data.order = !isNaN(+data.order) ? +data.order : 0; } - const result = await Base.update(param.baseId, data); + const result = await Base.update(context, param.baseId, data); this.appHooksService.emit(AppEvents.PROJECT_UPDATE, { base, @@ -97,24 +104,37 @@ export class BasesService { return result; } - protected async validateProjectTitle(data: Partial, base: Base) { + protected async validateProjectTitle( + context: NcContext, + data: Partial, + base: Base, + ) { if ( data?.title && base.title !== data.title && - (await Base.getByTitle(data.title)) + (await Base.getByTitle( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + data.title, + )) ) { NcError.badRequest('Base title already in use'); } } - async baseSoftDelete(param: { baseId: any; user: UserType; req: NcRequest }) { - const base = await Base.getWithInfo(param.baseId); + async baseSoftDelete( + context: NcContext, + param: { baseId: any; user: UserType; req: NcRequest }, + ) { + const base = await Base.getWithInfo(context, param.baseId); if (!base) { NcError.baseNotFound(param.baseId); } - await Base.softDelete(param.baseId); + await Base.softDelete(context, param.baseId); this.appHooksService.emit(AppEvents.PROJECT_DELETE, { base, @@ -125,7 +145,7 @@ export class BasesService { return true; } - async baseCreate(param: { base: ProjectReqType; user: any; req: NcRequest }) { + async baseCreate(param: { base: ProjectReqType; user: any; req: any }) { validatePayload('swagger.json#/components/schemas/ProjectReq', param.base); const baseId = await this.metaService.genNanoid(MetaTable.PROJECT); @@ -198,8 +218,13 @@ export class BasesService { const base = await Base.createProject(baseBody); + const context = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + // TODO: create n:m instances here - await BaseUser.insert({ + await BaseUser.insert(context, { fk_user_id: (param as any).user.id, base_id: base.id, roles: 'owner', @@ -210,7 +235,7 @@ export class BasesService { // populate metadata if existing table for (const source of await base.getSources()) { if (process.env.NC_CLOUD !== 'true' && !base.is_meta) { - const info = await populateMeta(source, base); + const info = await populateMeta(context, source, base); this.appHooksService.emit(AppEvents.APIS_CREATED, { info, @@ -231,7 +256,7 @@ export class BasesService { return base; } - async createDefaultBase(param: { user: UserType; req: NcRequest }) { + async createDefaultBase(param: { user: UserType; req: Request }) { const base = await this.baseCreate({ base: { title: 'Getting Started', @@ -241,10 +266,15 @@ export class BasesService { req: param.req, }); + const context = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + const sqlUI = SqlUiFactory.create({ client: base.sources[0].type }); const columns = sqlUI?.getNewTableColumns() as any; - const table = await this.tablesService.tableCreate({ + const table = await this.tablesService.tableCreate(context, { baseId: base.id, sourceId: base.sources[0].id, table: { diff --git a/packages/nocodb/src/services/bulk-data-alias.service.ts b/packages/nocodb/src/services/bulk-data-alias.service.ts index 0f0216d17a..320d2b89a0 100644 --- a/packages/nocodb/src/services/bulk-data-alias.service.ts +++ b/packages/nocodb/src/services/bulk-data-alias.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import type { PathParams } from '~/helpers/dataHelpers'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; +import type { NcContext } from '~/interface/config'; import { getViewAndModelByAliasOrId } from '~/helpers/dataHelpers'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; import { Model, Source } from '~/models'; @@ -14,21 +15,22 @@ type BulkOperation = @Injectable() export class BulkDataAliasService { - async getModelViewBase(param: PathParams) { - const { model, view } = await getViewAndModelByAliasOrId(param); + async getModelViewBase(context: NcContext, param: PathParams) { + const { model, view } = await getViewAndModelByAliasOrId(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); return { model, view, source }; } async executeBulkOperation( + context: NcContext, param: PathParams & { operation: T; options: Parameters<(typeof BaseModelSqlv2.prototype)[T]>; }, ) { - const { model, view, source } = await this.getModelViewBase(param); - const baseModel = await Model.getBaseModelSQL({ + const { model, view, source } = await this.getModelViewBase(context, param); + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -38,6 +40,7 @@ export class BulkDataAliasService { // todo: Integrate with filterArrJson bulkDataUpdateAll async bulkDataInsert( + context: NcContext, param: PathParams & { body: any; cookie: any; @@ -47,7 +50,7 @@ export class BulkDataAliasService { raw?: boolean; }, ) { - return await this.executeBulkOperation({ + return await this.executeBulkOperation(context, { ...param, operation: 'bulkInsert', options: [ @@ -64,13 +67,14 @@ export class BulkDataAliasService { // todo: Integrate with filterArrJson bulkDataUpdateAll async bulkDataUpdate( + context: NcContext, param: PathParams & { body: any; cookie: any; raw?: boolean; }, ) { - return await this.executeBulkOperation({ + return await this.executeBulkOperation(context, { ...param, operation: 'bulkUpdate', options: [param.body, { cookie: param.cookie, raw: param.raw }], @@ -79,13 +83,14 @@ export class BulkDataAliasService { // todo: Integrate with filterArrJson bulkDataUpdateAll async bulkDataUpdateAll( + context: NcContext, param: PathParams & { body: any; cookie: any; query: any; }, ) { - return await this.executeBulkOperation({ + return await this.executeBulkOperation(context, { ...param, operation: 'bulkUpdateAll', options: [param.query, param.body, { cookie: param.cookie }], @@ -93,12 +98,13 @@ export class BulkDataAliasService { } async bulkDataDelete( + context: NcContext, param: PathParams & { body: any; cookie: any; }, ) { - return await this.executeBulkOperation({ + return await this.executeBulkOperation(context, { ...param, operation: 'bulkDelete', options: [param.body, { cookie: param.cookie }], @@ -107,11 +113,12 @@ export class BulkDataAliasService { // todo: Integrate with filterArrJson bulkDataDeleteAll async bulkDataDeleteAll( + context: NcContext, param: PathParams & { query: any; }, ) { - return await this.executeBulkOperation({ + return await this.executeBulkOperation(context, { ...param, operation: 'bulkDeleteAll', options: [param.query], diff --git a/packages/nocodb/src/services/calendar-datas.service.ts b/packages/nocodb/src/services/calendar-datas.service.ts index f547d3c958..71426ffc62 100644 --- a/packages/nocodb/src/services/calendar-datas.service.ts +++ b/packages/nocodb/src/services/calendar-datas.service.ts @@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { ViewTypes } from 'nocodb-sdk'; import dayjs from 'dayjs'; import type { CalendarRangeType, FilterType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import { CalendarRange, Model, View } from '~/models'; import { NcError } from '~/helpers/catchError'; import { DatasService } from '~/services/datas.service'; @@ -12,12 +13,15 @@ export class CalendarDatasService { constructor(protected datasService: DatasService) {} - async getCalendarDataList(param: { - viewId: string; - query: any; - from_date: string; - to_date: string; - }) { + async getCalendarDataList( + context: NcContext, + param: { + viewId: string; + query: any; + from_date: string; + to_date: string; + }, + ) { const { viewId, query, from_date, to_date } = param; if (!from_date || !to_date) @@ -27,18 +31,18 @@ export class CalendarDatasService { NcError.badRequest('Date range should not exceed 42 days'); } - const view = await View.get(viewId); + const view = await View.get(context, viewId); if (!view) NcError.viewNotFound(viewId); if (view.type !== ViewTypes.CALENDAR) NcError.badRequest('View is not a calendar view'); - const calendarRange = await CalendarRange.read(view.id); + const calendarRange = await CalendarRange.read(context, view.id); if (!calendarRange?.ranges?.length) NcError.badRequest('No ranges found'); - const filterArr = await this.buildFilterArr({ + const filterArr = await this.buildFilterArr(context, { viewId, from_date, to_date, @@ -49,11 +53,11 @@ export class CalendarDatasService { ...(query.filterArrJson ? JSON.parse(query.filterArrJson) : []), ]); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view.fk_model_id, }); - return await this.datasService.dataList({ + return await this.datasService.dataList(context, { ...param, ...query, viewName: view.id, @@ -63,15 +67,18 @@ export class CalendarDatasService { }); } - async getPublicCalendarRecordCount(param: { - password: string; - query: any; - sharedViewUuid: string; - from_date: string; - to_date: string; - }) { + async getPublicCalendarRecordCount( + context: NcContext, + param: { + password: string; + query: any; + sharedViewUuid: string; + from_date: string; + to_date: string; + }, + ) { const { sharedViewUuid, password, query = {} } = param; - const view = await View.getByUUID(sharedViewUuid); + const view = await View.getByUUID(context, sharedViewUuid); if (!view) NcError.viewNotFound(sharedViewUuid); if (view.type !== ViewTypes.CALENDAR) { @@ -82,7 +89,7 @@ export class CalendarDatasService { return NcError.invalidSharedViewPassword(); } - return this.getCalendarRecordCount({ + return this.getCalendarRecordCount(context, { viewId: view.id, query, from_date: param.from_date, @@ -90,15 +97,18 @@ export class CalendarDatasService { }); } - async getPublicCalendarDataList(param: { - password: string; - query: any; - sharedViewUuid: string; - from_date: string; - to_date: string; - }) { + async getPublicCalendarDataList( + context: NcContext, + param: { + password: string; + query: any; + sharedViewUuid: string; + from_date: string; + to_date: string; + }, + ) { const { sharedViewUuid, password, query = {} } = param; - const view = await View.getByUUID(sharedViewUuid); + const view = await View.getByUUID(context, sharedViewUuid); if (!view) NcError.viewNotFound(sharedViewUuid); if (view.type !== ViewTypes.CALENDAR) { @@ -109,7 +119,7 @@ export class CalendarDatasService { return NcError.invalidSharedViewPassword(); } - return this.getCalendarDataList({ + return this.getCalendarDataList(context, { viewId: view.id, query, from_date: param.from_date, @@ -117,12 +127,15 @@ export class CalendarDatasService { }); } - async getCalendarRecordCount(param: { - viewId: string; - query: any; - from_date: string; - to_date: string; - }) { + async getCalendarRecordCount( + context: NcContext, + param: { + viewId: string; + query: any; + from_date: string; + to_date: string; + }, + ) { const { viewId, query, from_date, to_date } = param; if (!from_date || !to_date) @@ -132,18 +145,18 @@ export class CalendarDatasService { NcError.badRequest('Date range should not exceed 395 days'); } - const view = await View.get(viewId); + const view = await View.get(context, viewId); if (!view) NcError.viewNotFound(viewId); if (view.type !== ViewTypes.CALENDAR) NcError.badRequest('View is not a calendar view'); - const ranges = await CalendarRange.read(view.id); + const ranges = await CalendarRange.read(context, view.id); if (!ranges?.ranges.length) NcError.badRequest('No ranges found'); - const filterArr = await this.buildFilterArr({ + const filterArr = await this.buildFilterArr(context, { viewId, from_date, to_date, @@ -154,11 +167,11 @@ export class CalendarDatasService { ...(query.filterArrJson ? JSON.parse(query.filterArrJson) : []), ]); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view.fk_model_id, }); - const data = await this.datasService.dataList({ + const data = await this.datasService.dataList(context, { ...param, baseName: model.base_id, tableName: model.id, @@ -169,7 +182,7 @@ export class CalendarDatasService { const dates: Array = []; - const columns = await model.getColumns(); + const columns = await model.getColumns(context); ranges?.ranges?.forEach((range: CalendarRangeType) => { const fromCol = columns.find( @@ -191,16 +204,19 @@ export class CalendarDatasService { }; } - async buildFilterArr({ - viewId, - from_date, - to_date, - }: { - viewId: string; - from_date: string; - to_date: string; - }): Promise> { - const calendarRange = await CalendarRange.read(viewId); + async buildFilterArr( + context: NcContext, + { + viewId, + from_date, + to_date, + }: { + viewId: string; + from_date: string; + to_date: string; + }, + ): Promise> { + const calendarRange = await CalendarRange.read(context, viewId); if (!calendarRange?.ranges?.length) NcError.badRequest('No ranges found'); const filterArr: FilterType = { diff --git a/packages/nocodb/src/services/calendars.service.ts b/packages/nocodb/src/services/calendars.service.ts index 7bdccbc139..0e8a5de173 100644 --- a/packages/nocodb/src/services/calendars.service.ts +++ b/packages/nocodb/src/services/calendars.service.ts @@ -5,7 +5,7 @@ import type { UserType, ViewCreateReqType, } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -17,24 +17,28 @@ import { CacheScope } from '~/utils/globals'; export class CalendarsService { constructor(private readonly appHooksService: AppHooksService) {} - async calendarViewGet(param: { calendarViewId: string }) { - return await CalendarView.get(param.calendarViewId); + async calendarViewGet(context: NcContext, param: { calendarViewId: string }) { + return await CalendarView.get(context, param.calendarViewId); } - async calendarViewCreate(param: { - tableId: string; - calendar: ViewCreateReqType; - user: UserType; - req: NcRequest; - }) { + async calendarViewCreate( + context: NcContext, + param: { + tableId: string; + calendar: ViewCreateReqType; + user: UserType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewCreateReq', param.calendar, ); - const model = await Model.get(param.tableId); + const model = await Model.get(context, param.tableId); const { id } = await View.insertMetaOnly( + context, { ...param.calendar, fk_model_id: param.tableId, @@ -45,7 +49,7 @@ export class CalendarsService { model, ); - const view = await View.get(id); + const view = await View.get(context, id); await NocoCache.appendToList( CacheScope.VIEW, @@ -64,23 +68,30 @@ export class CalendarsService { return view; } - async calendarViewUpdate(param: { - calendarViewId: string; - calendar: CalendarUpdateReqType; - req: NcRequest; - }) { + async calendarViewUpdate( + context: NcContext, + param: { + calendarViewId: string; + calendar: CalendarUpdateReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/CalendarUpdateReq', param.calendar, ); - const view = await View.get(param.calendarViewId); + const view = await View.get(context, param.calendarViewId); if (!view) { NcError.viewNotFound(param.calendarViewId); } - const res = await CalendarView.update(param.calendarViewId, param.calendar); + const res = await CalendarView.update( + context, + param.calendarViewId, + param.calendar, + ); this.appHooksService.emit(AppEvents.VIEW_UPDATE, { view, diff --git a/packages/nocodb/src/services/columns.service.ts b/packages/nocodb/src/services/columns.service.ts index 99c20bc5ba..a5b30d0d37 100644 --- a/packages/nocodb/src/services/columns.service.ts +++ b/packages/nocodb/src/services/columns.service.ts @@ -24,7 +24,7 @@ import type { Base, LinkToAnotherRecordColumn } from '~/models'; import type CustomKnex from '~/db/CustomKnex'; import type SqlClient from '~/db/sql-client/lib/SqlClient'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { BaseUser, CalendarRange, @@ -80,10 +80,45 @@ interface ReusableParams { } async function reuseOrSave( - tp: keyof ReusableParams, + tp: 'table', params: ReusableParams, get: () => Promise, -) { +): Promise; +async function reuseOrSave( + tp: 'source', + params: ReusableParams, + get: () => Promise, +): Promise; +async function reuseOrSave( + tp: 'base', + params: ReusableParams, + get: () => Promise, +): Promise; +async function reuseOrSave( + tp: 'dbDriver', + params: ReusableParams, + get: () => Promise, +): Promise; +async function reuseOrSave( + tp: 'sqlClient', + params: ReusableParams, + get: () => Promise, +): Promise>; +async function reuseOrSave( + tp: 'sqlMgr', + params: ReusableParams, + get: () => Promise, +): Promise; +async function reuseOrSave( + tp: 'baseModel', + params: ReusableParams, + get: () => Promise, +): Promise; +async function reuseOrSave( + tp: string, + params: ReusableParams, + get: () => Promise, +): Promise { if (params[tp]) { return params[tp]; } @@ -102,7 +137,10 @@ export class ColumnsService { protected readonly appHooksService: AppHooksService, ) {} - async updateFormulas(args: { oldColumn: any; colBody: any }) { + async updateFormulas( + context: NcContext, + args: { oldColumn: any; colBody: any }, + ) { const { oldColumn, colBody } = args; // update formula if column name or title is changed @@ -124,7 +162,7 @@ export class ColumnsService { ); // update the formula_raw and set parsed_tree to null to reparse the formula - await FormulaColumn.update(oldColumn.id, { + await FormulaColumn.update(context, oldColumn.id, { formula_raw: new_formula_raw, parsed_tree: null, }); @@ -133,27 +171,30 @@ export class ColumnsService { } } - async columnUpdate(param: { - req?: any; - columnId: string; - column: ColumnReqType & { colOptions?: any }; - cookie?: any; - user: UserType; - reuse?: ReusableParams; - }) { + async columnUpdate( + context: NcContext, + param: { + req?: any; + columnId: string; + column: ColumnReqType & { colOptions?: any }; + cookie?: any; + user: UserType; + reuse?: ReusableParams; + }, + ) { const reuse = param.reuse || {}; const { cookie } = param; - const column = await Column.get({ colId: param.columnId }); + const column = await Column.get(context, { colId: param.columnId }); const table = await reuseOrSave('table', reuse, async () => - Model.getWithInfo({ + Model.getWithInfo(context, { id: column.fk_model_id, }), ); const source = await reuseOrSave('source', reuse, async () => - Source.get(table.source_id), + Source.get(context, table.source_id), ); const sqlClient = await reuseOrSave('sqlClient', reuse, async () => @@ -181,7 +222,7 @@ export class ColumnsService { let colName = param.column.column_name.slice(0, mxColumnLength - 5); let suffix = 1; while ( - !(await Column.checkTitleAvailable({ + !(await Column.checkTitleAvailable(context, { column_name: colName, fk_model_id: column.fk_model_id, exclude_id: param.columnId, @@ -212,7 +253,7 @@ export class ColumnsService { !isVirtualCol(param.column) && !isCreatedOrLastModifiedTimeCol(param.column) && !isCreatedOrLastModifiedByCol(param.column) && - !(await Column.checkTitleAvailable({ + !(await Column.checkTitleAvailable(context, { column_name: param.column.column_name, fk_model_id: column.fk_model_id, exclude_id: param.columnId, @@ -221,7 +262,7 @@ export class ColumnsService { NcError.badRequest('Duplicate column name'); } if ( - !(await Column.checkAliasAvailable({ + !(await Column.checkAliasAvailable(context, { title: param.column.title, fk_model_id: column.fk_model_id, exclude_id: param.columnId, @@ -253,7 +294,7 @@ export class ColumnsService { ) { if (column.uidt === colBody.uidt) { if ([UITypes.QrCode, UITypes.Barcode].includes(column.uidt)) { - await Column.update(column.id, { + await Column.update(context, column.id, { ...column, ...colBody, } as Column); @@ -266,17 +307,17 @@ export class ColumnsService { formula: colBody.formula || colBody.formula_raw, columns: table.columns, column, - clientOrSqlUi: source.type, + clientOrSqlUi: source.type as any, getMeta: async (modelId) => { - const model = await Model.get(modelId); - await model.getColumns(); + const model = await Model.get(context, modelId); + await model.getColumns(context); return model; }, }); try { const baseModel = await reuseOrSave('baseModel', reuse, async () => - Model.getBaseModelSQL({ + Model.getBaseModelSQL(context, { id: table.id, dbDriver: await reuseOrSave('dbDriver', reuse, async () => NcConnectionMgrv2.get(source), @@ -299,14 +340,14 @@ export class ColumnsService { NcError.badRequest('Invalid Formula'); } - await Column.update(column.id, { + await Column.update(context, column.id, { // title: colBody.title, ...column, ...colBody, }); } else { if (colBody.title !== column.title) { - await Column.updateAlias(param.columnId, { + await Column.updateAlias(context, param.columnId, { title: colBody.title, }); } @@ -316,7 +357,7 @@ export class ColumnsService { column.uidt, ) ) { - await Column.updateMeta({ + await Column.updateMeta(context, { colId: param.columnId, meta: colBody.meta, }); @@ -324,7 +365,7 @@ export class ColumnsService { if (isLinksOrLTAR(column)) { if ('meta' in colBody) { - await Column.updateMeta({ + await Column.updateMeta(context, { colId: param.columnId, meta: { ...column.meta, @@ -350,7 +391,7 @@ export class ColumnsService { (colBody as Column).colOptions .fk_target_view_id === null ) { - await Column.updateTargetView({ + await Column.updateTargetView(context, { colId: param.columnId, fk_target_view_id: ( colBody as Column @@ -368,9 +409,10 @@ export class ColumnsService { colBody.column_order?.view_id ) { const viewColumn = ( - await View.getColumns(colBody.column_order.view_id) + await View.getColumns(context, colBody.column_order.view_id) ).find((col) => col.fk_column_id === column.id); await View.updateColumn( + context, colBody.column_order.view_id, viewColumn.id, { @@ -380,7 +422,7 @@ export class ColumnsService { } } - await this.updateRollupOrLookup(colBody, column); + await this.updateRollupOrLookup(context, colBody, column); } else { NcError.notImplemented(`Updating ${colBody.uidt} => ${colBody.uidt}`); } @@ -405,7 +447,7 @@ export class ColumnsService { ].includes(colBody.uidt) ) { // allow updating of title only - await Column.update(param.columnId, { + await Column.update(context, param.columnId, { ...column, title: colBody.title, }); @@ -415,7 +457,7 @@ export class ColumnsService { colBody = await getColumnPropsFromUIDT(colBody, source); const baseModel = await reuseOrSave('baseModel', reuse, async () => - Model.getBaseModelSQL({ + Model.getBaseModelSQL(context, { id: table.id, dbDriver: await reuseOrSave('dbDriver', reuse, async () => NcConnectionMgrv2.get(source), @@ -488,17 +530,19 @@ export class ColumnsService { ); const baseModel = await reuseOrSave('baseModel', reuse, async () => - Model.getBaseModelSQL({ + Model.getBaseModelSQL(context, { id: table.id, dbDriver: dbDriver, }), ); const data = await baseModel.execAndParse( - baseModel.dbDriver.raw('SELECT DISTINCT ?? FROM ??', [ - column.column_name, - baseModel.getTnPath(table.table_name), - ]), + baseModel.dbDriver + .raw('SELECT DISTINCT ?? FROM ??', [ + column.column_name, + baseModel.getTnPath(table.table_name), + ]) + .toQuery(), null, { raw: true, @@ -848,13 +892,13 @@ export class ColumnsService { }; const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ + ProjectMgrv2.getSqlMgr(context, { id: source.base_id, }), ); await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); - await Column.update(param.columnId, { + await Column.update(context, param.columnId, { ...column, }); } @@ -1057,7 +1101,7 @@ export class ColumnsService { }; // update formula with new column name - await this.updateFormulas({ + await this.updateFormulas(context, { oldColumn: column, colBody, }); @@ -1071,17 +1115,17 @@ export class ColumnsService { }; const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ id: source.base_id }), + ProjectMgrv2.getSqlMgr(context, { id: source.base_id }), ); await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); - await Column.update(param.columnId, { + await Column.update(context, param.columnId, { ...colBody, }); } else if (colBody.uidt === UITypes.User) { // handle default value for user column if (colBody.cdf) { - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(context, { base_id: source.base_id, include_ws_deleted: false, }); @@ -1116,7 +1160,7 @@ export class ColumnsService { column.meta?.is_multi === true ) { const baseModel = await reuseOrSave('baseModel', reuse, async () => - Model.getBaseModelSQL({ + Model.getBaseModelSQL(context, { id: table.id, dbDriver: await reuseOrSave('dbDriver', reuse, async () => NcConnectionMgrv2.get(source), @@ -1192,7 +1236,7 @@ export class ColumnsService { }; // update formula with new column name - await this.updateFormulas({ + await this.updateFormulas(context, { oldColumn: column, colBody, }); @@ -1206,11 +1250,11 @@ export class ColumnsService { }; const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ id: source.base_id }), + ProjectMgrv2.getSqlMgr(context, { id: source.base_id }), ); await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); - await Column.update(param.columnId, { + await Column.update(context, param.columnId, { ...colBody, }); } else if ( @@ -1218,7 +1262,7 @@ export class ColumnsService { ) { // email/text to user const baseModel = await reuseOrSave('baseModel', reuse, async () => - Model.getBaseModelSQL({ + Model.getBaseModelSQL(context, { id: table.id, dbDriver: await reuseOrSave('dbDriver', reuse, async () => NcConnectionMgrv2.get(source), @@ -1226,7 +1270,7 @@ export class ColumnsService { }), ); - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(context, { base_id: column.base_id, }); @@ -1308,7 +1352,7 @@ export class ColumnsService { }; // update formula with new column name - await this.updateFormulas({ + await this.updateFormulas(context, { oldColumn: column, colBody, }); @@ -1322,11 +1366,11 @@ export class ColumnsService { }; const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ id: source.base_id }), + ProjectMgrv2.getSqlMgr(context, { id: source.base_id }), ); await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); - await Column.update(param.columnId, { + await Column.update(context, param.columnId, { ...colBody, }); } else { @@ -1336,7 +1380,7 @@ export class ColumnsService { if ([UITypes.SingleLineText, UITypes.Email].includes(colBody.uidt)) { // user to email/text const baseModel = await reuseOrSave('baseModel', reuse, async () => - Model.getBaseModelSQL({ + Model.getBaseModelSQL(context, { id: table.id, dbDriver: await reuseOrSave('dbDriver', reuse, async () => NcConnectionMgrv2.get(source), @@ -1344,7 +1388,7 @@ export class ColumnsService { }), ); - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(context, { base_id: column.base_id, }); @@ -1383,7 +1427,7 @@ export class ColumnsService { }; // update formula with new column name - await this.updateFormulas({ + await this.updateFormulas(context, { oldColumn: column, colBody, }); @@ -1397,11 +1441,11 @@ export class ColumnsService { }; const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ id: source.base_id }), + ProjectMgrv2.getSqlMgr(context, { id: source.base_id }), ); await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); - await Column.update(param.columnId, { + await Column.update(context, param.columnId, { ...colBody, }); } else { @@ -1429,7 +1473,7 @@ export class ColumnsService { }; // update formula with new column name - await this.updateFormulas({ + await this.updateFormulas(context, { oldColumn: column, colBody, }); @@ -1443,16 +1487,16 @@ export class ColumnsService { }; const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ id: source.base_id }), + ProjectMgrv2.getSqlMgr(context, { id: source.base_id }), ); await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); - await Column.update(param.columnId, { + await Column.update(context, param.columnId, { ...colBody, }); } - await table.getColumns(); + await table.getColumns(context); this.appHooksService.emit(AppEvents.COLUMN_UPDATE, { table, @@ -1465,38 +1509,41 @@ export class ColumnsService { return table; } - async columnGet(param: { columnId: string }) { - return Column.get({ colId: param.columnId }); + async columnGet(context: NcContext, param: { columnId: string }) { + return Column.get(context, { colId: param.columnId }); } - async columnSetAsPrimary(param: { columnId: string }) { - const column = await Column.get({ colId: param.columnId }); - return Model.updatePrimaryColumn(column.fk_model_id, column.id); + async columnSetAsPrimary(context: NcContext, param: { columnId: string }) { + const column = await Column.get(context, { colId: param.columnId }); + return Model.updatePrimaryColumn(context, column.fk_model_id, column.id); } - async columnAdd(param: { - req: NcRequest; - tableId: string; - column: ColumnReqType; - user: UserType; - reuse?: ReusableParams; - }) { + async columnAdd( + context: NcContext, + param: { + req: NcRequest; + tableId: string; + column: ColumnReqType; + user: UserType; + reuse?: ReusableParams; + }, + ) { validatePayload('swagger.json#/components/schemas/ColumnReq', param.column); const reuse = param.reuse || {}; const table = await reuseOrSave('table', reuse, async () => - Model.getWithInfo({ + Model.getWithInfo(context, { id: param.tableId, }), ); const source = await reuseOrSave('source', reuse, async () => - Source.get(table.source_id), + Source.get(context, table.source_id), ); const base = await reuseOrSave('base', reuse, async () => - source.getProject(), + source.getProject(context), ); if (param.column.title || param.column.column_name) { @@ -1525,7 +1572,7 @@ export class ColumnsService { let colName = param.column.column_name.slice(0, mxColumnLength - 5); let suffix = 1; while ( - !(await Column.checkTitleAvailable({ + !(await Column.checkTitleAvailable(context, { column_name: colName, fk_model_id: param.tableId, })) @@ -1554,7 +1601,7 @@ export class ColumnsService { if ( !isVirtualCol(param.column) && - !(await Column.checkTitleAvailable({ + !(await Column.checkTitleAvailable(context, { column_name: param.column.column_name, fk_model_id: param.tableId, })) @@ -1562,7 +1609,7 @@ export class ColumnsService { NcError.badRequest('Duplicate column name'); } if ( - !(await Column.checkAliasAvailable({ + !(await Column.checkAliasAvailable(context, { title: param.column.title || param.column.column_name, fk_model_id: param.tableId, })) @@ -1580,9 +1627,9 @@ export class ColumnsService { switch (colBody.uidt) { case UITypes.Rollup: { - await validateRollupPayload(param.column); + await validateRollupPayload(context, param.column); - await Column.insert({ + await Column.insert(context, { ...colBody, fk_model_id: table.id, }); @@ -1590,9 +1637,9 @@ export class ColumnsService { break; case UITypes.Lookup: { - await validateLookupPayload(param.column); + await validateLookupPayload(context, param.column); - await Column.insert({ + await Column.insert(context, { ...colBody, fk_model_id: table.id, }); @@ -1601,7 +1648,7 @@ export class ColumnsService { case UITypes.Links: case UITypes.LinkToAnotherRecord: - await this.createLTARColumn({ + await this.createLTARColumn(context, { ...param, source, base, @@ -1621,13 +1668,13 @@ export class ColumnsService { break; case UITypes.QrCode: - await Column.insert({ + await Column.insert(context, { ...colBody, fk_model_id: table.id, }); break; case UITypes.Barcode: - await Column.insert({ + await Column.insert(context, { ...colBody, fk_model_id: table.id, }); @@ -1646,17 +1693,17 @@ export class ColumnsService { colOptions: colBody, }, columns: table.columns, - clientOrSqlUi: source.type, + clientOrSqlUi: source.type as any, getMeta: async (modelId) => { - const model = await Model.get(modelId); - await model.getColumns(); + const model = await Model.get(context, modelId); + await model.getColumns(context); return model; }, }); try { const baseModel = await reuseOrSave('baseModel', reuse, async () => - Model.getBaseModelSQL({ + Model.getBaseModelSQL(context, { id: table.id, dbDriver: await reuseOrSave('dbDriver', reuse, async () => NcConnectionMgrv2.get(source), @@ -1678,7 +1725,7 @@ export class ColumnsService { NcError.badRequest('Invalid Formula'); } - await Column.insert({ + await Column.insert(context, { ...colBody, fk_model_id: table.id, }); @@ -1690,7 +1737,7 @@ export class ColumnsService { case UITypes.LastModifiedBy: { let columnName: string; - const columns = await table.getColumns(); + const columns = await table.getColumns(context); // check if column already exists, then just create a new column in meta // else create a new column in meta and db const existingColumn = columns.find( @@ -1753,14 +1800,14 @@ export class ColumnsService { ], }; const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ id: source.base_id }), + ProjectMgrv2.getSqlMgr(context, { id: source.base_id }), ); await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); } const title = getUniqueColumnAliasName(table.columns, columnTitle); - await Column.insert({ + await Column.insert(context, { ...colBody, title, system: 1, @@ -1770,7 +1817,7 @@ export class ColumnsService { } else { columnName = existingColumn.column_name; } - await Column.insert({ + await Column.insert(context, { ...colBody, fk_model_id: table.id, column_name: null, @@ -1920,7 +1967,7 @@ export class ColumnsService { if (colBody.uidt === UITypes.User) { // handle default value for user column if (colBody.cdf) { - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(context, { base_id: base.id, include_ws_deleted: false, }); @@ -1972,7 +2019,7 @@ export class ColumnsService { NcConnectionMgrv2.getSqlClient(source), ); const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ id: source.base_id }), + ProjectMgrv2.getSqlMgr(context, { id: source.base_id }), ); await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); @@ -1995,7 +2042,7 @@ export class ColumnsService { Object.assign(colBody, insertedColumnMeta); } - await Column.insert({ + await Column.insert(context, { ...colBody, fk_model_id: table.id, }); @@ -2003,7 +2050,7 @@ export class ColumnsService { break; } - await table.getColumns(); + await table.getColumns(context); this.appHooksService.emit(AppEvents.COLUMN_CREATE, { table, @@ -2020,6 +2067,7 @@ export class ColumnsService { } async columnDelete( + context: NcContext, param: { req?: any; columnId: string; @@ -2031,7 +2079,7 @@ export class ColumnsService { ) { const reuse = param.reuse || {}; - const column = await Column.get({ colId: param.columnId }, ncMeta); + const column = await Column.get(context, { colId: param.columnId }, ncMeta); if (column.system && !param.forceDeleteSystem) { NcError.badRequest( @@ -2043,6 +2091,7 @@ export class ColumnsService { const table = await reuseOrSave('table', reuse, async () => Model.getWithInfo( + context, { id: column.fk_model_id, }, @@ -2050,11 +2099,11 @@ export class ColumnsService { ), ); const source = await reuseOrSave('source', reuse, async () => - Source.get(table.source_id, false, ncMeta), + Source.get(context, table.source_id, false, ncMeta), ); const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ id: source.base_id }, ncMeta), + ProjectMgrv2.getSqlMgr(context, { id: source.base_id }, ncMeta), ); /** @@ -2074,14 +2123,14 @@ export class ColumnsService { case UITypes.QrCode: case UITypes.Barcode: case UITypes.Formula: - await Column.delete(param.columnId, ncMeta); + await Column.delete(context, param.columnId, ncMeta); break; // on deleting created/last modified columns, keep the column in table and delete the column from meta case UITypes.CreatedTime: case UITypes.LastModifiedTime: case UITypes.CreatedBy: case UITypes.LastModifiedBy: { - await Column.delete(param.columnId, ncMeta); + await Column.delete(context, param.columnId, ncMeta); break; } // Since Links is just an extended version of LTAR, we can use the same logic @@ -2089,18 +2138,27 @@ export class ColumnsService { case UITypes.LinkToAnotherRecord: { const relationColOpt = - await column.getColOptions(ncMeta); - const childColumn = await relationColOpt.getChildColumn(ncMeta); - const childTable = await childColumn.getModel(ncMeta); + await column.getColOptions( + context, + ncMeta, + ); + const childColumn = await relationColOpt.getChildColumn( + context, + ncMeta, + ); + const childTable = await childColumn.getModel(context, ncMeta); - const parentColumn = await relationColOpt.getParentColumn(ncMeta); - const parentTable = await parentColumn.getModel(ncMeta); + const parentColumn = await relationColOpt.getParentColumn( + context, + ncMeta, + ); + const parentTable = await parentColumn.getModel(context, ncMeta); switch (relationColOpt.type) { case 'bt': case 'hm': { - await this.deleteHmOrBtRelation({ + await this.deleteHmOrBtRelation(context, { relationColOpt, source, childColumn, @@ -2114,7 +2172,7 @@ export class ColumnsService { break; case 'oo': { - await this.deleteOoRelation({ + await this.deleteOoRelation(context, { relationColOpt, source, childColumn, @@ -2128,15 +2186,21 @@ export class ColumnsService { break; case 'mm': { - const mmTable = await relationColOpt.getMMModel(ncMeta); + const mmTable = await relationColOpt.getMMModel( + context, + ncMeta, + ); const mmParentCol = await relationColOpt.getMMParentColumn( + context, ncMeta, ); const mmChildCol = await relationColOpt.getMMChildColumn( + context, ncMeta, ); await this.deleteHmOrBtRelation( + context, { relationColOpt: null, parentColumn: parentColumn, @@ -2152,6 +2216,7 @@ export class ColumnsService { ); await this.deleteHmOrBtRelation( + context, { relationColOpt: null, parentColumn: childColumn, @@ -2166,13 +2231,16 @@ export class ColumnsService { true, ); const columnsInRelatedTable: Column[] = await relationColOpt - .getRelatedTable(ncMeta) - .then((m) => m.getColumns(ncMeta)); + .getRelatedTable(context, ncMeta) + .then((m) => m.getColumns(context, ncMeta)); for (const c of columnsInRelatedTable) { if (!isLinksOrLTAR(c.uidt)) continue; const colOpt = - await c.getColOptions(ncMeta); + await c.getColOptions( + context, + ncMeta, + ); if ( colOpt.type === 'mm' && colOpt.fk_parent_column_id === childColumn.id && @@ -2183,62 +2251,75 @@ export class ColumnsService { colOpt.fk_mm_child_column_id === relationColOpt.fk_mm_parent_column_id ) { - await Column.delete(c.id, ncMeta); + await Column.delete(context, c.id, ncMeta); break; } } - await Column.delete(relationColOpt.fk_column_id, ncMeta); + await Column.delete( + context, + relationColOpt.fk_column_id, + ncMeta, + ); if (mmTable) { // delete bt columns in m2m table - await mmTable.getColumns(ncMeta); + await mmTable.getColumns(context, ncMeta); for (const c of mmTable.columns) { if (!isLinksOrLTAR(c.uidt)) continue; const colOpt = - await c.getColOptions(ncMeta); + await c.getColOptions( + context, + ncMeta, + ); if (colOpt.type === 'bt') { - await Column.delete(c.id, ncMeta); + await Column.delete(context, c.id, ncMeta); } } } // delete hm columns in parent table - await parentTable.getColumns(ncMeta); + await parentTable.getColumns(context, ncMeta); for (const c of parentTable.columns) { if (!isLinksOrLTAR(c.uidt)) continue; const colOpt = - await c.getColOptions(ncMeta); + await c.getColOptions( + context, + ncMeta, + ); if ( colOpt.fk_related_model_id === relationColOpt.fk_mm_model_id ) { - await Column.delete(c.id, ncMeta); + await Column.delete(context, c.id, ncMeta); } } // delete hm columns in child table - await childTable.getColumns(ncMeta); + await childTable.getColumns(context, ncMeta); for (const c of childTable.columns) { if (!isLinksOrLTAR(c.uidt)) continue; const colOpt = - await c.getColOptions(ncMeta); + await c.getColOptions( + context, + ncMeta, + ); if ( colOpt.fk_related_model_id === relationColOpt.fk_mm_model_id ) { - await Column.delete(c.id, ncMeta); + await Column.delete(context, c.id, ncMeta); } } if (mmTable) { // retrieve columns in m2m table again - await mmTable.getColumns(ncMeta); + await mmTable.getColumns(context, ncMeta); // ignore deleting table if it has more than 2 columns // the expected 2 columns would be table1_id & table2_id if (mmTable.columns.length === 2) { (mmTable as any).tn = mmTable.table_name; await sqlMgr.sqlOpPlus(source, 'tableDelete', mmTable); - await mmTable.delete(ncMeta); + await mmTable.delete(context, ncMeta); } } } @@ -2255,7 +2336,9 @@ export class ColumnsService { break; } case UITypes.SingleSelect: { - if (await KanbanView.IsColumnBeingUsedAsGroupingField(column.id)) { + if ( + await KanbanView.IsColumnBeingUsedAsGroupingField(context, column.id) + ) { NcError.badRequest( `The column '${column.column_name}' is being used in Kanban View. Please delete Kanban View first.`, ); @@ -2266,7 +2349,11 @@ export class ColumnsService { case UITypes.Date: { if ( [UITypes.DateTime, UITypes.Date].includes(column.uidt) && - (await CalendarRange.IsColumnBeingUsedAsRange(column.id, ncMeta)) + (await CalendarRange.IsColumnBeingUsedAsRange( + context, + column.id, + ncMeta, + )) ) { NcError.badRequest( `The column '${column.column_name}' is being used in Calendar View. Please delete Calendar View first.`, @@ -2300,14 +2387,15 @@ export class ColumnsService { await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); - await Column.delete(param.columnId, ncMeta); + await Column.delete(context, param.columnId, ncMeta); } } - await table.getColumns(ncMeta); + await table.getColumns(context, ncMeta); const displayValueColumn = mapDefaultDisplayValue(table.columns); if (displayValueColumn) { await Model.updatePrimaryColumn( + context, displayValueColumn.fk_model_id, displayValueColumn.id, ncMeta, @@ -2326,6 +2414,7 @@ export class ColumnsService { } deleteHmOrBtRelation = async ( + context: NcContext, { relationColOpt, source, @@ -2357,11 +2446,14 @@ export class ColumnsService { if (!relationColOpt) { foreignKeyName = ( ( - await childTable.getColumns(ncMeta).then(async (cols) => { + await childTable.getColumns(context, ncMeta).then(async (cols) => { for (const col of cols) { if (col.uidt === UITypes.LinkToAnotherRecord) { const colOptions = - await col.getColOptions(ncMeta); + await col.getColOptions( + context, + ncMeta, + ); if (colOptions.fk_related_model_id === parentTable.id) { return { colOptions }; } @@ -2393,27 +2485,31 @@ export class ColumnsService { if (!relationColOpt) return; const columnsInRelatedTable: Column[] = await relationColOpt - .getRelatedTable(ncMeta) - .then((m) => m.getColumns(ncMeta)); + .getRelatedTable(context, ncMeta) + .then((m) => m.getColumns(context, ncMeta)); const relType = relationColOpt.type === 'bt' ? 'hm' : 'bt'; for (const c of columnsInRelatedTable) { if (c.uidt !== UITypes.LinkToAnotherRecord) continue; - const colOpt = await c.getColOptions(ncMeta); + const colOpt = await c.getColOptions( + context, + ncMeta, + ); if ( colOpt.fk_parent_column_id === parentColumn.id && colOpt.fk_child_column_id === childColumn.id && colOpt.type === relType ) { - await Column.delete(c.id, ncMeta); + await Column.delete(context, c.id, ncMeta); break; } } // delete virtual columns - await Column.delete(relationColOpt.fk_column_id, ncMeta); + await Column.delete(context, relationColOpt.fk_column_id, ncMeta); if (!ignoreFkDelete) { const cTable = await Model.getWithInfo( + context, { id: childTable.id, }, @@ -2466,11 +2562,12 @@ export class ColumnsService { await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); // delete foreign key column - await Column.delete(childColumn.id, ncMeta); + await Column.delete(context, childColumn.id, ncMeta); } }; deleteOoRelation = async ( + context: NcContext, { relationColOpt, source, @@ -2502,11 +2599,14 @@ export class ColumnsService { if (!relationColOpt) { foreignKeyName = ( ( - await childTable.getColumns(ncMeta).then(async (cols) => { + await childTable.getColumns(context, ncMeta).then(async (cols) => { for (const col of cols) { if (col.uidt === UITypes.LinkToAnotherRecord) { const colOptions = - await col.getColOptions(ncMeta); + await col.getColOptions( + context, + ncMeta, + ); if (colOptions.fk_related_model_id === parentTable.id) { return { colOptions }; } @@ -2538,27 +2638,31 @@ export class ColumnsService { if (!relationColOpt) return; const columnsInRelatedTable: Column[] = await relationColOpt - .getRelatedTable(ncMeta) - .then((m) => m.getColumns(ncMeta)); + .getRelatedTable(context, ncMeta) + .then((m) => m.getColumns(context, ncMeta)); const relType = RelationTypes.ONE_TO_ONE; for (const c of columnsInRelatedTable) { if (c.uidt !== UITypes.LinkToAnotherRecord) continue; - const colOpt = await c.getColOptions(ncMeta); + const colOpt = await c.getColOptions( + context, + ncMeta, + ); if ( colOpt.fk_parent_column_id === parentColumn.id && colOpt.fk_child_column_id === childColumn.id && colOpt.type === relType ) { - await Column.delete(c.id, ncMeta); + await Column.delete(context, c.id, ncMeta); break; } } // delete virtual columns - await Column.delete(relationColOpt.fk_column_id, ncMeta); + await Column.delete(context, relationColOpt.fk_column_id, ncMeta); if (!ignoreFkDelete) { const cTable = await Model.getWithInfo( + context, { id: childTable.id, }, @@ -2612,40 +2716,43 @@ export class ColumnsService { await sqlMgr.sqlOpPlus(source, 'tableUpdate', tableUpdateBody); // delete foreign key column - await Column.delete(childColumn.id, ncMeta); + await Column.delete(context, childColumn.id, ncMeta); } }; - async createLTARColumn(param: { - tableId: string; - column: ColumnReqType; - source: Source; - base: Base; - reuse?: ReusableParams; - colExtra?: any; - }) { + async createLTARColumn( + context: NcContext, + param: { + tableId: string; + column: ColumnReqType; + source: Source; + base: Base; + reuse?: ReusableParams; + colExtra?: any; + }, + ) { validateParams(['parentId', 'childId', 'type'], param.column); const reuse = param.reuse ?? {}; // get parent and child models - const parent = await Model.getWithInfo({ + const parent = await Model.getWithInfo(context, { id: (param.column as LinkToAnotherColumnReqType).parentId, }); - const child = await Model.getWithInfo({ + const child = await Model.getWithInfo(context, { id: (param.column as LinkToAnotherColumnReqType).childId, }); let childColumn: Column; const childView: View | null = (param.column as LinkToAnotherColumnReqType) ?.childViewId - ? await View.getByTitleOrId({ + ? await View.getByTitleOrId(context, { fk_model_id: child.id, titleOrId: (param.column as LinkToAnotherColumnReqType).childViewId, }) : null; const sqlMgr = await reuseOrSave('sqlMgr', reuse, async () => - ProjectMgrv2.getSqlMgr({ + ProjectMgrv2.getSqlMgr(context, { id: param.source.base_id, }), ); @@ -2664,7 +2771,7 @@ export class ColumnsService { ) { // populate fk column name const fkColName = getUniqueColumnName( - await child.getColumns(), + await child.getColumns(context), `${parent.table_name}_id`, ); @@ -2704,13 +2811,13 @@ export class ColumnsService { await sqlMgr.sqlOpPlus(param.source, 'tableUpdate', tableUpdateBody); - const { id } = await Column.insert({ + const { id } = await Column.insert(context, { ...newColumn, uidt: UITypes.ForeignKey, fk_model_id: child.id, }); - childColumn = await Column.get({ colId: id }); + childColumn = await Column.get(context, { colId: id }); // ignore relation creation if virtual if (!(param.column as LinkToAnotherColumnReqType).virtual) { @@ -2734,7 +2841,7 @@ export class ColumnsService { param.source.type === 'pg' || (param.column as LinkToAnotherColumnReqType).virtual ) { - await this.createColumnIndex({ + await this.createColumnIndex(context, { column: new Column({ ...newColumn, fk_model_id: child.id, @@ -2746,6 +2853,7 @@ export class ColumnsService { } await createHmAndBtColumn( + context, child, parent, childColumn, @@ -2762,7 +2870,7 @@ export class ColumnsService { } else if ((param.column as LinkToAnotherColumnReqType).type === 'oo') { // populate fk column name const fkColName = getUniqueColumnName( - await child.getColumns(), + await child.getColumns(context), `${parent.table_name}_id`, ); @@ -2803,13 +2911,13 @@ export class ColumnsService { await sqlMgr.sqlOpPlus(param.source, 'tableUpdate', tableUpdateBody); - const { id } = await Column.insert({ + const { id } = await Column.insert(context, { ...newColumn, uidt: UITypes.ForeignKey, fk_model_id: child.id, }); - childColumn = await Column.get({ colId: id }); + childColumn = await Column.get(context, { colId: id }); // ignore relation creation if virtual if (!(param.column as LinkToAnotherColumnReqType).virtual) { @@ -2833,7 +2941,7 @@ export class ColumnsService { param.source.type === 'pg' || (param.column as LinkToAnotherColumnReqType).virtual ) { - await this.createColumnIndex({ + await this.createColumnIndex(context, { column: new Column({ ...newColumn, fk_model_id: child.id, @@ -2844,6 +2952,7 @@ export class ColumnsService { } } await createOOColumn( + context, child, parent, childColumn, @@ -2907,13 +3016,18 @@ export class ColumnsService { columns: associateTableCols, }); - const assocModel = await Model.insert(param.base.id, param.source.id, { - table_name: aTn, - title: aTnAlias, - // todo: sanitize - mm: true, - columns: associateTableCols, - }); + const assocModel = await Model.insert( + context, + param.base.id, + param.source.id, + { + table_name: aTn, + title: aTnAlias, + // todo: sanitize + mm: true, + columns: associateTableCols, + }, + ); let foreignKeyName1; let foreignKeyName2; @@ -2944,14 +3058,15 @@ export class ColumnsService { await sqlMgr.sqlOpPlus(param.source, 'relationCreate', rel1Args); await sqlMgr.sqlOpPlus(param.source, 'relationCreate', rel2Args); } - const parentCol = (await assocModel.getColumns())?.find( + const parentCol = (await assocModel.getColumns(context))?.find( (c) => c.column_name === parentCn, ); - const childCol = (await assocModel.getColumns())?.find( + const childCol = (await assocModel.getColumns(context))?.find( (c) => c.column_name === childCn, ); await createHmAndBtColumn( + context, assocModel, child, childCol, @@ -2966,6 +3081,7 @@ export class ColumnsService { param.colExtra, ); await createHmAndBtColumn( + context, assocModel, parent, parentCol, @@ -2980,9 +3096,9 @@ export class ColumnsService { param.colExtra, ); - await Column.insert({ + await Column.insert(context, { title: getUniqueColumnAliasName( - await child.getColumns(), + await child.getColumns(context), pluralize(parent.title), ), uidt: isLinks ? UITypes.Links : UITypes.LinkToAnotherRecord, @@ -3008,9 +3124,9 @@ export class ColumnsService { // if self referencing treat it as system field to hide from ui system: parent.id === child.id, }); - await Column.insert({ + await Column.insert(context, { title: getUniqueColumnAliasName( - await parent.getColumns(), + await parent.getColumns(context), param.column.title ?? pluralize(child.title), ), @@ -3041,7 +3157,7 @@ export class ColumnsService { // todo: create index for virtual relations as well // create index for foreign key in pg if (param.source.type === 'pg') { - await this.createColumnIndex({ + await this.createColumnIndex(context, { column: new Column({ ...associateTableCols[0], fk_model_id: assocModel.id, @@ -3049,7 +3165,7 @@ export class ColumnsService { source: param.source, sqlMgr, }); - await this.createColumnIndex({ + await this.createColumnIndex(context, { column: new Column({ ...associateTableCols[1], fk_model_id: assocModel.id, @@ -3061,22 +3177,25 @@ export class ColumnsService { } } - async createColumnIndex({ - column, - sqlMgr, - source, - indexName = null, - nonUnique = true, - }: { - column: Column; - sqlMgr: SqlMgrv2; - source: Source; - indexName?: string; - nonUnique?: boolean; - }) { + async createColumnIndex( + context: NcContext, + { + column, + sqlMgr, + source, + indexName = null, + nonUnique = true, + }: { + column: Column; + sqlMgr: SqlMgrv2; + source: Source; + indexName?: string; + nonUnique?: boolean; + }, + ) { // TODO: implement for snowflake (right now create index does not work with identifier quoting in snowflake - bug?) if (source.type === 'snowflake') return; - const model = await column.getModel(); + const model = await column.getModel(context); const indexArgs = { columns: [column.column_name], tn: model.table_name, @@ -3086,7 +3205,11 @@ export class ColumnsService { await sqlMgr.sqlOpPlus(source, 'indexCreate', indexArgs); } - async updateRollupOrLookup(colBody: any, column: Column) { + async updateRollupOrLookup( + context: NcContext, + colBody: any, + column: Column, + ) { // Validate rollup or lookup payload before proceeding with the update if ( UITypes.Lookup === column.uidt && @@ -3096,8 +3219,8 @@ export class ColumnsService { ]) ) { // Perform additional validation for lookup payload - await validateLookupPayload(colBody, column.id); - await Column.update(column.id, colBody); + await validateLookupPayload(context, colBody, column.id); + await Column.update(context, column.id, colBody); } else if ( UITypes.Rollup === column.uidt && validateRequiredField(colBody, [ @@ -3107,13 +3230,13 @@ export class ColumnsService { ]) ) { // Perform additional validation for rollup payload - await validateRollupPayload(colBody); - await Column.update(column.id, colBody); + await validateRollupPayload(context, colBody); + await Column.update(context, column.id, colBody); } } - async columnsHash(tableId: string) { - const table = await Model.getWithInfo({ + async columnsHash(context: NcContext, tableId: string) { + const table = await Model.getWithInfo(context, { id: tableId, }); @@ -3121,7 +3244,7 @@ export class ColumnsService { NcError.tableNotFound(tableId); } - const columns = await table.getColumns(); + const columns = await table.getColumns(context); return { hash: hash(columns), @@ -3129,6 +3252,7 @@ export class ColumnsService { } async columnBulk( + context: NcContext, tableId: string, params: { hash: string; @@ -3141,7 +3265,7 @@ export class ColumnsService { ) { // TODO validatePayload - const table = await Model.getWithInfo({ + const table = await Model.getWithInfo(context, { id: tableId, }); @@ -3149,7 +3273,7 @@ export class ColumnsService { NcError.tableNotFound(tableId); } - const columns = await table.getColumns(); + const columns = await table.getColumns(context); if (hash(columns) !== params.hash) { NcError.badRequest( @@ -3157,13 +3281,13 @@ export class ColumnsService { ); } - const source = await Source.get(table.source_id); + const source = await Source.get(context, table.source_id); if (!source) { NcError.sourceNotFound(table.source_id); } - const base = await source.getProject(); + const base = await source.getProject(context); if (!base) { NcError.baseNotFound(source.base_id); @@ -3171,8 +3295,10 @@ export class ColumnsService { const dbDriver = await NcConnectionMgrv2.get(source); const sqlClient = await NcConnectionMgrv2.getSqlClient(source); - const sqlMgr = await ProjectMgrv2.getSqlMgr({ id: source.base_id }); - const baseModel = await Model.getBaseModelSQL({ + const sqlMgr = await ProjectMgrv2.getSqlMgr(context, { + id: source.base_id, + }); + const baseModel = await Model.getBaseModelSQL(context, { id: table.id, dbDriver: dbDriver, }); @@ -3220,7 +3346,7 @@ export class ColumnsService { if (op.op === 'add') { try { - const tableMeta = await this.columnAdd({ + const tableMeta = await this.columnAdd(context, { tableId, column: column as ColumnReqType, req, @@ -3228,7 +3354,7 @@ export class ColumnsService { reuse, }); - await this.postColumnAdd(column as ColumnReqType, tableMeta); + await this.postColumnAdd(context, column as ColumnReqType, tableMeta); } catch (e) { failedOps.push({ ...op, @@ -3237,7 +3363,7 @@ export class ColumnsService { } } else if (op.op === 'update') { try { - await this.columnUpdate({ + await this.columnUpdate(context, { columnId: op.column.id, column: column as ColumnReqType, req, @@ -3245,7 +3371,7 @@ export class ColumnsService { reuse, }); - await this.postColumnUpdate(column as ColumnReqType); + await this.postColumnUpdate(context, column as ColumnReqType); } catch (e) { failedOps.push({ ...op, @@ -3254,7 +3380,7 @@ export class ColumnsService { } } else if (op.op === 'delete') { try { - await this.columnDelete({ + await this.columnDelete(context, { columnId: op.column.id, req, user: req.user, @@ -3273,11 +3399,18 @@ export class ColumnsService { }; } - protected async postColumnAdd(_columnBody: ColumnReqType, _tableMeta: Model) { + protected async postColumnAdd( + _context: NcContext, + _columnBody: ColumnReqType, + _tableMeta: Model, + ) { // placeholder for post column add hook } - protected async postColumnUpdate(_columnBody: ColumnReqType) { + protected async postColumnUpdate( + _context: NcContext, + _columnBody: ColumnReqType, + ) { // placeholder for post column update hook } } diff --git a/packages/nocodb/src/services/command-palette.service.ts b/packages/nocodb/src/services/command-palette.service.ts index 3f2565d5dd..43ff595d05 100644 --- a/packages/nocodb/src/services/command-palette.service.ts +++ b/packages/nocodb/src/services/command-palette.service.ts @@ -32,6 +32,7 @@ export class CommandPaletteService { viewList.push( ...( (await this.tablesService.xcVisibilityMetaGet( + { workspace_id: base.fk_workspace_id, base_id: base.id }, base.id, null, false, diff --git a/packages/nocodb/src/services/comments.service.ts b/packages/nocodb/src/services/comments.service.ts index 8626ff6d1f..8c130add5f 100644 --- a/packages/nocodb/src/services/comments.service.ts +++ b/packages/nocodb/src/services/comments.service.ts @@ -6,7 +6,7 @@ import type { CommentUpdateReqType, UserType, } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { NcError } from '~/helpers/catchError'; import { validatePayload } from '~/helpers'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; @@ -16,23 +16,28 @@ import Comment from '~/models/Comment'; export class CommentsService { constructor(protected readonly appHooksService: AppHooksService) {} - async commentRow(param: { - body: CommentReqType; - user: UserType; - req: NcRequest; - }) { + async commentRow( + context: NcContext, + param: { + body: CommentReqType; + user: UserType; + req: NcRequest; + }, + ) { validatePayload('swagger.json#/components/schemas/CommentReq', param.body); - const res = await Comment.insert({ + const res = await Comment.insert(context, { ...param.body, created_by: param.user?.id, created_by_email: param.user?.email, }); - const model = await Model.getByIdOrName({ id: param.body.fk_model_id }); + const model = await Model.getByIdOrName(context, { + id: param.body.fk_model_id, + }); this.appHooksService.emit(AppEvents.COMMENT_CREATE, { - base: await Base.getByTitleOrId(model.base_id), + base: await Base.getByTitleOrId(context, model.base_id), model: model, user: param.user, comment: res, @@ -43,23 +48,28 @@ export class CommentsService { return res; } - async commentDelete(param: { - commentId: string; - user: UserType; - req: NcRequest; - }) { - const comment = await Comment.get(param.commentId); + async commentDelete( + context: NcContext, + param: { + commentId: string; + user: UserType; + req: NcRequest; + }, + ) { + const comment = await Comment.get(context, param.commentId); if (comment.created_by !== param.user.id || comment.is_deleted) { NcError.unauthorized('Unauthorized access'); } - const res = await Comment.delete(param.commentId); + const res = await Comment.delete(context, param.commentId); - const model = await Model.getByIdOrName({ id: comment.fk_model_id }); + const model = await Model.getByIdOrName(context, { + id: comment.fk_model_id, + }); this.appHooksService.emit(AppEvents.COMMENT_DELETE, { - base: await Base.getByTitleOrId(model.base_id), + base: await Base.getByTitleOrId(context, model.base_id), model: model, user: param.user, comment: comment, @@ -69,47 +79,58 @@ export class CommentsService { return res; } - async commentList(param: { - query: { - row_id: string; - fk_model_id: string; - }; - }) { - return await Comment.list(param.query); + async commentList( + context: NcContext, + param: { + query: { + row_id: string; + fk_model_id: string; + }; + }, + ) { + return await Comment.list(context, param.query); } - async commentsCount(param: { fk_model_id: string; ids: string[] }) { - return await Comment.commentsCount({ + async commentsCount( + context: NcContext, + param: { fk_model_id: string; ids: string[] }, + ) { + return await Comment.commentsCount(context, { fk_model_id: param.fk_model_id as string, ids: param.ids as string[], }); } - async commentUpdate(param: { - commentId: string; - user: UserType; - body: CommentUpdateReqType; - req: NcRequest; - }) { + async commentUpdate( + context: NcContext, + param: { + commentId: string; + user: UserType; + body: CommentUpdateReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/CommentUpdateReq', param.body, ); - const comment = await Comment.get(param.commentId); + const comment = await Comment.get(context, param.commentId); if (comment.created_by !== param.user.id || comment.is_deleted) { NcError.unauthorized('Unauthorized access'); } - const res = await Comment.update(param.commentId, { + const res = await Comment.update(context, param.commentId, { comment: param.body.comment, }); - const model = await Model.getByIdOrName({ id: param.body.fk_model_id }); + const model = await Model.getByIdOrName(context, { + id: param.body.fk_model_id, + }); this.appHooksService.emit(AppEvents.COMMENT_UPDATE, { - base: await Base.getByTitleOrId(model.base_id), + base: await Base.getByTitleOrId(context, model.base_id), model: model, user: param.user, comment: { diff --git a/packages/nocodb/src/services/data-alias-nested.service.ts b/packages/nocodb/src/services/data-alias-nested.service.ts index 91ebd75b79..1537f6b03e 100644 --- a/packages/nocodb/src/services/data-alias-nested.service.ts +++ b/packages/nocodb/src/services/data-alias-nested.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { UITypes } from 'nocodb-sdk'; import type { PathParams } from '~/helpers/dataHelpers'; +import type { NcContext } from '~/interface/config'; import { NcError } from '~/helpers/catchError'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; import { @@ -14,25 +15,26 @@ import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; export class DataAliasNestedService { // todo: handle case where the given column is not ltar async mmList( + context: NcContext, param: PathParams & { query: any; columnName: string; rowId: string; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); if (!model) NcError.tableNotFound(param.tableName); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await getColumnByIdOrName(param.columnName, model); + const column = await getColumnByIdOrName(context, param.columnName, model); if ( !column || @@ -62,23 +64,24 @@ export class DataAliasNestedService { } async mmExcludedList( + context: NcContext, param: PathParams & { query: any; columnName: string; rowId: string; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); if (!model) NcError.tableNotFound(param.tableName); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await getColumnByIdOrName(param.columnName, model); + const column = await getColumnByIdOrName(context, param.columnName, model); const data = await baseModel.getMmChildrenExcludedList( { @@ -103,25 +106,26 @@ export class DataAliasNestedService { } async hmExcludedList( + context: NcContext, param: PathParams & { query: any; columnName: string; rowId: string; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); if (!model) NcError.tableNotFound(param.tableName); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await getColumnByIdOrName(param.columnName, model); + const column = await getColumnByIdOrName(context, param.columnName, model); const data = await baseModel.getHmChildrenExcludedList( { @@ -146,24 +150,25 @@ export class DataAliasNestedService { } async btExcludedList( + context: NcContext, param: PathParams & { query: any; columnName: string; rowId: string; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); if (!model) NcError.tableNotFound(param.tableName); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await getColumnByIdOrName(param.columnName, model); + const column = await getColumnByIdOrName(context, param.columnName, model); const data = await baseModel.getBtChildrenExcludedList( { @@ -187,24 +192,25 @@ export class DataAliasNestedService { }); } async ooExcludedList( + context: NcContext, param: PathParams & { query: any; columnName: string; rowId: string; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); if (!model) NcError.notFound('Table not found'); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await getColumnByIdOrName(param.columnName, model); + const column = await getColumnByIdOrName(context, param.columnName, model); const data = await baseModel.getExcludedOneToOneChildrenList( { @@ -230,25 +236,26 @@ export class DataAliasNestedService { // todo: handle case where the given column is not ltar async hmList( + context: NcContext, param: PathParams & { query: any; columnName: string; rowId: string; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); if (!model) NcError.tableNotFound(param.tableName); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await getColumnByIdOrName(param.columnName, model); + const column = await getColumnByIdOrName(context, param.columnName, model); if (![UITypes.LinkToAnotherRecord, UITypes.Links].includes(column.uidt)) NcError.badRequest('Column is not LTAR'); @@ -276,6 +283,7 @@ export class DataAliasNestedService { } async relationDataRemove( + context: NcContext, param: PathParams & { columnName: string; rowId: string; @@ -283,18 +291,18 @@ export class DataAliasNestedService { cookie: any; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); if (!model) NcError.tableNotFound(param.tableName); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await getColumnByIdOrName(param.columnName, model); + const column = await getColumnByIdOrName(context, param.columnName, model); await baseModel.removeChild({ colId: column.id, @@ -308,6 +316,7 @@ export class DataAliasNestedService { // todo: Give proper error message when reference row is already related and handle duplicate ref row id in hm async relationDataAdd( + context: NcContext, param: PathParams & { columnName: string; rowId: string; @@ -315,18 +324,18 @@ export class DataAliasNestedService { cookie: any; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); if (!model) NcError.tableNotFound(param.tableName); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await getColumnByIdOrName(param.columnName, model); + const column = await getColumnByIdOrName(context, param.columnName, model); await baseModel.addChild({ colId: column.id, childId: param.refRowId, diff --git a/packages/nocodb/src/services/data-table.service.ts b/packages/nocodb/src/services/data-table.service.ts index f136c5891c..1be2d59667 100644 --- a/packages/nocodb/src/services/data-table.service.ts +++ b/packages/nocodb/src/services/data-table.service.ts @@ -3,6 +3,7 @@ import { isLinksOrLTAR, RelationTypes } from 'nocodb-sdk'; import { nocoExecute } from 'nc-help'; import { validatePayload } from 'src/helpers'; import type { LinkToAnotherRecordColumn } from '~/models'; +import type { NcContext } from '~/interface/config'; import { Column, Model, Source, View } from '~/models'; import { DatasService } from '~/services/datas.service'; import { NcError } from '~/helpers/catchError'; @@ -14,34 +15,40 @@ import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; export class DataTableService { constructor(private datasService: DatasService) {} - async dataList(param: { - baseId?: string; - modelId: string; - query: any; - viewId?: string; - ignorePagination?: boolean; - }) { + async dataList( + context: NcContext, + param: { + baseId?: string; + modelId: string; + query: any; + viewId?: string; + ignorePagination?: boolean; + }, + ) { const { modelId, viewId, baseId, ...rest } = param; - const { model, view } = await this.getModelAndView({ + const { model, view } = await this.getModelAndView(context, { modelId, viewId, baseId, }); - return await this.datasService.dataList({ ...rest, model, view }); + return await this.datasService.dataList(context, { ...rest, model, view }); } - async dataRead(param: { - baseId?: string; - modelId: string; - rowId: string; - viewId?: string; - query: any; - }) { - const { model, view } = await this.getModelAndView(param); + async dataRead( + context: NcContext, + param: { + baseId?: string; + modelId: string; + rowId: string; + viewId?: string; + query: any; + }, + ) { + const { model, view } = await this.getModelAndView(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -58,17 +65,20 @@ export class DataTableService { return row; } - async dataInsert(param: { - baseId?: string; - viewId?: string; - modelId: string; - body: any; - cookie: any; - }) { - const { model, view } = await this.getModelAndView(param); - const source = await Source.get(model.source_id); - - const baseModel = await Model.getBaseModelSQL({ + async dataInsert( + context: NcContext, + param: { + baseId?: string; + viewId?: string; + modelId: string; + body: any; + cookie: any; + }, + ) { + const { model, view } = await this.getModelAndView(context, param); + const source = await Source.get(context, model.source_id); + + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -87,21 +97,24 @@ export class DataTableService { return Array.isArray(param.body) ? result : result[0]; } - async dataUpdate(param: { - baseId?: string; - modelId: string; - viewId?: string; - // rowId: string; - body: any; - cookie: any; - }) { - const { model, view } = await this.getModelAndView(param); + async dataUpdate( + context: NcContext, + param: { + baseId?: string; + modelId: string; + viewId?: string; + // rowId: string; + body: any; + cookie: any; + }, + ) { + const { model, view } = await this.getModelAndView(context, param); - await this.checkForDuplicateRow({ rows: param.body, model }); + await this.checkForDuplicateRow(context, { rows: param.body, model }); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -116,23 +129,26 @@ export class DataTableService { }, ); - return this.extractIdObj({ body: param.body, model }); + return this.extractIdObj(context, { body: param.body, model }); } - async dataDelete(param: { - baseId?: string; - modelId: string; - viewId?: string; - // rowId: string; - cookie: any; - body: any; - }) { - const { model, view } = await this.getModelAndView(param); - - await this.checkForDuplicateRow({ rows: param.body, model }); - - const source = await Source.get(model.source_id); - const baseModel = await Model.getBaseModelSQL({ + async dataDelete( + context: NcContext, + param: { + baseId?: string; + modelId: string; + viewId?: string; + // rowId: string; + cookie: any; + body: any; + }, + ) { + const { model, view } = await this.getModelAndView(context, param); + + await this.checkForDuplicateRow(context, { rows: param.body, model }); + + const source = await Source.get(context, model.source_id); + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -147,20 +163,23 @@ export class DataTableService { }, ); - return this.extractIdObj({ body: param.body, model }); + return this.extractIdObj(context, { body: param.body, model }); } - async dataCount(param: { - baseId?: string; - viewId?: string; - modelId: string; - query: any; - }) { - const { model, view } = await this.getModelAndView(param); + async dataCount( + context: NcContext, + param: { + baseId?: string; + viewId?: string; + modelId: string; + query: any; + }, + ) { + const { model, view } = await this.getModelAndView(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -176,12 +195,15 @@ export class DataTableService { return { count }; } - private async getModelAndView(param: { - baseId?: string; - viewId?: string; - modelId: string; - }) { - const model = await Model.get(param.modelId); + private async getModelAndView( + context: NcContext, + param: { + baseId?: string; + viewId?: string; + modelId: string; + }, + ) { + const model = await Model.get(context, param.modelId); if (!model) { NcError.tableNotFound(param.modelId); @@ -194,7 +216,7 @@ export class DataTableService { let view: View; if (param.viewId) { - view = await View.get(param.viewId); + view = await View.get(context, param.viewId); if (!view || (view.fk_model_id && view.fk_model_id !== param.modelId)) { NcError.viewNotFound(param.viewId); } @@ -203,15 +225,18 @@ export class DataTableService { return { model, view }; } - private async extractIdObj({ - model, - body, - }: { - body: Record | Record[]; - model: Model; - }) { + private async extractIdObj( + context: NcContext, + { + model, + body, + }: { + body: Record | Record[]; + model: Model; + }, + ) { const pkColumns = await model - .getColumns() + .getColumns(context) .then((cols) => cols.filter((col) => col.pk)); const result = (Array.isArray(body) ? body : [body]).map((row) => { @@ -224,18 +249,21 @@ export class DataTableService { return Array.isArray(body) ? result : result[0]; } - private async checkForDuplicateRow({ - rows, - model, - }: { - rows: any[] | any; - model: Model; - }) { + private async checkForDuplicateRow( + context: NcContext, + { + rows, + model, + }: { + rows: any[] | any; + model: Model; + }, + ) { if (!rows || !Array.isArray(rows) || rows.length === 1) { return; } - await model.getColumns(); + await model.getColumns(context); const keys = new Set(); @@ -261,17 +289,20 @@ export class DataTableService { } } - async nestedDataList(param: { - viewId: string; - modelId: string; - query: any; - rowId: string | string[] | number | number[]; - columnId: string; - }) { - const { model, view } = await this.getModelAndView(param); - const source = await Source.get(model.source_id); - - const baseModel = await Model.getBaseModelSQL({ + async nestedDataList( + context: NcContext, + param: { + viewId: string; + modelId: string; + query: any; + rowId: string | string[] | number | number[]; + columnId: string; + }, + ) { + const { model, view } = await this.getModelAndView(context, param); + const source = await Source.get(context, model.source_id); + + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -281,13 +312,15 @@ export class DataTableService { NcError.recordNotFound(`${param.rowId}`); } - const column = await this.getColumn(param); + const column = await this.getColumn(context, param); - const colOptions = await column.getColOptions(); + const colOptions = await column.getColOptions( + context, + ); - const relatedModel = await colOptions.getRelatedTable(); + const relatedModel = await colOptions.getRelatedTable(context); - const { ast, dependencyFields } = await getAst({ + const { ast, dependencyFields } = await getAst(context, { model: relatedModel, query: param.query, extractOnlyPrimaries: !(param.query?.f || param.query?.fields), @@ -353,8 +386,11 @@ export class DataTableService { }); } - private async getColumn(param: { modelId: string; columnId: string }) { - const column = await Column.get({ colId: param.columnId }); + private async getColumn( + context: NcContext, + param: { modelId: string; columnId: string }, + ) { + const column = await Column.get(context, { colId: param.columnId }); if (!column) NcError.fieldNotFound(param.columnId); @@ -365,34 +401,37 @@ export class DataTableService { return column; } - async nestedLink(param: { - cookie: any; - viewId: string; - modelId: string; - columnId: string; - query: any; - refRowIds: - | string - | string[] - | number - | number[] - | Record - | Record[]; - rowId: string; - }) { + async nestedLink( + context: NcContext, + param: { + cookie: any; + viewId: string; + modelId: string; + columnId: string; + query: any; + refRowIds: + | string + | string[] + | number + | number[] + | Record + | Record[]; + rowId: string; + }, + ) { this.validateIds(param.refRowIds); - const { model, view } = await this.getModelAndView(param); + const { model, view } = await this.getModelAndView(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await this.getColumn(param); + const column = await this.getColumn(context, param); await baseModel.addLinks({ colId: column.id, @@ -406,29 +445,32 @@ export class DataTableService { return true; } - async nestedUnlink(param: { - cookie: any; - viewId: string; - modelId: string; - columnId: string; - query: any; - refRowIds: string | string[] | number | number[] | Record; - rowId: string; - }) { + async nestedUnlink( + context: NcContext, + param: { + cookie: any; + viewId: string; + modelId: string; + columnId: string; + query: any; + refRowIds: string | string[] | number | number[] | Record; + rowId: string; + }, + ) { this.validateIds(param.refRowIds); - const { model, view } = await this.getModelAndView(param); + const { model, view } = await this.getModelAndView(context, param); if (!model) NcError.tableNotFound(param.modelId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const column = await this.getColumn(param); + const column = await this.getColumn(context, param); await baseModel.removeLinks({ colId: column.id, @@ -443,19 +485,22 @@ export class DataTableService { } // todo: naming & optimizing - async nestedListCopyPasteOrDeleteAll(param: { - cookie: any; - viewId: string; - modelId: string; - columnId: string; - query: any; - data: { - operation: 'copy' | 'paste' | 'deleteAll'; - rowId: string; + async nestedListCopyPasteOrDeleteAll( + context: NcContext, + param: { + cookie: any; + viewId: string; + modelId: string; columnId: string; - fk_related_model_id: string; - }[]; - }) { + query: any; + data: { + operation: 'copy' | 'paste' | 'deleteAll'; + rowId: string; + columnId: string; + fk_related_model_id: string; + }[]; + }, + ) { validatePayload( 'swagger.json#/components/schemas/nestedListCopyPasteOrDeleteAllReq', param.data, @@ -487,11 +532,11 @@ export class DataTableService { ); } - const { model, view } = await this.getModelAndView(param); + const { model, view } = await this.getModelAndView(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -519,14 +564,16 @@ export class DataTableService { } } - const column = await this.getColumn(param); - const colOptions = await column.getColOptions(); - const relatedModel = await colOptions.getRelatedTable(); - await relatedModel.getColumns(); + const column = await this.getColumn(context, param); + const colOptions = await column.getColOptions( + context, + ); + const relatedModel = await colOptions.getRelatedTable(context); + await relatedModel.getColumns(context); if (colOptions.type !== RelationTypes.MANY_TO_MANY) return; - const { dependencyFields } = await getAst({ + const { dependencyFields } = await getAst(context, { model: relatedModel, query: param.query, extractOnlyPrimaries: !(param.query?.f || param.query?.fields), diff --git a/packages/nocodb/src/services/datas.service.ts b/packages/nocodb/src/services/datas.service.ts index 4bdd8a6285..4edacba80d 100644 --- a/packages/nocodb/src/services/datas.service.ts +++ b/packages/nocodb/src/services/datas.service.ts @@ -5,9 +5,9 @@ import papaparse from 'papaparse'; import { nocoExecute } from 'nc-help'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; import type { PathParams } from '~/helpers/dataHelpers'; +import type { NcContext } from '~/interface/config'; import type { Filter } from '~/models'; -import { getDbRows } from '~/helpers/dataHelpers'; -import { getViewAndModelByAliasOrId } from '~/helpers/dataHelpers'; +import { getDbRows, getViewAndModelByAliasOrId } from '~/helpers/dataHelpers'; import { Base, Column, Model, Source, View } from '~/models'; import { NcBaseError, NcError } from '~/helpers/catchError'; import getAst from '~/helpers/getAst'; @@ -21,6 +21,7 @@ export class DatasService { constructor() {} async dataList( + context: NcContext, param: (PathParams | { view?: View; model: Model }) & { query: any; disableOptimization?: boolean; @@ -33,13 +34,14 @@ export class DatasService { if (!model) { const modelAndView = await getViewAndModelByAliasOrId( + context, param as PathParams, ); model = modelAndView.model; view = modelAndView.view; } - return await this.getDataList({ + return await this.getDataList(context, { model, view, query: param.query, @@ -49,22 +51,26 @@ export class DatasService { }); } - async dataFindOne(param: PathParams & { query: any }) { - const { model, view } = await getViewAndModelByAliasOrId(param); - return await this.getFindOne({ model, view, query: param.query }); + async dataFindOne(context: NcContext, param: PathParams & { query: any }) { + const { model, view } = await getViewAndModelByAliasOrId(context, param); + return await this.getFindOne(context, { model, view, query: param.query }); } - async dataGroupBy(param: PathParams & { query: any }) { - const { model, view } = await getViewAndModelByAliasOrId(param); - return await this.getDataGroupBy({ model, view, query: param.query }); + async dataGroupBy(context: NcContext, param: PathParams & { query: any }) { + const { model, view } = await getViewAndModelByAliasOrId(context, param); + return await this.getDataGroupBy(context, { + model, + view, + query: param.query, + }); } - async dataCount(param: PathParams & { query: any }) { - const { model, view } = await getViewAndModelByAliasOrId(param); + async dataCount(context: NcContext, param: PathParams & { query: any }) { + const { model, view } = await getViewAndModelByAliasOrId(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -81,17 +87,18 @@ export class DatasService { } async dataInsert( + context: NcContext, param: PathParams & { body: unknown; cookie: any; disableOptimization?: boolean; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -101,6 +108,7 @@ export class DatasService { } async dataUpdate( + context: NcContext, param: PathParams & { body: unknown; cookie: any; @@ -108,10 +116,10 @@ export class DatasService { disableOptimization?: boolean; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); - const source = await Source.get(model.source_id); + const { model, view } = await getViewAndModelByAliasOrId(context, param); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -126,10 +134,13 @@ export class DatasService { ); } - async dataDelete(param: PathParams & { rowId: string; cookie: any }) { - const { model, view } = await getViewAndModelByAliasOrId(param); - const source = await Source.get(model.source_id); - const baseModel = await Model.getBaseModelSQL({ + async dataDelete( + context: NcContext, + param: PathParams & { rowId: string; cookie: any }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(context, param); + const source = await Source.get(context, model.source_id); + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -147,17 +158,20 @@ export class DatasService { return await baseModel.delByPk(param.rowId, null, param.cookie); } - async getDataList(param: { - model: Model; - view?: View; - query: any; - baseModel?: BaseModelSqlv2; - throwErrorIfInvalidParams?: boolean; - ignoreViewFilterAndSort?: boolean; - ignorePagination?: boolean; - limitOverride?: number; - customConditions?: Filter[]; - }) { + async getDataList( + context: NcContext, + param: { + model: Model; + view?: View; + query: any; + baseModel?: BaseModelSqlv2; + throwErrorIfInvalidParams?: boolean; + ignoreViewFilterAndSort?: boolean; + ignorePagination?: boolean; + limitOverride?: number; + customConditions?: Filter[]; + }, + ) { const { model, view: view, @@ -165,17 +179,17 @@ export class DatasService { ignoreViewFilterAndSort = false, } = param; - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); const baseModel = param.baseModel || - (await Model.getBaseModelSQL({ + (await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), })); - const { ast, dependencyFields } = await getAst({ + const { ast, dependencyFields } = await getAst(context, { model, query, view: view, @@ -225,12 +239,15 @@ export class DatasService { }); } - async getFindOne(param: { model: Model; view: View; query: any }) { + async getFindOne( + context: NcContext, + param: { model: Model; view: View; query: any }, + ) { const { model, view, query = {} } = param; - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -244,7 +261,7 @@ export class DatasService { args.sortArr = JSON.parse(args.sortArrJson); } catch (e) {} - const { ast, dependencyFields } = await getAst({ + const { ast, dependencyFields } = await getAst(context, { model, query: args, view, @@ -254,12 +271,15 @@ export class DatasService { return data ? await nocoExecute(ast, data, {}, dependencyFields) : {}; } - async getDataGroupBy(param: { model: Model; view: View; query?: any }) { + async getDataGroupBy( + context: NcContext, + param: { model: Model; view: View; query?: any }, + ) { const { model, view, query = {} } = param; - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -284,6 +304,7 @@ export class DatasService { } async dataRead( + context: NcContext, param: PathParams & { query: any; rowId: string; @@ -291,11 +312,11 @@ export class DatasService { getHiddenColumn?: boolean; }, ) { - const { model, view } = await getViewAndModelByAliasOrId(param); + const { model, view } = await getViewAndModelByAliasOrId(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -311,12 +332,15 @@ export class DatasService { return row; } - async dataExist(param: PathParams & { rowId: string; query: any }) { - const { model, view } = await getViewAndModelByAliasOrId(param); + async dataExist( + context: NcContext, + param: PathParams & { rowId: string; query: any }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(context, param); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -326,9 +350,12 @@ export class DatasService { } // todo: Handle the error case where view doesnt belong to model - async groupedDataList(param: PathParams & { query: any; columnId: string }) { - const { model, view } = await getViewAndModelByAliasOrId(param); - const groupedData = await this.getGroupedDataList({ + async groupedDataList( + context: NcContext, + param: PathParams & { query: any; columnId: string }, + ) { + const { model, view } = await getViewAndModelByAliasOrId(context, param); + const groupedData = await this.getGroupedDataList(context, { model, view, query: param.query, @@ -337,23 +364,30 @@ export class DatasService { return groupedData; } - async getGroupedDataList(param: { - model; - view: View; - query: any; - columnId: string; - }) { + async getGroupedDataList( + context: NcContext, + param: { + model; + view: View; + query: any; + columnId: string; + }, + ) { const { model, view, query = {} } = param; - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { ast, dependencyFields } = await getAst({ model, query, view }); + const { ast, dependencyFields } = await getAst(context, { + model, + query, + view, + }); const listArgs: any = { ...dependencyFields }; try { @@ -393,35 +427,41 @@ export class DatasService { return data; } - async dataListByViewId(param: { viewId: string; query: any }) { - const view = await View.get(param.viewId); + async dataListByViewId( + context: NcContext, + param: { viewId: string; query: any }, + ) { + const view = await View.get(context, param.viewId); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id || param.viewId, }); if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); - return await this.getDataList({ model, view, query: param.query }); + return await this.getDataList(context, { model, view, query: param.query }); } - async mmList(param: { - viewId: string; - colId: string; - query: any; - rowId: string; - }) { - const view = await View.get(param.viewId); + async mmList( + context: NcContext, + param: { + viewId: string; + colId: string; + query: any; + rowId: string; + }, + ) { + const view = await View.get(context, param.viewId); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id || param.viewId, }); if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -466,23 +506,26 @@ export class DatasService { }); } - async mmExcludedList(param: { - viewId: string; - colId: string; - query: any; - rowId: string; - }) { - const view = await View.get(param.viewId); + async mmExcludedList( + context: NcContext, + param: { + viewId: string; + colId: string; + query: any; + rowId: string; + }, + ) { + const view = await View.get(context, param.viewId); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id || param.viewId, }); if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -527,23 +570,26 @@ export class DatasService { }); } - async hmExcludedList(param: { - viewId: string; - colId: string; - query: any; - rowId: string; - }) { - const view = await View.get(param.viewId); + async hmExcludedList( + context: NcContext, + param: { + viewId: string; + colId: string; + query: any; + rowId: string; + }, + ) { + const view = await View.get(context, param.viewId); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id || param.viewId, }); if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -588,23 +634,26 @@ export class DatasService { }); } - async btExcludedList(param: { - viewId: string; - colId: string; - query: any; - rowId: string; - }) { - const view = await View.get(param.viewId); + async btExcludedList( + context: NcContext, + param: { + viewId: string; + colId: string; + query: any; + rowId: string; + }, + ) { + const view = await View.get(context, param.viewId); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id || param.viewId, }); if (!model) return NcError.tableNotFound(view?.fk_model_id || param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -649,23 +698,26 @@ export class DatasService { }); } - async hmList(param: { - viewId: string; - colId: string; - query: any; - rowId: string; - }) { - const view = await View.get(param.viewId); + async hmList( + context: NcContext, + param: { + viewId: string; + colId: string; + query: any; + rowId: string; + }, + ) { + const view = await View.get(context, param.viewId); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id || param.viewId, }); if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -708,21 +760,24 @@ export class DatasService { } as any); } - async dataReadByViewId(param: { viewId: string; rowId: string; query: any }) { + async dataReadByViewId( + context: NcContext, + param: { viewId: string; rowId: string; query: any }, + ) { try { - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: param.viewId, }); if (!model) NcError.tableNotFound(param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { ast, dependencyFields } = await getAst({ + const { ast, dependencyFields } = await getAst(context, { model, query: param.query, }); @@ -739,15 +794,18 @@ export class DatasService { } } - async dataInsertByViewId(param: { viewId: string; body: any; cookie: any }) { - const model = await Model.getByIdOrName({ + async dataInsertByViewId( + context: NcContext, + param: { viewId: string; body: any; cookie: any }, + ) { + const model = await Model.getByIdOrName(context, { id: param.viewId, }); if (!model) return NcError.tableNotFound(param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, dbDriver: await NcConnectionMgrv2.get(source), }); @@ -755,20 +813,23 @@ export class DatasService { return await baseModel.insert(param.body, null, param.cookie); } - async dataUpdateByViewId(param: { - viewId: string; - rowId: string; - body: any; - cookie: any; - }) { - const model = await Model.getByIdOrName({ + async dataUpdateByViewId( + context: NcContext, + param: { + viewId: string; + rowId: string; + body: any; + cookie: any; + }, + ) { + const model = await Model.getByIdOrName(context, { id: param.viewId, }); if (!model) NcError.tableNotFound(param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, dbDriver: await NcConnectionMgrv2.get(source), }); @@ -781,19 +842,22 @@ export class DatasService { ); } - async dataDeleteByViewId(param: { - viewId: string; - rowId: string; - cookie: any; - }) { - const model = await Model.getByIdOrName({ + async dataDeleteByViewId( + context: NcContext, + param: { + viewId: string; + rowId: string; + cookie: any; + }, + ) { + const model = await Model.getByIdOrName(context, { id: param.viewId, }); if (!model) NcError.tableNotFound(param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, dbDriver: await NcConnectionMgrv2.get(source), }); @@ -801,24 +865,27 @@ export class DatasService { return await baseModel.delByPk(param.rowId, null, param.cookie); } - async relationDataDelete(param: { - viewId: string; - colId: string; - childId: string; - rowId: string; - cookie: any; - }) { - const view = await View.get(param.viewId); + async relationDataDelete( + context: NcContext, + param: { + viewId: string; + colId: string; + childId: string; + rowId: string; + cookie: any; + }, + ) { + const view = await View.get(context, param.viewId); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id || param.viewId, }); if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -834,24 +901,27 @@ export class DatasService { return true; } - async relationDataAdd(param: { - viewId: string; - colId: string; - childId: string; - rowId: string; - cookie: any; - }) { - const view = await View.get(param.viewId); + async relationDataAdd( + context: NcContext, + param: { + viewId: string; + colId: string; + childId: string; + rowId: string; + cookie: any; + }, + ) { + const view = await View.get(context, param.viewId); - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id || param.viewId, }); if (!model) NcError.tableNotFound(view?.fk_model_id || param.viewId); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -868,20 +938,24 @@ export class DatasService { } async getViewAndModelFromRequestByAliasOrId( + context: NcContext, req, // : // | Request<{ baseName: string; tableName: string; viewName?: string }> // | Request, ) { - const base = await Base.getWithInfoByTitleOrId(req.params.baseName); + const base = await Base.getWithInfoByTitleOrId( + context, + req.params.baseName, + ); - const model = await Model.getByAliasOrId({ + const model = await Model.getByAliasOrId(context, { base_id: base.id, aliasOrId: req.params.tableName, }); const view = req.params.viewName && - (await View.getByTitleOrId({ + (await View.getByTitleOrId(context, { titleOrId: req.params.viewName, fk_model_id: model.id, })); @@ -889,12 +963,15 @@ export class DatasService { return { model, view }; } - async extractXlsxData(param: { view: View; query: any; siteUrl: string }) { + async extractXlsxData( + context: NcContext, + param: { view: View; query: any; siteUrl: string }, + ) { const { view, query, siteUrl } = param; - const source = await Source.get(view.source_id); + const source = await Source.get(context, view.source_id); - await view.getModelWithInfo(); - await view.getColumns(); + await view.getModelWithInfo(context); + await view.getColumns(context); view.model.columns = view.columns .filter((c) => c.show) @@ -907,13 +984,13 @@ export class DatasService { ) .filter((column) => !isSystemColumn(column) || view.show_system_fields); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: view.model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { offset, dbRows, elapsed } = await getDbRows({ + const { offset, dbRows, elapsed } = await getDbRows(context, { baseModel, view, query, @@ -927,12 +1004,12 @@ export class DatasService { return { offset, dbRows, elapsed, data }; } - async extractCsvData(view: View, req) { - const source = await Source.get(view.source_id); + async extractCsvData(context: NcContext, view: View, req) { + const source = await Source.get(context, view.source_id); const fields = req.query.fields; - await view.getModelWithInfo(); - await view.getColumns(); + await view.getModelWithInfo(context); + await view.getColumns(context); view.model.columns = view.columns .filter((c) => c.show) @@ -945,13 +1022,13 @@ export class DatasService { ) .filter((column) => !isSystemColumn(column) || view.show_system_fields); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: view.model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { offset, dbRows, elapsed } = await getDbRows({ + const { offset, dbRows, elapsed } = await getDbRows(context, { baseModel, view, query: req.query, @@ -984,8 +1061,12 @@ export class DatasService { return { offset, dbRows, elapsed, data }; } - async getColumnByIdOrName(columnNameOrId: string, model: Model) { - const column = (await model.getColumns()).find( + async getColumnByIdOrName( + context: NcContext, + columnNameOrId: string, + model: Model, + ) { + const column = (await model.getColumns(context)).find( (c) => c.title === columnNameOrId || c.id === columnNameOrId || diff --git a/packages/nocodb/src/services/extensions.service.ts b/packages/nocodb/src/services/extensions.service.ts index 94ff2b54ba..031ccc6107 100644 --- a/packages/nocodb/src/services/extensions.service.ts +++ b/packages/nocodb/src/services/extensions.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; import { AppEvents, type ExtensionReqType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { Extension } from '~/models'; @@ -9,24 +9,27 @@ import { Extension } from '~/models'; export class ExtensionsService { constructor(private readonly appHooksService: AppHooksService) {} - async extensionList(param: { baseId: string }) { - return await Extension.list(param.baseId); + async extensionList(context: NcContext, param: { baseId: string }) { + return await Extension.list(context, param.baseId); } - async extensionRead(param: { extensionId: string }) { - return await Extension.get(param.extensionId); + async extensionRead(context: NcContext, param: { extensionId: string }) { + return await Extension.get(context, param.extensionId); } - async extensionCreate(param: { - extension: ExtensionReqType; - req: NcRequest; - }) { + async extensionCreate( + context: NcContext, + param: { + extension: ExtensionReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ExtensionReq', param.extension, ); - const res = await Extension.insert({ + const res = await Extension.insert(context, { ...param.extension, fk_user_id: param.req.user.id, }); @@ -40,17 +43,24 @@ export class ExtensionsService { return res; } - async extensionUpdate(param: { - extensionId: string; - extension: ExtensionReqType; - req: NcRequest; - }) { + async extensionUpdate( + context: NcContext, + param: { + extensionId: string; + extension: ExtensionReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ExtensionReq', param.extension, ); - const res = await Extension.update(param.extensionId, param.extension); + const res = await Extension.update( + context, + param.extensionId, + param.extension, + ); this.appHooksService.emit(AppEvents.EXTENSION_UPDATE, { extensionId: param.extensionId, @@ -61,8 +71,11 @@ export class ExtensionsService { return res; } - async extensionDelete(param: { extensionId: string; req: NcRequest }) { - const res = await Extension.delete(param.extensionId); + async extensionDelete( + context: NcContext, + param: { extensionId: string; req: NcRequest }, + ) { + const res = await Extension.delete(context, param.extensionId); this.appHooksService.emit(AppEvents.EXTENSION_DELETE, { extensionId: param.extensionId, diff --git a/packages/nocodb/src/services/filters.service.ts b/packages/nocodb/src/services/filters.service.ts index fbe65a5577..8b4af05426 100644 --- a/packages/nocodb/src/services/filters.service.ts +++ b/packages/nocodb/src/services/filters.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; import type { FilterReqType, UserType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -11,21 +11,24 @@ import { Filter, Hook, View } from '~/models'; export class FiltersService { constructor(protected readonly appHooksService: AppHooksService) {} - async hookFilterCreate(param: { - filter: FilterReqType; - hookId: any; - user: UserType; - req: NcRequest; - }) { + async hookFilterCreate( + context: NcContext, + param: { + filter: FilterReqType; + hookId: any; + user: UserType; + req: NcRequest; + }, + ) { validatePayload('swagger.json#/components/schemas/FilterReq', param.filter); - const hook = await Hook.get(param.hookId); + const hook = await Hook.get(context, param.hookId); if (!hook) { NcError.badRequest('Hook not found'); } - const filter = await Filter.insert({ + const filter = await Filter.insert(context, { ...param.filter, fk_hook_id: param.hookId, }); @@ -38,18 +41,21 @@ export class FiltersService { return filter; } - async hookFilterList(param: { hookId: any }) { - return Filter.rootFilterListByHook({ hookId: param.hookId }); + async hookFilterList(context: NcContext, param: { hookId: any }) { + return Filter.rootFilterListByHook(context, { hookId: param.hookId }); } - async filterDelete(param: { filterId: string; req: NcRequest }) { - const filter = await Filter.get(param.filterId); + async filterDelete( + context: NcContext, + param: { filterId: string; req: NcRequest }, + ) { + const filter = await Filter.get(context, param.filterId); if (!filter) { NcError.badRequest('Filter not found'); } - await Filter.delete(param.filterId); + await Filter.delete(context, param.filterId); this.appHooksService.emit(AppEvents.FILTER_DELETE, { filter, @@ -59,17 +65,20 @@ export class FiltersService { return true; } - async filterCreate(param: { - filter: FilterReqType; - viewId: string; - user: UserType; - req: NcRequest; - }) { + async filterCreate( + context: NcContext, + param: { + filter: FilterReqType; + viewId: string; + user: UserType; + req: NcRequest; + }, + ) { validatePayload('swagger.json#/components/schemas/FilterReq', param.filter); - const view = await View.get(param.viewId); + const view = await View.get(context, param.viewId); - const filter = await Filter.insert({ + const filter = await Filter.insert(context, { ...param.filter, fk_view_id: param.viewId, }); @@ -83,21 +92,28 @@ export class FiltersService { return filter; } - async filterUpdate(param: { - filter: FilterReqType; - filterId: string; - user: UserType; - req: NcRequest; - }) { + async filterUpdate( + context: NcContext, + param: { + filter: FilterReqType; + filterId: string; + user: UserType; + req: NcRequest; + }, + ) { validatePayload('swagger.json#/components/schemas/FilterReq', param.filter); - const filter = await Filter.get(param.filterId); + const filter = await Filter.get(context, param.filterId); if (!filter) { NcError.badRequest('Filter not found'); } // todo: type correction - const res = await Filter.update(param.filterId, param.filter as Filter); + const res = await Filter.update( + context, + param.filterId, + param.filter as Filter, + ); this.appHooksService.emit(AppEvents.FILTER_UPDATE, { filter, @@ -107,28 +123,33 @@ export class FiltersService { return res; } - async filterChildrenList(param: { filterId: string }) { - return Filter.parentFilterList({ + async filterChildrenList(context: NcContext, param: { filterId: string }) { + return Filter.parentFilterList(context, { parentId: param.filterId, }); } - async filterGet(param: { filterId: string }) { - const filter = await Filter.get(param.filterId); + async filterGet(context: NcContext, param: { filterId: string }) { + const filter = await Filter.get(context, param.filterId); return filter; } - async filterList(param: { viewId: string }) { - const filter = await Filter.rootFilterList({ viewId: param.viewId }); + async filterList(context: NcContext, param: { viewId: string }) { + const filter = await Filter.rootFilterList(context, { + viewId: param.viewId, + }); return filter; } - async linkFilterCreate(_param: { - filter: any; - columnId: string; - user: UserType; - req: NcRequest; - }): Promise { + async linkFilterCreate( + _context: NcContext, + _param: { + filter: any; + columnId: string; + user: UserType; + req: NcRequest; + }, + ): Promise { // placeholder method return null; } diff --git a/packages/nocodb/src/services/form-columns.service.ts b/packages/nocodb/src/services/form-columns.service.ts index 0811314b3d..8a0a7fe2dd 100644 --- a/packages/nocodb/src/services/form-columns.service.ts +++ b/packages/nocodb/src/services/form-columns.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { FormViewColumn } from '~/models'; @@ -9,18 +9,22 @@ import { FormViewColumn } from '~/models'; export class FormColumnsService { constructor(private readonly appHooksService: AppHooksService) {} - async columnUpdate(param: { - formViewColumnId: string; - // todo: replace with FormColumnReq - formViewColumn: FormViewColumn; - req: NcRequest; - }) { + async columnUpdate( + context: NcContext, + param: { + formViewColumnId: string; + // todo: replace with FormColumnReq + formViewColumn: FormViewColumn; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/FormColumnReq', param.formViewColumn, ); const res = await FormViewColumn.update( + context, param.formViewColumnId, param.formViewColumn, ); diff --git a/packages/nocodb/src/services/forms.service.ts b/packages/nocodb/src/services/forms.service.ts index 23b0beb641..40bd47b6ad 100644 --- a/packages/nocodb/src/services/forms.service.ts +++ b/packages/nocodb/src/services/forms.service.ts @@ -5,7 +5,7 @@ import type { UserType, ViewCreateReqType, } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -17,25 +17,29 @@ import { CacheScope } from '~/utils/globals'; export class FormsService { constructor(private readonly appHooksService: AppHooksService) {} - async formViewGet(param: { formViewId: string }) { - const formViewData = await FormView.getWithInfo(param.formViewId); + async formViewGet(context: NcContext, param: { formViewId: string }) { + const formViewData = await FormView.getWithInfo(context, param.formViewId); return formViewData; } - async formViewCreate(param: { - tableId: string; - body: ViewCreateReqType; - user: UserType; - req: NcRequest; - }) { + async formViewCreate( + context: NcContext, + param: { + tableId: string; + body: ViewCreateReqType; + user: UserType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewCreateReq', param.body, ); - const model = await Model.get(param.tableId); + const model = await Model.get(context, param.tableId); const { id } = await View.insertMetaOnly( + context, { ...param.body, // todo: sanitize @@ -48,7 +52,7 @@ export class FormsService { ); // populate cache and add to list since the list cache already exist - const view = await View.get(id); + const view = await View.get(context, id); await NocoCache.appendToList( CacheScope.VIEW, [view.fk_model_id], @@ -65,22 +69,25 @@ export class FormsService { return view; } - async formViewUpdate(param: { - formViewId: string; - form: FormUpdateReqType; - req: NcRequest; - }) { + async formViewUpdate( + context: NcContext, + param: { + formViewId: string; + form: FormUpdateReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/FormUpdateReq', param.form, ); - const view = await View.get(param.formViewId); + const view = await View.get(context, param.formViewId); if (!view) { NcError.viewNotFound(param.formViewId); } - const res = await FormView.update(param.formViewId, param.form); + const res = await FormView.update(context, param.formViewId, param.form); this.appHooksService.emit(AppEvents.VIEW_UPDATE, { view, diff --git a/packages/nocodb/src/services/galleries.service.ts b/packages/nocodb/src/services/galleries.service.ts index 70d52a9025..2a093c6d20 100644 --- a/packages/nocodb/src/services/galleries.service.ts +++ b/packages/nocodb/src/services/galleries.service.ts @@ -5,7 +5,7 @@ import type { UserType, ViewCreateReqType, } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -17,25 +17,29 @@ import { CacheScope } from '~/utils/globals'; export class GalleriesService { constructor(private readonly appHooksService: AppHooksService) {} - async galleryViewGet(param: { galleryViewId: string }) { - return await GalleryView.get(param.galleryViewId); + async galleryViewGet(context: NcContext, param: { galleryViewId: string }) { + return await GalleryView.get(context, param.galleryViewId); } - async galleryViewCreate(param: { - tableId: string; - gallery: ViewCreateReqType; - user: UserType; + async galleryViewCreate( + context: NcContext, + param: { + tableId: string; + gallery: ViewCreateReqType; + user: UserType; - req: NcRequest; - }) { + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewCreateReq', param.gallery, ); - const model = await Model.get(param.tableId); + const model = await Model.get(context, param.tableId); const { id } = await View.insertMetaOnly( + context, { ...param.gallery, // todo: sanitize @@ -48,7 +52,7 @@ export class GalleriesService { ); // populate cache and add to list since the list cache already exist - const view = await View.get(id); + const view = await View.get(context, id); await NocoCache.appendToList( CacheScope.VIEW, [view.fk_model_id], @@ -63,23 +67,30 @@ export class GalleriesService { return view; } - async galleryViewUpdate(param: { - galleryViewId: string; - gallery: GalleryUpdateReqType; - req: NcRequest; - }) { + async galleryViewUpdate( + context: NcContext, + param: { + galleryViewId: string; + gallery: GalleryUpdateReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/GalleryUpdateReq', param.gallery, ); - const view = await View.get(param.galleryViewId); + const view = await View.get(context, param.galleryViewId); if (!view) { NcError.viewNotFound(param.galleryViewId); } - const res = await GalleryView.update(param.galleryViewId, param.gallery); + const res = await GalleryView.update( + context, + param.galleryViewId, + param.gallery, + ); this.appHooksService.emit(AppEvents.VIEW_UPDATE, { view, diff --git a/packages/nocodb/src/services/grid-columns.service.ts b/packages/nocodb/src/services/grid-columns.service.ts index e72f23472c..abe09edd3a 100644 --- a/packages/nocodb/src/services/grid-columns.service.ts +++ b/packages/nocodb/src/services/grid-columns.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; import type { GridColumnReqType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { GridViewColumn } from '~/models'; @@ -10,21 +10,28 @@ import { GridViewColumn } from '~/models'; export class GridColumnsService { constructor(private readonly appHooksService: AppHooksService) {} - async columnList(param: { gridViewId: string }) { - return await GridViewColumn.list(param.gridViewId); + async columnList(context: NcContext, param: { gridViewId: string }) { + return await GridViewColumn.list(context, param.gridViewId); } - async gridColumnUpdate(param: { - gridViewColumnId: string; - grid: GridColumnReqType; - req: NcRequest; - }) { + async gridColumnUpdate( + context: NcContext, + param: { + gridViewColumnId: string; + grid: GridColumnReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/GridColumnReq', param.grid, ); - const res = await GridViewColumn.update(param.gridViewColumnId, param.grid); + const res = await GridViewColumn.update( + context, + param.gridViewColumnId, + param.grid, + ); this.appHooksService.emit(AppEvents.GRID_COLUMN_UPDATE, { req: param.req, diff --git a/packages/nocodb/src/services/grids.service.ts b/packages/nocodb/src/services/grids.service.ts index 4496223f47..8f141ea29e 100644 --- a/packages/nocodb/src/services/grids.service.ts +++ b/packages/nocodb/src/services/grids.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents, ViewTypes } from 'nocodb-sdk'; import type { GridUpdateReqType, ViewCreateReqType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -13,19 +13,23 @@ import { CacheScope } from '~/utils/globals'; export class GridsService { constructor(private readonly appHooksService: AppHooksService) {} - async gridViewCreate(param: { - tableId: string; - grid: ViewCreateReqType; - req: NcRequest; - }) { + async gridViewCreate( + context: NcContext, + param: { + tableId: string; + grid: ViewCreateReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewCreateReq', param.grid, ); - const model = await Model.get(param.tableId); + const model = await Model.get(context, param.tableId); const { id } = await View.insertMetaOnly( + context, { ...param.grid, // todo: sanitize @@ -38,7 +42,7 @@ export class GridsService { ); // populate cache and add to list since the list cache already exist - const view = await View.get(id); + const view = await View.get(context, id); await NocoCache.appendToList( CacheScope.VIEW, [view.fk_model_id], @@ -54,23 +58,26 @@ export class GridsService { return view; } - async gridViewUpdate(param: { - viewId: string; - grid: GridUpdateReqType; - req: NcRequest; - }) { + async gridViewUpdate( + context: NcContext, + param: { + viewId: string; + grid: GridUpdateReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/GridUpdateReq', param.grid, ); - const view = await View.get(param.viewId); + const view = await View.get(context, param.viewId); if (!view) { NcError.viewNotFound(param.viewId); } - const res = await GridView.update(param.viewId, param.grid); + const res = await GridView.update(context, param.viewId, param.grid); this.appHooksService.emit(AppEvents.VIEW_UPDATE, { view, diff --git a/packages/nocodb/src/services/hook-handler.service.ts b/packages/nocodb/src/services/hook-handler.service.ts index ad59fd5e93..a64b248b1e 100644 --- a/packages/nocodb/src/services/hook-handler.service.ts +++ b/packages/nocodb/src/services/hook-handler.service.ts @@ -1,6 +1,7 @@ import { Inject, Injectable, Logger } from '@nestjs/common'; import { UITypes, ViewTypes } from 'nocodb-sdk'; import ejs from 'ejs'; +import type { NcContext } from '~/interface/config'; import type { FormColumnType, HookType } from 'nocodb-sdk'; import type { ColumnType } from 'nocodb-sdk'; import type { OnModuleDestroy, OnModuleInit } from '@nestjs/common'; @@ -24,17 +25,12 @@ export class HookHandlerService implements OnModuleInit, OnModuleDestroy { @Inject('JobsService') private readonly jobsService: IJobsService, ) {} - public async handleHooks({ - hookName, - prevData, - newData, - user, - viewId, - modelId, - tnPath, - }): Promise { - const view = await View.get(viewId); - const model = await Model.get(modelId); + public async handleHooks( + context: NcContext, + { hookName, prevData, newData, user, viewId, modelId, tnPath }, + ): Promise { + const view = await View.get(context, viewId); + const model = await Model.get(context, modelId); // handle form view data submission if ( @@ -42,15 +38,18 @@ export class HookHandlerService implements OnModuleInit, OnModuleDestroy { view.type === ViewTypes.FORM ) { try { - const formView = await view.getView(); + const formView = await view.getView(context); const emails = Object.entries(JSON.parse(formView?.email) || {}) .filter((a) => a[1]) .map((a) => a[0]); if (emails?.length) { - const { columns } = await FormView.getWithInfo(formView.fk_view_id); - const allColumns = await model.getColumns(); + const { columns } = await FormView.getWithInfo( + context, + formView.fk_view_id, + ); + const allColumns = await model.getColumns(context); const fieldById = columns.reduce( (o: Record, f: FormColumnType) => { return Object.assign(o, { [f.fk_column_id]: f }); @@ -111,7 +110,7 @@ export class HookHandlerService implements OnModuleInit, OnModuleDestroy { } const [event, operation] = hookName.split('.'); - const hooks = await Hook.list({ + const hooks = await Hook.list(context, { fk_model_id: modelId, event: event as HookType['event'], operation: operation as HookType['operation'], @@ -120,6 +119,7 @@ export class HookHandlerService implements OnModuleInit, OnModuleDestroy { if (hook.active) { try { await this.jobsService.add(JobTypes.HandleWebhook, { + context, hookId: hook.id, modelId, viewId, @@ -139,10 +139,10 @@ export class HookHandlerService implements OnModuleInit, OnModuleDestroy { } onModuleInit(): any { - this.unsubscribe = this.eventEmitter.on( - HANDLE_WEBHOOK, - this.handleHooks.bind(this), - ); + this.unsubscribe = this.eventEmitter.on(HANDLE_WEBHOOK, async (arg) => { + const { context, ...rest } = arg; + return this.handleHooks(context, rest); + }); } onModuleDestroy() { diff --git a/packages/nocodb/src/services/hooks.service.ts b/packages/nocodb/src/services/hooks.service.ts index 7903a0e334..cfd8b62edf 100644 --- a/packages/nocodb/src/services/hooks.service.ts +++ b/packages/nocodb/src/services/hooks.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; import type { HookReqType, HookTestReqType, HookType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -30,24 +30,31 @@ export class HooksService { } } - async hookList(param: { tableId: string }) { - return await Hook.list({ fk_model_id: param.tableId }); + async hookList(context: NcContext, param: { tableId: string }) { + return await Hook.list(context, { fk_model_id: param.tableId }); } - async hookLogList(param: { query: any; hookId: string }) { - return await HookLog.list({ fk_hook_id: param.hookId }, param.query); + async hookLogList(context: NcContext, param: { query: any; hookId: string }) { + return await HookLog.list( + context, + { fk_hook_id: param.hookId }, + param.query, + ); } - async hookCreate(param: { - tableId: string; - hook: HookReqType; - req: NcRequest; - }) { + async hookCreate( + context: NcContext, + param: { + tableId: string; + hook: HookReqType; + req: NcRequest; + }, + ) { validatePayload('swagger.json#/components/schemas/HookReq', param.hook); this.validateHookPayload(param.hook.notification); - const hook = await Hook.insert({ + const hook = await Hook.insert(context, { ...param.hook, fk_model_id: param.tableId, } as any); @@ -60,14 +67,17 @@ export class HooksService { return hook; } - async hookDelete(param: { hookId: string; req: NcRequest }) { - const hook = await Hook.get(param.hookId); + async hookDelete( + context: NcContext, + param: { hookId: string; req: NcRequest }, + ) { + const hook = await Hook.get(context, param.hookId); if (!hook) { NcError.badRequest('Hook not found'); } - await Hook.delete(param.hookId); + await Hook.delete(context, param.hookId); this.appHooksService.emit(AppEvents.WEBHOOK_DELETE, { hook, req: param.req, @@ -75,14 +85,17 @@ export class HooksService { return true; } - async hookUpdate(param: { - hookId: string; - hook: HookReqType; - req: NcRequest; - }) { + async hookUpdate( + context: NcContext, + param: { + hookId: string; + hook: HookReqType; + req: NcRequest; + }, + ) { validatePayload('swagger.json#/components/schemas/HookReq', param.hook); - const hook = await Hook.get(param.hookId); + const hook = await Hook.get(context, param.hookId); if (!hook) { NcError.badRequest('Hook not found'); @@ -90,7 +103,7 @@ export class HooksService { this.validateHookPayload(param.hook.notification); - const res = await Hook.update(param.hookId, param.hook); + const res = await Hook.update(context, param.hookId, param.hook); this.appHooksService.emit(AppEvents.WEBHOOK_UPDATE, { hook: { @@ -103,11 +116,14 @@ export class HooksService { return res; } - async hookTest(param: { - tableId: string; - hookTest: HookTestReqType; - req: NcRequest; - }) { + async hookTest( + context: NcContext, + param: { + tableId: string; + hookTest: HookTestReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/HookTestReq', param.hookTest, @@ -115,14 +131,14 @@ export class HooksService { this.validateHookPayload(param.hookTest.hook?.notification); - const model = await Model.getByIdOrName({ id: param.tableId }); + const model = await Model.getByIdOrName(context, { id: param.tableId }); const { hook, payload: { data, user }, } = param.hookTest; try { - await invokeWebhook({ + await invokeWebhook(context, { hook: new Hook(hook), model: model, view: null, @@ -145,20 +161,35 @@ export class HooksService { return true; } - async tableSampleData(param: { - tableId: string; - operation: HookType['operation']; - version: any; // HookType['version']; - }) { - const model = new Model(await Model.getByIdOrName({ id: param.tableId })); + async tableSampleData( + context: NcContext, + param: { + tableId: string; + operation: HookType['operation']; + version: any; // HookType['version']; + }, + ) { + const model = new Model( + await Model.getByIdOrName(context, { id: param.tableId }), + ); if (param.version === 'v1') { - return await populateSamplePayload(model, false, param.operation); + return await populateSamplePayload( + context, + model, + false, + param.operation, + ); } - return await populateSamplePayloadV2(model, false, param.operation); + return await populateSamplePayloadV2( + context, + model, + false, + param.operation, + ); } - async hookLogCount(param: { hookId: string }) { - return await HookLog.count({ hookId: param.hookId }); + async hookLogCount(context: NcContext, param: { hookId: string }) { + return await HookLog.count(context, { hookId: param.hookId }); } } diff --git a/packages/nocodb/src/services/kanbans.service.ts b/packages/nocodb/src/services/kanbans.service.ts index bfa73ff566..e8ffb835f3 100644 --- a/packages/nocodb/src/services/kanbans.service.ts +++ b/packages/nocodb/src/services/kanbans.service.ts @@ -5,7 +5,7 @@ import type { UserType, ViewCreateReqType, } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -17,24 +17,28 @@ import { CacheScope } from '~/utils/globals'; export class KanbansService { constructor(private readonly appHooksService: AppHooksService) {} - async kanbanViewGet(param: { kanbanViewId: string }) { - return await KanbanView.get(param.kanbanViewId); + async kanbanViewGet(context: NcContext, param: { kanbanViewId: string }) { + return await KanbanView.get(context, param.kanbanViewId); } - async kanbanViewCreate(param: { - tableId: string; - kanban: ViewCreateReqType; - user: UserType; - req: NcRequest; - }) { + async kanbanViewCreate( + context: NcContext, + param: { + tableId: string; + kanban: ViewCreateReqType; + user: UserType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewCreateReq', param.kanban, ); - const model = await Model.get(param.tableId); + const model = await Model.get(context, param.tableId); const { id } = await View.insertMetaOnly( + context, { ...param.kanban, // todo: sanitize @@ -47,7 +51,7 @@ export class KanbansService { ); // populate cache and add to list since the list cache already exist - const view = await View.get(id); + const view = await View.get(context, id); await NocoCache.appendToList( CacheScope.VIEW, [view.fk_model_id], @@ -65,23 +69,30 @@ export class KanbansService { return view; } - async kanbanViewUpdate(param: { - kanbanViewId: string; - kanban: KanbanUpdateReqType; - req: NcRequest; - }) { + async kanbanViewUpdate( + context: NcContext, + param: { + kanbanViewId: string; + kanban: KanbanUpdateReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/KanbanUpdateReq', param.kanban, ); - const view = await View.get(param.kanbanViewId); + const view = await View.get(context, param.kanbanViewId); if (!view) { NcError.viewNotFound(param.kanbanViewId); } - const res = await KanbanView.update(param.kanbanViewId, param.kanban); + const res = await KanbanView.update( + context, + param.kanbanViewId, + param.kanban, + ); this.appHooksService.emit(AppEvents.VIEW_UPDATE, { view, diff --git a/packages/nocodb/src/services/maps.service.ts b/packages/nocodb/src/services/maps.service.ts index cdf9112b40..3e12393393 100644 --- a/packages/nocodb/src/services/maps.service.ts +++ b/packages/nocodb/src/services/maps.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents, ViewTypes } from 'nocodb-sdk'; import type { MapUpdateReqType, UserType, ViewCreateReqType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -13,24 +13,28 @@ import NocoCache from '~/cache/NocoCache'; export class MapsService { constructor(private readonly appHooksService: AppHooksService) {} - async mapViewGet(param: { mapViewId: string }) { - return await MapView.get(param.mapViewId); + async mapViewGet(context: NcContext, param: { mapViewId: string }) { + return await MapView.get(context, param.mapViewId); } - async mapViewCreate(param: { - tableId: string; - map: ViewCreateReqType; - user: UserType; - req: NcRequest; - }) { + async mapViewCreate( + context: NcContext, + param: { + tableId: string; + map: ViewCreateReqType; + user: UserType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewCreateReq', param.map, ); - const model = await Model.get(param.tableId); + const model = await Model.get(context, param.tableId); const { id } = await View.insertMetaOnly( + context, { ...param.map, // todo: sanitize @@ -43,7 +47,7 @@ export class MapsService { ); // populate cache and add to list since the list cache already exist - const view = await View.get(id); + const view = await View.get(context, id); await NocoCache.appendToList( CacheScope.VIEW, [view.fk_model_id], @@ -60,20 +64,23 @@ export class MapsService { return view; } - async mapViewUpdate(param: { - mapViewId: string; - map: MapUpdateReqType; - req: NcRequest; - }) { + async mapViewUpdate( + context: NcContext, + param: { + mapViewId: string; + map: MapUpdateReqType; + req: NcRequest; + }, + ) { validatePayload('swagger.json#/components/schemas/MapUpdateReq', param.map); - const view = await View.get(param.mapViewId); + const view = await View.get(context, param.mapViewId); if (!view) { NcError.viewNotFound(param.mapViewId); } - const res = await MapView.update(param.mapViewId, param.map); + const res = await MapView.update(context, param.mapViewId, param.map); this.appHooksService.emit(AppEvents.VIEW_UPDATE, { view, diff --git a/packages/nocodb/src/services/meta-diffs.service.ts b/packages/nocodb/src/services/meta-diffs.service.ts index fa3c572b16..927919c2b8 100644 --- a/packages/nocodb/src/services/meta-diffs.service.ts +++ b/packages/nocodb/src/services/meta-diffs.service.ts @@ -9,6 +9,7 @@ import { } from 'nocodb-sdk'; import { pluralize, singularize } from 'inflection'; import type { LinksColumn, LinkToAnotherRecordColumn } from '~/models'; +import type { NcContext } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import ModelXcMetaFactory from '~/db/sql-mgr/code/models/xc/ModelXcMetaFactory'; import getColumnUiType from '~/helpers/getColumnUiType'; @@ -129,6 +130,7 @@ export class MetaDiffsService { constructor(private appHooksService: AppHooksService) {} async getMetaDiff( + context: NcContext, sqlClient, base: Base, source: Source, @@ -152,7 +154,7 @@ export class MetaDiffsService { }); const colListRef = {}; - const oldMetas = await source.getModels(); + const oldMetas = await source.getModels(context); // @ts-ignore const oldTableMetas: Model[] = []; const oldViewMetas: Model[] = []; @@ -219,7 +221,7 @@ export class MetaDiffsService { }) )?.data?.list; - await oldMeta.getColumns(); + await oldMeta.getColumns(context); for (const column of colListRef[table.tn]) { const oldColIdx = oldMeta.columns.findIndex( @@ -313,16 +315,17 @@ export class MetaDiffsService { } for (const relationCol of virtualRelationColumns) { - const colOpt = - await relationCol.getColOptions(); - const parentCol = await colOpt.getParentColumn(); - const childCol = await colOpt.getChildColumn(); - const parentModel = await parentCol.getModel(); - const childModel = await childCol.getModel(); + const colOpt = await relationCol.getColOptions( + context, + ); + const parentCol = await colOpt.getParentColumn(context); + const childCol = await colOpt.getChildColumn(context); + const parentModel = await parentCol.getModel(context); + const childModel = await childCol.getModel(context); // many to many relation if (colOpt.type === RelationTypes.MANY_TO_MANY) { - const m2mModel = await colOpt.getMMModel(); + const m2mModel = await colOpt.getMMModel(context); const relatedTable = tableList.find( (t) => t.tn === parentModel.table_name, @@ -381,8 +384,8 @@ export class MetaDiffsService { }) )?.data?.list); - const m2mChildCol = await colOpt.getMMChildColumn(); - const m2mParentCol = await colOpt.getMMParentColumn(); + const m2mChildCol = await colOpt.getMMChildColumn(context); + const m2mParentCol = await colOpt.getMMParentColumn(context); if ( pColumns.every((c) => c.cn !== parentCol.column_name) || @@ -537,7 +540,7 @@ export class MetaDiffsService { }) )?.data?.list; - await oldMeta.getColumns(); + await oldMeta.getColumns(context); for (const column of colListRef[view.tn]) { const oldColIdx = oldMeta.columns.findIndex( @@ -614,8 +617,8 @@ export class MetaDiffsService { return changes; } - async metaDiff(param: { baseId: string }) { - const base = await Base.getWithInfo(param.baseId); + async metaDiff(context: NcContext, param: { baseId: string }) { + const base = await Base.getWithInfo(context, param.baseId); let changes = []; for (const source of base.sources) { try { @@ -625,7 +628,7 @@ export class MetaDiffsService { // @ts-ignore const sqlClient = await NcConnectionMgrv2.getSqlClient(source); changes = changes.concat( - await this.getMetaDiff(sqlClient, base, source), + await this.getMetaDiff(context, sqlClient, base, source), ); } catch (e) { console.log(e); @@ -635,19 +638,27 @@ export class MetaDiffsService { return changes; } - async baseMetaDiff(param: { baseId: string; sourceId: string }) { - const base = await Base.getWithInfo(param.baseId); - const source = await Source.get(param.sourceId); + async baseMetaDiff( + context: NcContext, + param: { baseId: string; sourceId: string }, + ) { + const base = await Base.getWithInfo(context, param.baseId); + const source = await Source.get(context, param.sourceId); let changes = []; const sqlClient = await NcConnectionMgrv2.getSqlClient(source); - changes = await this.getMetaDiff(sqlClient, base, source); + changes = await this.getMetaDiff(context, sqlClient, base, source); return changes; } - async syncBaseMeta(base: Base, source: Source, throwOnFail = false) { + async syncBaseMeta( + context: NcContext, + base: Base, + source: Source, + throwOnFail = false, + ) { if (source.is_meta) { if (throwOnFail) NcError.badRequest('Cannot sync meta source'); return; @@ -657,7 +668,7 @@ export class MetaDiffsService { // @ts-ignore const sqlClient = await NcConnectionMgrv2.getSqlClient(source); - const changes = await this.getMetaDiff(sqlClient, base, source); + const changes = await this.getMetaDiff(context, sqlClient, base, source); /* Get all relations */ // const relations = (await sqlClient.relationListAll())?.data?.list; @@ -685,7 +696,7 @@ export class MetaDiffsService { mapDefaultDisplayValue(columns); - const model = await Model.insert(base.id, source.id, { + const model = await Model.insert(context, base.id, source.id, { table_name: table_name, title: getTableNameAlias( table_name, @@ -696,7 +707,7 @@ export class MetaDiffsService { }); for (const column of columns) { - await Column.insert({ + await Column.insert(context, { uidt: getColumnUiType(source, column), fk_model_id: model.id, ...column, @@ -716,14 +727,14 @@ export class MetaDiffsService { mapDefaultDisplayValue(columns); - const model = await Model.insert(base.id, source.id, { + const model = await Model.insert(context, base.id, source.id, { table_name: table_name, title: getTableNameAlias(table_name, base.prefix, source), type: ModelTypes.VIEW, }); for (const column of columns) { - await Column.insert({ + await Column.insert(context, { uidt: getColumnUiType(source, column), fk_model_id: model.id, ...column, @@ -735,7 +746,7 @@ export class MetaDiffsService { case MetaDiffType.TABLE_REMOVE: case MetaDiffType.VIEW_REMOVE: { - await change.model.delete(); + await change.model.delete(context); } break; case MetaDiffType.TABLE_COLUMN_ADD: @@ -751,7 +762,10 @@ export class MetaDiffsService { column.uidt = getColumnUiType(source, column); //todo: inflection column.title = getColumnNameAlias(column.cn, source); - await Column.insert({ fk_model_id: change.id, ...column }); + await Column.insert(context, { + fk_model_id: change.id, + ...column, + }); } // update old // populateParams.tableNames.push({ tn }); @@ -774,7 +788,7 @@ export class MetaDiffsService { ); column.uidt = metaFact.getUIDataType(column); column.title = change.column.title; - await Column.update(change.column.id, column); + await Column.update(context, change.column.id, column); } break; case MetaDiffType.TABLE_COLUMN_PROPS_CHANGED: @@ -785,7 +799,7 @@ export class MetaDiffsService { const colMeta = columns.find((c) => c.cn === change.cn); if (!colMeta) break; const { pk, ai, rqd, un, unique } = colMeta; - await Column.update(change.column.id, { + await Column.update(context, change.column.id, { pk, ai, rqd, @@ -796,37 +810,37 @@ export class MetaDiffsService { break; case MetaDiffType.TABLE_COLUMN_REMOVE: case MetaDiffType.VIEW_COLUMN_REMOVE: - await change.column.delete(); + await change.column.delete(context); break; case MetaDiffType.TABLE_RELATION_REMOVE: case MetaDiffType.TABLE_VIRTUAL_M2M_REMOVE: - await change.column.delete(); + await change.column.delete(context); break; case MetaDiffType.TABLE_RELATION_ADD: { virtualColumnInsert.push(async () => { - const parentModel = await Model.getByIdOrName({ + const parentModel = await Model.getByIdOrName(context, { base_id: source.base_id, source_id: source.id, table_name: change.rtn, }); - const childModel = await Model.getByIdOrName({ + const childModel = await Model.getByIdOrName(context, { base_id: source.base_id, source_id: source.id, table_name: change.tn, }); const parentCol = await parentModel - .getColumns() + .getColumns(context) .then((cols) => cols.find((c) => c.column_name === change.rcn), ); const childCol = await childModel - .getColumns() + .getColumns(context) .then((cols) => cols.find((c) => c.column_name === change.cn), ); - await Column.update(childCol.id, { + await Column.update(context, childCol.id, { ...childCol, uidt: UITypes.ForeignKey, system: true, @@ -837,7 +851,7 @@ export class MetaDiffsService { childModel.columns, `${parentModel.title || parentModel.table_name}`, ); - await Column.insert({ + await Column.insert(context, { uidt: UITypes.LinkToAnotherRecord, title, fk_model_id: childModel.id, @@ -853,7 +867,7 @@ export class MetaDiffsService { childModel.columns, pluralize(childModel.title || childModel.table_name), ); - await Column.insert({ + await Column.insert(context, { uidt: UITypes.Links, title, fk_model_id: parentModel.id, @@ -879,13 +893,16 @@ export class MetaDiffsService { await NcHelp.executeOperations(virtualColumnInsert, source.type); // populate m2m relations - await this.extractAndGenerateManyToManyRelations(await source.getModels()); + await this.extractAndGenerateManyToManyRelations( + context, + await source.getModels(context), + ); } - async metaDiffSync(param: { baseId: string; req: any }) { - const base = await Base.getWithInfo(param.baseId); + async metaDiffSync(context: NcContext, param: { baseId: string; req: any }) { + const base = await Base.getWithInfo(context, param.baseId); for (const source of base.sources) { - await this.syncBaseMeta(base, source); + await this.syncBaseMeta(context, base, source); } this.appHooksService.emit(AppEvents.META_DIFF_SYNC, { @@ -896,15 +913,18 @@ export class MetaDiffsService { return true; } - async baseMetaDiffSync(param: { - baseId: string; - sourceId: string; - req: any; - }) { - const base = await Base.getWithInfo(param.baseId); - const source = await Source.get(param.sourceId); + async baseMetaDiffSync( + context: NcContext, + param: { + baseId: string; + sourceId: string; + req: any; + }, + ) { + const base = await Base.getWithInfo(context, param.baseId); + const source = await Source.get(context, param.sourceId); - await this.syncBaseMeta(base, source, true); + await this.syncBaseMeta(context, base, source, true); this.appHooksService.emit(AppEvents.META_DIFF_SYNC, { base, @@ -916,16 +936,19 @@ export class MetaDiffsService { } async isMMRelationExist( + context: NcContext, model: Model, assocModel: Model, belongsToCol: Column, ) { let isExist = false; const colChildOpt = - await belongsToCol.getColOptions(); - for (const col of await model.getColumns()) { + await belongsToCol.getColOptions(context); + for (const col of await model.getColumns(context)) { if (isLinksOrLTAR(col.uidt)) { - const colOpt = await col.getColOptions(); + const colOpt = await col.getColOptions( + context, + ); if ( colOpt && colOpt.type === RelationTypes.MANY_TO_MANY && @@ -942,9 +965,12 @@ export class MetaDiffsService { } // @ts-ignore - async extractAndGenerateManyToManyRelations(modelsArr: Array) { + async extractAndGenerateManyToManyRelations( + context: NcContext, + modelsArr: Array, + ) { for (const assocModel of modelsArr) { - await assocModel.getColumns(); + await assocModel.getColumns(context); // check if table is a Bridge table(or Associative Table) by checking // number of foreign keys and columns @@ -952,7 +978,9 @@ export class MetaDiffsService { const belongsToCols: Column[] = []; for (const col of assocModel.columns) { if (col.uidt == UITypes.LinkToAnotherRecord) { - const colOpt = await col.getColOptions(); + const colOpt = await col.getColOptions( + context, + ); if (colOpt?.type === RelationTypes.BELONGS_TO) belongsToCols.push(col); } @@ -964,26 +992,32 @@ export class MetaDiffsService { normalColumns.length < 5 && assocModel.primaryKeys.length === 2 ) { - const modelA = await belongsToCols[0].colOptions.getRelatedTable(); - const modelB = await belongsToCols[1].colOptions.getRelatedTable(); + const modelA = await belongsToCols[0].colOptions.getRelatedTable( + context, + ); + const modelB = await belongsToCols[1].colOptions.getRelatedTable( + context, + ); - await modelA.getColumns(); - await modelB.getColumns(); + await modelA.getColumns(context); + await modelB.getColumns(context); // check tableA already have the relation or not const isRelationAvailInA = await this.isMMRelationExist( + context, modelA, assocModel, belongsToCols[0], ); const isRelationAvailInB = await this.isMMRelationExist( + context, modelB, assocModel, belongsToCols[1], ); if (!isRelationAvailInA) { - await Column.insert({ + await Column.insert(context, { title: getUniqueColumnAliasName( modelA.columns, pluralize(modelB.title), @@ -1007,7 +1041,7 @@ export class MetaDiffsService { }); } if (!isRelationAvailInB) { - await Column.insert({ + await Column.insert(context, { title: getUniqueColumnAliasName( modelB.columns, pluralize(modelA.title), @@ -1031,18 +1065,19 @@ export class MetaDiffsService { }); } - await Model.markAsMmTable(assocModel.id, true); + await Model.markAsMmTable(context, assocModel.id, true); // mark has many relation associated with mm as system field in both table for (const btCol of [belongsToCols[0], belongsToCols[1]]) { const colOpt = await btCol.colOptions; - const model = await colOpt.getRelatedTable(); + const model = await colOpt.getRelatedTable(context); - for (const col of await model.getColumns()) { + for (const col of await model.getColumns(context)) { if (!isLinksOrLTAR(col.uidt)) continue; - const colOpt1 = - await col.getColOptions(); + const colOpt1 = await col.getColOptions( + context, + ); if (!colOpt1 || colOpt1.type !== RelationTypes.HAS_MANY) continue; if ( @@ -1051,12 +1086,13 @@ export class MetaDiffsService { ) continue; - await Column.markAsSystemField(col.id); + await Column.markAsSystemField(context, col.id); break; } } } else { - if (assocModel.mm) await Model.markAsMmTable(assocModel.id, false); + if (assocModel.mm) + await Model.markAsMmTable(context, assocModel.id, false); } } } diff --git a/packages/nocodb/src/services/model-visibilities.service.ts b/packages/nocodb/src/services/model-visibilities.service.ts index 465a257dae..5ee104acca 100644 --- a/packages/nocodb/src/services/model-visibilities.service.ts +++ b/packages/nocodb/src/services/model-visibilities.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; import type { VisibilityRuleReqType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -11,17 +11,20 @@ import { Base, Model, ModelRoleVisibility, View } from '~/models'; export class ModelVisibilitiesService { constructor(private readonly appHooksService: AppHooksService) {} - async xcVisibilityMetaSetAll(param: { - visibilityRule: VisibilityRuleReqType; - baseId: string; - req: NcRequest; - }) { + async xcVisibilityMetaSetAll( + context: NcContext, + param: { + visibilityRule: VisibilityRuleReqType; + baseId: string; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/VisibilityRuleReq', param.visibilityRule, ); - const base = await Base.getWithInfo(param.baseId); + const base = await Base.getWithInfo(context, param.baseId); if (!base) { NcError.baseNotFound(param.baseId); @@ -29,28 +32,28 @@ export class ModelVisibilitiesService { for (const d of param.visibilityRule) { for (const role of Object.keys(d.disabled)) { - const view = await View.get(d.id); + const view = await View.get(context, d.id); if (view.base_id !== param.baseId) { NcError.badRequest('View does not belong to the base'); } - const dataInDb = await ModelRoleVisibility.get({ + const dataInDb = await ModelRoleVisibility.get(context, { role, fk_view_id: d.id, }); if (dataInDb) { if (d.disabled[role]) { if (!dataInDb.disabled) { - await ModelRoleVisibility.update(d.id, role, { + await ModelRoleVisibility.update(context, d.id, role, { disabled: d.disabled[role], }); } } else { - await dataInDb.delete(); + await dataInDb.delete(context); } } else if (d.disabled[role]) { - await ModelRoleVisibility.insert({ + await ModelRoleVisibility.insert(context, { fk_view_id: d.id, disabled: d.disabled[role], role, @@ -66,11 +69,14 @@ export class ModelVisibilitiesService { return true; } - async xcVisibilityMetaGet(param: { - baseId: string; - includeM2M?: boolean; - models?: Model[]; - }) { + async xcVisibilityMetaGet( + context: NcContext, + param: { + baseId: string; + includeM2M?: boolean; + models?: Model[]; + }, + ) { const { includeM2M = true, baseId, models: _models } = param ?? {}; // todo: move to @@ -87,7 +93,7 @@ export class ModelVisibilitiesService { let models = _models || - (await Model.list({ + (await Model.list(context, { base_id: baseId, source_id: undefined, })); @@ -97,7 +103,7 @@ export class ModelVisibilitiesService { const result = await models.reduce(async (_obj, model) => { const obj = await _obj; - const views = await model.getViews(); + const views = await model.getViews(context); for (const view of views) { obj[view.id] = { ptn: model.table_name, @@ -114,7 +120,7 @@ export class ModelVisibilitiesService { return obj; }, Promise.resolve({})); - const disabledList = await ModelRoleVisibility.list(baseId); + const disabledList = await ModelRoleVisibility.list(context, baseId); for (const d of disabledList) { if (result[d.fk_view_id]) diff --git a/packages/nocodb/src/services/notifications/notifications.service.ts b/packages/nocodb/src/services/notifications/notifications.service.ts index f800fb31e5..2ca6153b6d 100644 --- a/packages/nocodb/src/services/notifications/notifications.service.ts +++ b/packages/nocodb/src/services/notifications/notifications.service.ts @@ -131,7 +131,6 @@ export class NotificationsService implements OnModuleInit, OnModuleDestroy { ); } catch (e) { this.logger.error(e); - throw e; } } diff --git a/packages/nocodb/src/services/org-users.service.ts b/packages/nocodb/src/services/org-users.service.ts index fb8a27e04c..e0aae4fabd 100644 --- a/packages/nocodb/src/services/org-users.service.ts +++ b/packages/nocodb/src/services/org-users.service.ts @@ -16,10 +16,10 @@ import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; import { extractProps } from '~/helpers/extractProps'; import { randomTokenString } from '~/helpers/stringHelpers'; -import { BaseUser, Store, SyncSource, User } from '~/models'; +import { BaseUser, Store, User } from '~/models'; import Noco from '~/Noco'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; @Injectable() export class OrgUsersService { @@ -65,17 +65,27 @@ export class OrgUsersService { } // delete base user entry and assign to super admin + // TODO-TENANT: scope this to org const baseUsers = await BaseUser.getProjectsIdList(param.userId, ncMeta); // todo: clear cache // TODO: assign super admin as base owner for (const baseUser of baseUsers) { - await BaseUser.delete(baseUser.base_id, baseUser.fk_user_id, ncMeta); + await BaseUser.delete( + { + workspace_id: baseUser.fk_workspace_id, + base_id: baseUser.base_id, + }, + baseUser.base_id, + baseUser.fk_user_id, + ncMeta, + ); } // delete sync source entry - await SyncSource.deleteByUserId(param.userId, ncMeta); + // TODO-TENANT: ENABLE THIS & CONFIRM SCOPE + // await SyncSource.deleteByUserId(param.userId, ncMeta); // delete user await User.delete(param.userId, ncMeta); @@ -211,8 +221,8 @@ export class OrgUsersService { }); const pluginData = await Noco.ncMeta.metaGet2( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.PLUGIN, { category: PluginCategory.EMAIL, diff --git a/packages/nocodb/src/services/public-datas.service.ts b/packages/nocodb/src/services/public-datas.service.ts index 25a6d5e4f3..58c5d5dced 100644 --- a/packages/nocodb/src/services/public-datas.service.ts +++ b/packages/nocodb/src/services/public-datas.service.ts @@ -6,6 +6,7 @@ import slash from 'slash'; import { nocoExecute } from 'nc-help'; import type { LinkToAnotherRecordColumn } from '~/models'; +import type { NcContext } from '~/interface/config'; import { Column, Model, Source, View } from '~/models'; import { NcError } from '~/helpers/catchError'; import getAst from '~/helpers/getAst'; @@ -25,13 +26,16 @@ export function sanitizeUrlPath(paths) { @Injectable() export class PublicDatasService { - async dataList(param: { - sharedViewUuid: string; - password?: string; - query: any; - }) { + async dataList( + context: NcContext, + param: { + sharedViewUuid: string; + password?: string; + query: any; + }, + ) { const { sharedViewUuid, password, query = {} } = param; - const view = await View.getByUUID(sharedViewUuid); + const view = await View.getByUUID(context, sharedViewUuid); if (!view) NcError.viewNotFound(sharedViewUuid); if ( @@ -48,19 +52,19 @@ export class PublicDatasService { return NcError.invalidSharedViewPassword(); } - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id, }); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { ast, dependencyFields } = await getAst({ + const { ast, dependencyFields } = await getAst(context, { model, query: {}, view, @@ -93,13 +97,16 @@ export class PublicDatasService { } // todo: Handle the error case where view doesnt belong to model - async groupedDataList(param: { - sharedViewUuid: string; - password?: string; - query: any; - groupColumnId: string; - }) { - const view = await View.getByUUID(param.sharedViewUuid); + async groupedDataList( + context: NcContext, + param: { + sharedViewUuid: string; + password?: string; + query: any; + groupColumnId: string; + }, + ) { + const view = await View.getByUUID(context, param.sharedViewUuid); if (!view) NcError.viewNotFound(param.sharedViewUuid); @@ -115,11 +122,11 @@ export class PublicDatasService { return NcError.invalidSharedViewPassword(); } - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id, }); - return await this.getGroupedDataList({ + return await this.getGroupedDataList(context, { model, view, query: param.query, @@ -127,22 +134,25 @@ export class PublicDatasService { }); } - async getGroupedDataList(param: { - model: Model; - view: View; - query: any; - groupColumnId: string; - }) { + async getGroupedDataList( + context: NcContext, + param: { + model: Model; + view: View; + query: any; + groupColumnId: string; + }, + ) { const { model, view, query = {}, groupColumnId } = param; - const source = await Source.get(param.model.source_id); + const source = await Source.get(context, param.model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { ast } = await getAst({ model, query: param.query, view }); + const { ast } = await getAst(context, { model, query: param.query, view }); const listArgs: any = { ...query }; try { @@ -191,12 +201,15 @@ export class PublicDatasService { return data; } - async dataGroupBy(param: { - sharedViewUuid: string; - password?: string; - query: any; - }) { - const view = await View.getByUUID(param.sharedViewUuid); + async dataGroupBy( + context: NcContext, + param: { + sharedViewUuid: string; + password?: string; + query: any; + }, + ) { + const view = await View.getByUUID(context, param.sharedViewUuid); if (!view) NcError.viewNotFound(param.sharedViewUuid); @@ -208,20 +221,27 @@ export class PublicDatasService { return NcError.invalidSharedViewPassword(); } - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id, }); - return await this.getDataGroupBy({ model, view, query: param.query }); + return await this.getDataGroupBy(context, { + model, + view, + query: param.query, + }); } - async getDataGroupBy(param: { model: Model; view: View; query?: any }) { + async getDataGroupBy( + context: NcContext, + param: { model: Model; view: View; query?: any }, + ) { try { const { model, view, query = {} } = param; - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -249,14 +269,17 @@ export class PublicDatasService { } } - async dataInsert(param: { - sharedViewUuid: string; - password?: string; - body: any; - files: any[]; - siteUrl: string; - }) { - const view = await View.getByUUID(param.sharedViewUuid); + async dataInsert( + context: NcContext, + param: { + sharedViewUuid: string; + password?: string; + body: any; + files: any[]; + siteUrl: string; + }, + ) { + const view = await View.getByUUID(context, param.sharedViewUuid); if (!view) NcError.viewNotFound(param.sharedViewUuid); if (view.type !== ViewTypes.FORM) NcError.notFound(); @@ -265,23 +288,23 @@ export class PublicDatasService { return NcError.invalidSharedViewPassword(); } - const model = await Model.getByIdOrName({ + const model = await Model.getByIdOrName(context, { id: view?.fk_model_id, }); - const source = await Source.get(model.source_id); - const base = await source.getProject(); + const source = await Source.get(context, model.source_id); + const base = await source.getProject(context); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), }); - await view.getViewWithInfo(); - await view.getColumns(); - await view.getModelWithInfo(); - await view.model.getColumns(); + await view.getViewWithInfo(context); + await view.getColumns(context); + await view.getModelWithInfo(context); + await view.model.getColumns(context); const fields = (view.model.columns = view.columns .filter((c) => c.show) @@ -424,14 +447,17 @@ export class PublicDatasService { return await baseModel.nestedInsert(insertObject, null); } - async relDataList(param: { - query: any; - sharedViewUuid: string; - password?: string; - columnId: string; - rowData: Record; - }) { - const view = await View.getByUUID(param.sharedViewUuid); + async relDataList( + context: NcContext, + param: { + query: any; + sharedViewUuid: string; + password?: string; + columnId: string; + rowData: Record; + }, + ) { + const view = await View.getByUUID(context, param.sharedViewUuid); if (!view) NcError.viewNotFound(param.sharedViewUuid); @@ -443,22 +469,24 @@ export class PublicDatasService { NcError.invalidSharedViewPassword(); } - const column = await Column.get({ colId: param.columnId }); - const currentModel = await view.getModel(); - await currentModel.getColumns(); - const colOptions = await column.getColOptions(); + const column = await Column.get(context, { colId: param.columnId }); + const currentModel = await view.getModel(context); + await currentModel.getColumns(context); + const colOptions = await column.getColOptions( + context, + ); - const model = await colOptions.getRelatedTable(); + const model = await colOptions.getRelatedTable(context); - const source = await Source.get(model.source_id); + const source = await Source.get(context, model.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: model.id, viewId: colOptions.fk_target_view_id, dbDriver: await NcConnectionMgrv2.get(source), }); - const { ast, dependencyFields } = await getAst({ + const { ast, dependencyFields } = await getAst(context, { query: param.query, model, extractOnlyPrimaries: true, @@ -476,7 +504,9 @@ export class PublicDatasService { baseModel.readByPk, )( (column.meta?.enableConditions - ? await Filter.rootFilterListByLink({ columnId: param.columnId }) + ? await Filter.rootFilterListByLink(context, { + columnId: param.columnId, + }) : []) || [], ); @@ -501,14 +531,17 @@ export class PublicDatasService { return new PagedResponseImpl(data, { ...param.query, count }); } - async publicMmList(param: { - query: any; - sharedViewUuid: string; - password?: string; - columnId: string; - rowId: string; - }) { - const view = await View.getByUUID(param.sharedViewUuid); + async publicMmList( + context: NcContext, + param: { + query: any; + sharedViewUuid: string; + password?: string; + columnId: string; + rowId: string; + }, + ) { + const view = await View.getByUUID(context, param.sharedViewUuid); if (!view) NcError.viewNotFound(param.sharedViewUuid); if ( @@ -525,16 +558,17 @@ export class PublicDatasService { } const column = await getColumnByIdOrName( + context, param.columnId, - await view.getModel(), + await view.getModel(context), ); if (column.fk_model_id !== view.fk_model_id) NcError.badRequest("Column doesn't belongs to the model"); - const source = await Source.get(view.source_id); + const source = await Source.get(context, view.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: view.fk_model_id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), @@ -576,14 +610,17 @@ export class PublicDatasService { return new PagedResponseImpl(data, { ...param.query, count }); } - async publicHmList(param: { - query: any; - rowId: string; - sharedViewUuid: string; - password?: string; - columnId: string; - }) { - const view = await View.getByUUID(param.sharedViewUuid); + async publicHmList( + context: NcContext, + param: { + query: any; + rowId: string; + sharedViewUuid: string; + password?: string; + columnId: string; + }, + ) { + const view = await View.getByUUID(context, param.sharedViewUuid); if (!view) NcError.viewNotFound(param.sharedViewUuid); if ( @@ -600,16 +637,17 @@ export class PublicDatasService { } const column = await getColumnByIdOrName( + context, param.columnId, - await view.getModel(), + await view.getModel(context), ); if (column.fk_model_id !== view.fk_model_id) NcError.badRequest("Column doesn't belongs to the model"); - const source = await Source.get(view.source_id); + const source = await Source.get(context, view.source_id); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(context, { id: view.fk_model_id, viewId: view?.id, dbDriver: await NcConnectionMgrv2.get(source), diff --git a/packages/nocodb/src/services/public-metas.service.ts b/packages/nocodb/src/services/public-metas.service.ts index 02db9589ad..2cb080c65e 100644 --- a/packages/nocodb/src/services/public-metas.service.ts +++ b/packages/nocodb/src/services/public-metas.service.ts @@ -11,17 +11,21 @@ import type { LinkToAnotherRecordColumn, LookupColumn, } from '~/models'; +import type { NcContext } from '~/interface/config'; import { Base, BaseUser, Column, Model, Source, View } from '~/models'; import { NcError } from '~/helpers/catchError'; @Injectable() export class PublicMetasService { - async viewMetaGet(param: { sharedViewUuid: string; password: string }) { + async viewMetaGet( + context: NcContext, + param: { sharedViewUuid: string; password: string }, + ) { const view: View & { relatedMetas?: { [ket: string]: Model }; users?: { id: string; display_name: string; email: string }[]; client?: string; - } = await View.getByUUID(param.sharedViewUuid); + } = await View.getByUUID(context, param.sharedViewUuid); if (!view) NcError.viewNotFound(param.sharedViewUuid); @@ -29,15 +33,15 @@ export class PublicMetasService { NcError.invalidSharedViewPassword(); } - await view.getFilters(); - await view.getSorts(); + await view.getFilters(context); + await view.getSorts(context); - await view.getViewWithInfo(); - await view.getColumns(); - await view.getModelWithInfo(); - await view.model.getColumns(); + await view.getViewWithInfo(context); + await view.getColumns(context); + await view.getModelWithInfo(context); + await view.model.getColumns(context); - const source = await Source.get(view.model.source_id); + const source = await Source.get(context, view.model.source_id); view.client = source.type; // todo: return only required props @@ -93,7 +97,7 @@ export class PublicMetasService { // load related table metas for (const col of view.model.columns) { - await this.extractRelatedMetas({ col, relatedMetas }); + await this.extractRelatedMetas(context, { col, relatedMetas }); } view.relatedMetas = relatedMetas; @@ -103,7 +107,7 @@ export class PublicMetasService { (c) => c.uidt === UITypes.User || isCreatedOrLastModifiedByCol(c), ) ) { - const baseUsers = await BaseUser.getUsersList({ + const baseUsers = await BaseUser.getUsersList(context, { base_id: view.model.base_id, }); @@ -117,61 +121,78 @@ export class PublicMetasService { return view; } - private async extractRelatedMetas({ - col, - relatedMetas = {}, - }: { - col: Column; - relatedMetas: Record; - }) { + private async extractRelatedMetas( + context: NcContext, + { + col, + relatedMetas = {}, + }: { + col: Column; + relatedMetas: Record; + }, + ) { if (isLinksOrLTAR(col.uidt)) { - await this.extractLTARRelatedMetas({ - ltarColOption: await col.getColOptions(), + await this.extractLTARRelatedMetas(context, { + ltarColOption: await col.getColOptions( + context, + ), relatedMetas, }); } else if (UITypes.Lookup === col.uidt) { - await this.extractLookupRelatedMetas({ - lookupColOption: await col.getColOptions(), + await this.extractLookupRelatedMetas(context, { + lookupColOption: await col.getColOptions(context), relatedMetas, }); } } - private async extractLTARRelatedMetas({ - ltarColOption, - relatedMetas = {}, - }: { - ltarColOption: LinkToAnotherRecordColumn; - relatedMetas: { [key: string]: Model }; - }) { - relatedMetas[ltarColOption.fk_related_model_id] = await Model.getWithInfo({ - id: ltarColOption.fk_related_model_id, - }); + private async extractLTARRelatedMetas( + context: NcContext, + { + ltarColOption, + relatedMetas = {}, + }: { + ltarColOption: LinkToAnotherRecordColumn; + relatedMetas: { [key: string]: Model }; + }, + ) { + relatedMetas[ltarColOption.fk_related_model_id] = await Model.getWithInfo( + context, + { + id: ltarColOption.fk_related_model_id, + }, + ); if (ltarColOption.type === 'mm') { - relatedMetas[ltarColOption.fk_mm_model_id] = await Model.getWithInfo({ - id: ltarColOption.fk_mm_model_id, - }); + relatedMetas[ltarColOption.fk_mm_model_id] = await Model.getWithInfo( + context, + { + id: ltarColOption.fk_mm_model_id, + }, + ); } } - private async extractLookupRelatedMetas({ - lookupColOption, - relatedMetas = {}, - }: { - lookupColOption: LookupColumn; - relatedMetas: { [key: string]: Model }; - }) { - const relationCol = await Column.get({ + private async extractLookupRelatedMetas( + context: NcContext, + { + lookupColOption, + relatedMetas = {}, + }: { + lookupColOption: LookupColumn; + relatedMetas: { [key: string]: Model }; + }, + ) { + const relationCol = await Column.get(context, { colId: lookupColOption.fk_relation_column_id, }); - const lookedUpCol = await Column.get({ + const lookedUpCol = await Column.get(context, { colId: lookupColOption.fk_lookup_column_id, }); // extract meta for table which belongs the relation column // if not already extracted if (!relatedMetas[relationCol.fk_model_id]) { - relatedMetas[relationCol.fk_model_id] = await Model.getWithInfo({ + relatedMetas[relationCol.fk_model_id] = await Model.getWithInfo(context, { id: relationCol.fk_model_id, }); } @@ -179,20 +200,23 @@ export class PublicMetasService { // extract meta for table in which looked up column belongs // if not already extracted if (!relatedMetas[lookedUpCol.fk_model_id]) { - relatedMetas[lookedUpCol.fk_model_id] = await Model.getWithInfo({ + relatedMetas[lookedUpCol.fk_model_id] = await Model.getWithInfo(context, { id: lookedUpCol.fk_model_id, }); } // extract metas related to the looked up column - await this.extractRelatedMetas({ + await this.extractRelatedMetas(context, { col: lookedUpCol, relatedMetas, }); } - async publicSharedBaseGet(param: { sharedBaseUuid: string }): Promise { - const base = await Base.getByUuid(param.sharedBaseUuid); + async publicSharedBaseGet( + context: NcContext, + param: { sharedBaseUuid: string }, + ): Promise { + const base = await Base.getByUuid(context, param.sharedBaseUuid); if (!base) { NcError.baseNotFound(param.sharedBaseUuid); diff --git a/packages/nocodb/src/services/shared-bases.service.ts b/packages/nocodb/src/services/shared-bases.service.ts index a6bfe878fc..05eba5fc97 100644 --- a/packages/nocodb/src/services/shared-bases.service.ts +++ b/packages/nocodb/src/services/shared-bases.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; import { v4 as uuidv4 } from 'uuid'; import { ConfigService } from '@nestjs/config'; -import type { AppConfig, NcRequest } from '~/interface/config'; +import type { AppConfig, NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -20,17 +20,20 @@ export class SharedBasesService { private configService: ConfigService, ) {} - async createSharedBaseLink(param: { - baseId: string; - roles: string; - password: string; - siteUrl: string; - - req: NcRequest; - }): Promise { + async createSharedBaseLink( + context: NcContext, + param: { + baseId: string; + roles: string; + password: string; + siteUrl: string; + + req: NcRequest; + }, + ): Promise { validatePayload('swagger.json#/components/schemas/SharedBaseReq', param); - const base = await Base.get(param.baseId); + const base = await Base.get(context, param.baseId); let roles = param?.roles; if (!roles || (roles !== 'editor' && roles !== 'viewer')) { @@ -51,7 +54,7 @@ export class SharedBasesService { roles, }; - await Base.update(base.id, data); + await Base.update(context, base.id, data); data.url = this.getUrl({ base, @@ -69,16 +72,19 @@ export class SharedBasesService { return data; } - async updateSharedBaseLink(param: { - baseId: string; - roles: string; - password: string; - siteUrl: string; - req: NcRequest; - }): Promise { + async updateSharedBaseLink( + context: NcContext, + param: { + baseId: string; + roles: string; + password: string; + siteUrl: string; + req: NcRequest; + }, + ): Promise { validatePayload('swagger.json#/components/schemas/SharedBaseReq', param); - const base = await Base.get(param.baseId); + const base = await Base.get(context, param.baseId); let roles = param.roles; if (!roles || (roles !== 'editor' && roles !== 'viewer')) { @@ -99,7 +105,7 @@ export class SharedBasesService { roles, }; - await Base.update(base.id, data); + await Base.update(context, base.id, data); data.url = this.getUrl({ base, @@ -130,11 +136,14 @@ export class SharedBasesService { return `${siteUrl}${config.dashboardPath}#/base/${base.uuid}`; } - async disableSharedBaseLink(param: { - baseId: string; - req: NcRequest; - }): Promise { - const base = await Base.get(param.baseId); + async disableSharedBaseLink( + context: NcContext, + param: { + baseId: string; + req: NcRequest; + }, + ): Promise { + const base = await Base.get(context, param.baseId); if (!base) { NcError.baseNotFound(param.baseId); @@ -143,7 +152,7 @@ export class SharedBasesService { uuid: null, }; - await Base.update(base.id, data); + await Base.update(context, base.id, data); this.appHooksService.emit(AppEvents.SHARED_BASE_DELETE_LINK, { base, @@ -152,11 +161,14 @@ export class SharedBasesService { return { uuid: null }; } - async getSharedBaseLink(param: { - baseId: string; - siteUrl: string; - }): Promise { - const base = await Base.get(param.baseId); + async getSharedBaseLink( + context: NcContext, + param: { + baseId: string; + siteUrl: string; + }, + ): Promise { + const base = await Base.get(context, param.baseId); if (!base) { NcError.baseNotFound(param.baseId); diff --git a/packages/nocodb/src/services/sorts.service.ts b/packages/nocodb/src/services/sorts.service.ts index 1443dc4826..0c66b29b06 100644 --- a/packages/nocodb/src/services/sorts.service.ts +++ b/packages/nocodb/src/services/sorts.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; import type { SortReqType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; @@ -11,18 +11,21 @@ import { Sort } from '~/models'; export class SortsService { constructor(protected readonly appHooksService: AppHooksService) {} - async sortGet(param: { sortId: string }) { - return Sort.get(param.sortId); + async sortGet(context: NcContext, param: { sortId: string }) { + return Sort.get(context, param.sortId); } - async sortDelete(param: { sortId: string; req: NcRequest }) { - const sort = await Sort.get(param.sortId); + async sortDelete( + context: NcContext, + param: { sortId: string; req: NcRequest }, + ) { + const sort = await Sort.get(context, param.sortId); if (!sort) { NcError.badRequest('Sort not found'); } - await Sort.delete(param.sortId); + await Sort.delete(context, param.sortId); this.appHooksService.emit(AppEvents.SORT_CREATE, { sort, @@ -31,16 +34,19 @@ export class SortsService { return true; } - async sortUpdate(param: { sortId: any; sort: SortReqType; req: NcRequest }) { + async sortUpdate( + context: NcContext, + param: { sortId: any; sort: SortReqType; req: NcRequest }, + ) { validatePayload('swagger.json#/components/schemas/SortReq', param.sort); - const sort = await Sort.get(param.sortId); + const sort = await Sort.get(context, param.sortId); if (!sort) { NcError.badRequest('Sort not found'); } - const res = await Sort.update(param.sortId, param.sort); + const res = await Sort.update(context, param.sortId, param.sort); this.appHooksService.emit(AppEvents.SORT_UPDATE, { sort, @@ -51,10 +57,13 @@ export class SortsService { return res; } - async sortCreate(param: { viewId: any; sort: SortReqType; req: NcRequest }) { + async sortCreate( + context: NcContext, + param: { viewId: any; sort: SortReqType; req: NcRequest }, + ) { validatePayload('swagger.json#/components/schemas/SortReq', param.sort); - const sort = await Sort.insert({ + const sort = await Sort.insert(context, { ...param.sort, fk_view_id: param.viewId, } as Sort); @@ -67,7 +76,7 @@ export class SortsService { return sort; } - async sortList(param: { viewId: string }) { - return Sort.list({ viewId: param.viewId }); + async sortList(context: NcContext, param: { viewId: string }) { + return Sort.list(context, { viewId: param.viewId }); } } diff --git a/packages/nocodb/src/services/sources.service.ts b/packages/nocodb/src/services/sources.service.ts index bc9ec7c4b0..9b9e08da5d 100644 --- a/packages/nocodb/src/services/sources.service.ts +++ b/packages/nocodb/src/services/sources.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; import type { BaseReqType } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { populateMeta, validatePayload } from '~/helpers'; import { populateRollupColumnAndHideLTAR } from '~/helpers/populateMeta'; @@ -13,25 +13,28 @@ import { NcError } from '~/helpers/catchError'; export class SourcesService { constructor(protected readonly appHooksService: AppHooksService) {} - async baseGetWithConfig(param: { sourceId: any }) { - const source = await Source.get(param.sourceId); + async baseGetWithConfig(context: NcContext, param: { sourceId: any }) { + const source = await Source.get(context, param.sourceId); source.config = await source.getConnectionConfig(); return source; } - async baseUpdate(param: { - sourceId: string; - source: BaseReqType; - baseId: string; - req: NcRequest; - }) { + async baseUpdate( + context: NcContext, + param: { + sourceId: string; + source: BaseReqType; + baseId: string; + req: NcRequest; + }, + ) { validatePayload('swagger.json#/components/schemas/BaseReq', param.source); const baseBody = param.source; - const base = await Base.getWithInfo(param.baseId); - const source = await Source.updateBase(param.sourceId, { + const base = await Base.getWithInfo(context, param.baseId); + const source = await Source.updateBase(context, param.sourceId, { ...baseBody, type: baseBody.config?.client, baseId: base.id, @@ -48,16 +51,16 @@ export class SourcesService { return source; } - async baseList(param: { baseId: string }) { - const sources = await Source.list({ baseId: param.baseId }); + async baseList(context: NcContext, param: { baseId: string }) { + const sources = await Source.list(context, { baseId: param.baseId }); return sources; } - async baseDelete(param: { sourceId: string; req: NcRequest }) { + async baseDelete(context: NcContext, param: { sourceId: string; req: any }) { try { - const source = await Source.get(param.sourceId, true); - await source.delete(); + const source = await Source.get(context, param.sourceId, true); + await source.delete(context); this.appHooksService.emit(AppEvents.BASE_DELETE, { source, req: param.req, @@ -68,22 +71,25 @@ export class SourcesService { return true; } - async baseSoftDelete(param: { sourceId: string }) { + async baseSoftDelete(context: NcContext, param: { sourceId: string }) { try { - const source = await Source.get(param.sourceId); - await source.softDelete(); + const source = await Source.get(context, param.sourceId); + await source.softDelete(context); } catch (e) { NcError.badRequest(e); } return true; } - async baseCreate(param: { - baseId: string; - source: BaseReqType; - logger?: (message: string) => void; - req: NcRequest; - }): Promise<{ + async baseCreate( + context: NcContext, + param: { + baseId: string; + source: BaseReqType; + logger?: (message: string) => void; + req: any; + }, + ): Promise<{ source: Source; error?: any; }> { @@ -91,13 +97,13 @@ export class SourcesService { // type | base | baseId const baseBody = param.source; - const base = await Base.getWithInfo(param.baseId); + const base = await Base.getWithInfo(context, param.baseId); let error; param.logger?.('Creating the source'); - const source = await Source.createBase({ + const source = await Source.createBase(context, { ...baseBody, type: baseBody.config?.client, baseId: base.id, @@ -108,9 +114,9 @@ export class SourcesService { param.logger?.('Populating meta'); - const info = await populateMeta(source, base, param.logger); + const info = await populateMeta(context, source, base, param.logger); - await populateRollupColumnAndHideLTAR(source, base); + await populateRollupColumnAndHideLTAR(context, source, base); this.appHooksService.emit(AppEvents.APIS_CREATED, { info, diff --git a/packages/nocodb/src/services/sql-views.service.ts b/packages/nocodb/src/services/sql-views.service.ts index 962a5c00c2..a942701b72 100644 --- a/packages/nocodb/src/services/sql-views.service.ts +++ b/packages/nocodb/src/services/sql-views.service.ts @@ -6,6 +6,7 @@ import { } from 'nocodb-sdk'; import DOMPurify from 'isomorphic-dompurify'; import type { UserType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import { NcError } from '~/helpers/catchError'; import getTableNameAlias, { getColumnNameAlias } from '~/helpers/getTableName'; import ProjectMgrv2 from '~/db/sql-mgr/v2/ProjectMgrv2'; @@ -16,22 +17,25 @@ import { Audit, Base, Column, Model } from '~/models'; @Injectable() export class SqlViewsService { - async sqlViewCreate(param: { - clientIp: string; - baseId: string; - sourceId: string; - body: { - view_name: string; - title: string; - view_definition?: string; - }; - user: UserType; - }) { + async sqlViewCreate( + context: NcContext, + param: { + clientIp: string; + baseId: string; + sourceId: string; + body: { + view_name: string; + title: string; + view_definition?: string; + }; + user: UserType; + }, + ) { NcError.notImplemented(); return; const body = { ...param.body }; - const base = await Base.getWithInfo(param.baseId); + const base = await Base.getWithInfo(context, param.baseId); let source = base.sources[0]; if (param.sourceId) { @@ -60,7 +64,7 @@ export class SqlViewsService { } if ( - !(await Model.checkTitleAvailable({ + !(await Model.checkTitleAvailable(context, { table_name: body.view_name, base_id: base.id, source_id: source.id, @@ -74,7 +78,7 @@ export class SqlViewsService { } if ( - !(await Model.checkAliasAvailable({ + !(await Model.checkAliasAvailable(context, { title: body.title, base_id: base.id, source_id: source.id, @@ -83,7 +87,7 @@ export class SqlViewsService { NcError.badRequest('Duplicate table alias'); } - const sqlMgr = await ProjectMgrv2.getSqlMgr(base); + const sqlMgr = await ProjectMgrv2.getSqlMgr(context, base); const sqlClient = await NcConnectionMgrv2.getSqlClient(source); @@ -121,7 +125,7 @@ export class SqlViewsService { }) )?.data?.list; - const tables = await Model.list({ + const tables = await Model.list(context, { base_id: base.id, source_id: source.id, }); @@ -138,7 +142,7 @@ export class SqlViewsService { mapDefaultDisplayValue(columns); - const model = await Model.insert(base.id, source.id, { + const model = await Model.insert(context, base.id, source.id, { table_name: body.view_name, title: getTableNameAlias(body.view_name, base.prefix, source), type: ModelTypes.VIEW, @@ -148,7 +152,7 @@ export class SqlViewsService { let colOrder = 1; for (const column of columns) { - await Column.insert({ + await Column.insert(context, { fk_model_id: model.id, ...column, title: getColumnNameAlias(column.cn, source), @@ -157,6 +161,6 @@ export class SqlViewsService { }); } - return await Model.get(model.id); + return await Model.get(context, model.id); } } diff --git a/packages/nocodb/src/services/sync.service.ts b/packages/nocodb/src/services/sync.service.ts index 19ce24a740..db97de304e 100644 --- a/packages/nocodb/src/services/sync.service.ts +++ b/packages/nocodb/src/services/sync.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; import { AppEvents } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { NcError } from '~/helpers/catchError'; import { PagedResponseImpl } from '~/helpers/PagedResponse'; @@ -10,22 +10,28 @@ import { Base, SyncSource } from '~/models'; export class SyncService { constructor(private readonly appHooksService: AppHooksService) {} - async syncSourceList(param: { baseId: string; sourceId?: string }) { + async syncSourceList( + context: NcContext, + param: { baseId: string; sourceId?: string }, + ) { return new PagedResponseImpl( - await SyncSource.list(param.baseId, param.sourceId), + await SyncSource.list(context, param.baseId, param.sourceId), ); } - async syncCreate(param: { - baseId: string; - sourceId?: string; - userId: string; - syncPayload: Partial; - req: NcRequest; - }) { - const base = await Base.getWithInfo(param.baseId); - - const sync = await SyncSource.insert({ + async syncCreate( + context: NcContext, + param: { + baseId: string; + sourceId?: string; + userId: string; + syncPayload: Partial; + req: NcRequest; + }, + ) { + const base = await Base.getWithInfo(context, param.baseId); + + const sync = await SyncSource.insert(context, { ...param.syncPayload, fk_user_id: param.userId, source_id: param.sourceId ? param.sourceId : base.sources[0].id, @@ -40,14 +46,17 @@ export class SyncService { return sync; } - async syncDelete(param: { syncId: string; req: NcRequest }) { - const syncSource = await SyncSource.get(param.syncId); + async syncDelete( + context: NcContext, + param: { syncId: string; req: NcRequest }, + ) { + const syncSource = await SyncSource.get(context, param.syncId); if (!syncSource) { NcError.badRequest('Sync source not found'); } - const res = await SyncSource.delete(param.syncId); + const res = await SyncSource.delete(context, param.syncId); this.appHooksService.emit(AppEvents.SYNC_SOURCE_DELETE, { syncSource, @@ -56,18 +65,25 @@ export class SyncService { return res; } - async syncUpdate(param: { - syncId: string; - syncPayload: Partial; - req: NcRequest; - }) { - const syncSource = await SyncSource.get(param.syncId); + async syncUpdate( + context: NcContext, + param: { + syncId: string; + syncPayload: Partial; + req: NcRequest; + }, + ) { + const syncSource = await SyncSource.get(context, param.syncId); if (!syncSource) { NcError.badRequest('Sync source not found'); } - const res = await SyncSource.update(param.syncId, param.syncPayload); + const res = await SyncSource.update( + context, + param.syncId, + param.syncPayload, + ); this.appHooksService.emit(AppEvents.SYNC_SOURCE_UPDATE, { syncSource, diff --git a/packages/nocodb/src/services/tables.service.ts b/packages/nocodb/src/services/tables.service.ts index abb45e87e9..4e7f733518 100644 --- a/packages/nocodb/src/services/tables.service.ts +++ b/packages/nocodb/src/services/tables.service.ts @@ -21,7 +21,7 @@ import type { } from 'nocodb-sdk'; import type { MetaService } from '~/meta/meta.service'; import type { LinkToAnotherRecordColumn, User, View } from '~/models'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { Base, Column, Model, ModelRoleVisibility } from '~/models'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import ProjectMgrv2 from '~/db/sql-mgr/v2/ProjectMgrv2'; @@ -46,16 +46,22 @@ export class TablesService { protected readonly columnsService: ColumnsService, ) {} - async tableUpdate(param: { - tableId: any; - table: TableReqType & { base_id?: string }; - baseId?: string; - user: UserType; - req: NcRequest; - }) { - const model = await Model.get(param.tableId); + async tableUpdate( + context: NcContext, + param: { + tableId: any; + table: TableReqType & { base_id?: string }; + baseId?: string; + user: UserType; + req: NcRequest; + }, + ) { + const model = await Model.get(context, param.tableId); - const base = await Base.getWithInfo(param.table.base_id || param.baseId); + const base = await Base.getWithInfo( + context, + param.table.base_id || param.baseId, + ); const source = base.sources.find((b) => b.id === model.source_id); if (model.base_id !== base.id) { @@ -65,7 +71,7 @@ export class TablesService { // if meta present update meta and return // todo: allow user to update meta and other prop in single api call if ('meta' in param.table) { - await Model.updateMeta(param.tableId, param.table.meta); + await Model.updateMeta(context, param.tableId, param.table.meta); return true; } @@ -98,7 +104,7 @@ export class TablesService { } if ( - !(await Model.checkTitleAvailable({ + !(await Model.checkTitleAvailable(context, { table_name: param.table.table_name, base_id: base.id, source_id: source.id, @@ -116,7 +122,7 @@ export class TablesService { } if ( - !(await Model.checkAliasAvailable({ + !(await Model.checkAliasAvailable(context, { title: param.table.title, base_id: base.id, source_id: source.id, @@ -125,7 +131,7 @@ export class TablesService { NcError.badRequest('Duplicate table alias'); } - const sqlMgr = await ProjectMgrv2.getSqlMgr(base); + const sqlMgr = await ProjectMgrv2.getSqlMgr(context, base); const sqlClient = await NcConnectionMgrv2.getSqlClient(source); let tableNameLengthLimit = 255; @@ -152,6 +158,7 @@ export class TablesService { }); await Model.updateAliasAndTableName( + context, param.tableId, param.table.title, param.table.table_name, @@ -166,21 +173,24 @@ export class TablesService { return true; } - reorderTable(param: { tableId: string; order: any }) { - return Model.updateOrder(param.tableId, param.order); + reorderTable(context: NcContext, param: { tableId: string; order: any }) { + return Model.updateOrder(context, param.tableId, param.order); } - async tableDelete(param: { - tableId: string; - user: User; - forceDeleteRelations?: boolean; - req?: any; - }) { - const table = await Model.getByIdOrName({ id: param.tableId }); - await table.getColumns(); + async tableDelete( + context: NcContext, + param: { + tableId: string; + user: User; + forceDeleteRelations?: boolean; + req?: any; + }, + ) { + const table = await Model.getByIdOrName(context, { id: param.tableId }); + await table.getColumns(context); if (table.mm) { - const columns = await table.getColumns(); + const columns = await table.getColumns(context); // get table names of the relation which uses the current table as junction table const tables = await Promise.all( @@ -192,7 +202,7 @@ export class TablesService { // get relation column names const relColumns = await Promise.all( tables.map((t) => { - return t.getColumns().then((cols) => { + return t.getColumns(context).then((cols) => { return cols.find((c) => { return ( isLinksOrLTAR(c) && @@ -211,7 +221,7 @@ export class TablesService { ); } - const base = await Base.getWithInfo(table.base_id); + const base = await Base.getWithInfo(context, table.base_id); const source = base.sources.find((b) => b.id === table.source_id); const relationColumns = table.columns.filter((c) => isLinksOrLTAR(c)); @@ -222,8 +232,8 @@ export class TablesService { const referredTables = await Promise.all( relationColumns.map(async (c) => c - .getColOptions() - .then((opt) => opt.getRelatedTable()) + .getColOptions(context) + .then((opt) => opt.getRelatedTable(context)) .then(), ), ); @@ -246,11 +256,12 @@ export class TablesService { } // verify column exist or not and based on that delete the column - if (!(await Column.get({ colId: c.id }, ncMeta))) { + if (!(await Column.get(context, { colId: c.id }, ncMeta))) { continue; } await this.columnsService.columnDelete( + context, { req: param.req, columnId: c.id, @@ -261,7 +272,7 @@ export class TablesService { ); } - const sqlMgr = await ProjectMgrv2.getSqlMgr(base, ncMeta); + const sqlMgr = await ProjectMgrv2.getSqlMgr(context, base, ncMeta); (table as any).tn = table.table_name; table.columns = table.columns.filter((c) => !isVirtualCol(c)); table.columns.forEach((c) => { @@ -284,7 +295,7 @@ export class TablesService { req: param.req, }); - result = await table.delete(ncMeta); + result = await table.delete(context, ncMeta); await ncMeta.commit(); } catch (e) { await ncMeta.rollback(); @@ -293,11 +304,14 @@ export class TablesService { return result; } - async getTableWithAccessibleViews(param: { - tableId: string; - user: User | UserType; - }) { - const table = await Model.getWithInfo({ + async getTableWithAccessibleViews( + context: NcContext, + param: { + tableId: string; + user: User | UserType; + }, + ) { + const table = await Model.getWithInfo(context, { id: param.tableId, }); @@ -307,7 +321,7 @@ export class TablesService { // todo: optimise const viewList = ( - await this.xcVisibilityMetaGet(table.base_id, [table]) + await this.xcVisibilityMetaGet(context, table.base_id, [table]) ); //await View.list(param.tableId) @@ -321,6 +335,7 @@ export class TablesService { } async xcVisibilityMetaGet( + context: NcContext, baseId, _models: Model[] = null, includeM2M = true, @@ -340,7 +355,7 @@ export class TablesService { let models = _models || - (await Model.list({ + (await Model.list(context, { base_id: baseId, source_id: undefined, })); @@ -350,7 +365,7 @@ export class TablesService { const result = await models.reduce(async (_obj, model) => { const obj = await _obj; - const views = await model.getViews(); + const views = await model.getViews(context); for (const view of views) { obj[view.id] = { ptn: model.table_name, @@ -367,7 +382,7 @@ export class TablesService { return obj; }, Promise.resolve({})); - const disabledList = await ModelRoleVisibility.list(baseId); + const disabledList = await ModelRoleVisibility.list(context, baseId); for (const d of disabledList) { if (result[d.fk_view_id]) @@ -377,13 +392,16 @@ export class TablesService { return Object.values(result); } - async getAccessibleTables(param: { - baseId: string; - sourceId: string; - includeM2M?: boolean; - roles: Record; - }) { - const viewList = await this.xcVisibilityMetaGet(param.baseId); + async getAccessibleTables( + context: NcContext, + param: { + baseId: string; + sourceId: string; + includeM2M?: boolean; + roles: Record; + }, + ) { + const viewList = await this.xcVisibilityMetaGet(context, param.baseId); // todo: optimise const tableViewMapping = viewList.reduce((o, view: any) => { @@ -399,7 +417,7 @@ export class TablesService { }, {}); const tableList = ( - await Model.list({ + await Model.list(context, { base_id: param.baseId, source_id: param.sourceId, }) @@ -410,13 +428,16 @@ export class TablesService { : (tableList.filter((t) => !t.mm) as Model[]); } - async tableCreate(param: { - baseId: string; - sourceId?: string; - table: TableReqType; - user: User | UserType; - req?: any; - }) { + async tableCreate( + context: NcContext, + param: { + baseId: string; + sourceId?: string; + table: TableReqType; + user: User | UserType; + req?: any; + }, + ) { validatePayload('swagger.json#/components/schemas/TableReq', param.table); const tableCreatePayLoad: Omit & { @@ -425,7 +446,7 @@ export class TablesService { ...param.table, }; - const base = await Base.getWithInfo(param.baseId); + const base = await Base.getWithInfo(context, param.baseId); let source = base.sources[0]; if (param.sourceId) { @@ -542,7 +563,7 @@ export class TablesService { } if ( - !(await Model.checkTitleAvailable({ + !(await Model.checkTitleAvailable(context, { table_name: tableCreatePayLoad.table_name, base_id: base.id, source_id: source.id, @@ -560,7 +581,7 @@ export class TablesService { } if ( - !(await Model.checkAliasAvailable({ + !(await Model.checkAliasAvailable(context, { title: tableCreatePayLoad.title, base_id: base.id, source_id: source.id, @@ -569,7 +590,7 @@ export class TablesService { NcError.badRequest('Duplicate table alias'); } - const sqlMgr = await ProjectMgrv2.getSqlMgr(base); + const sqlMgr = await ProjectMgrv2.getSqlMgr(context, base); const sqlClient = await NcConnectionMgrv2.getSqlClient(source); @@ -669,13 +690,13 @@ export class TablesService { )?.data?.list; } - const tables = await Model.list({ + const tables = await Model.list(context, { base_id: base.id, source_id: source.id, }); // todo: type correction - const result = await Model.insert(base.id, source.id, { + const result = await Model.insert(context, base.id, source.id, { ...tableCreatePayLoad, columns: tableCreatePayLoad.columns.map((c, i) => { const colMetaFromDb = columns?.find((c1) => c.cn === c1.cn); diff --git a/packages/nocodb/src/services/users/users.service.ts b/packages/nocodb/src/services/users/users.service.ts index 54dfaff6e8..c9c2e68de7 100644 --- a/packages/nocodb/src/services/users/users.service.ts +++ b/packages/nocodb/src/services/users/users.service.ts @@ -19,7 +19,7 @@ import { NC_APP_SETTINGS } from '~/constants'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { MetaService } from '~/meta/meta.service'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; import Noco from '~/Noco'; import { Store, User, UserRefreshToken } from '~/models'; import { randomTokenString } from '~/helpers/stringHelpers'; @@ -49,9 +49,14 @@ export class UsersService { async findOne(_email: string) { const email = _email.toLowerCase(); - const user = await this.metaService.metaGet(null, null, MetaTable.USERS, { - email, - }); + const user = await this.metaService.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + { + email, + }, + ); return user; } @@ -66,10 +71,15 @@ export class UsersService { email: string; lastname: any; }) { - return this.metaService.metaInsert2(null, null, MetaTable.USERS, { - ...param, - email: param.email?.toLowerCase(), - }); + return this.metaService.metaInsert2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + { + ...param, + email: param.email?.toLowerCase(), + }, + ); } async profileUpdate({ @@ -263,9 +273,14 @@ export class UsersService { async tokenValidate(param: { token: string }): Promise { const token = param.token; - const user = await Noco.ncMeta.metaGet(null, null, MetaTable.USERS, { - reset_password_token: token, - }); + const user = await Noco.ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + { + reset_password_token: token, + }, + ); if (!user || !user.email) { NcError.badRequest('Invalid reset url'); @@ -289,9 +304,14 @@ export class UsersService { const { token, body } = param; - const user = await Noco.ncMeta.metaGet(null, null, MetaTable.USERS, { - reset_password_token: token, - }); + const user = await Noco.ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + { + reset_password_token: token, + }, + ); if (!user) { NcError.badRequest('Invalid reset url'); @@ -337,9 +357,14 @@ export class UsersService { }): Promise { const { token, req } = param; - const user = await Noco.ncMeta.metaGet(null, null, MetaTable.USERS, { - email_verification_token: token, - }); + const user = await Noco.ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + { + email_verification_token: token, + }, + ); if (!user) { NcError.badRequest('Invalid verification url'); diff --git a/packages/nocodb/src/services/utils.service.ts b/packages/nocodb/src/services/utils.service.ts index 921d5714f6..823d306486 100644 --- a/packages/nocodb/src/services/utils.service.ts +++ b/packages/nocodb/src/services/utils.service.ts @@ -12,7 +12,7 @@ import { NcError } from '~/helpers/catchError'; import { Base, Store, User } from '~/models'; import Noco from '~/Noco'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; import { jdbcToXcConfig } from '~/utils/nc-config/helpers'; import { packageVersion } from '~/utils/packageVersion'; import { @@ -214,7 +214,7 @@ export class UtilsService { async aggregatedMetaInfo() { const [bases, userCount] = await Promise.all([ Base.list({}), - Noco.ncMeta.metaCount(null, null, MetaTable.USERS), + Noco.ncMeta.metaCount(RootScopes.ROOT, RootScopes.ROOT, MetaTable.USERS), ]); const result: AllMeta = { @@ -241,22 +241,32 @@ export class UtilsService { ] = this.extractResultOrNull( await Promise.allSettled([ // db tables count - Noco.ncMeta.metaCount(base.id, null, MetaTable.MODELS, { - condition: { - type: 'table', + Noco.ncMeta.metaCount( + base.fk_workspace_id, + base.id, + MetaTable.MODELS, + { + condition: { + type: 'table', + }, }, - }), + ), // db views count - Noco.ncMeta.metaCount(base.id, null, MetaTable.MODELS, { - condition: { - type: 'view', + Noco.ncMeta.metaCount( + base.fk_workspace_id, + base.id, + MetaTable.MODELS, + { + condition: { + type: 'view', + }, }, - }), + ), // views count (async () => { const views = await Noco.ncMeta.metaList2( + base.fk_workspace_id, base.id, - null, MetaTable.VIEWS, ); // grid, form, gallery, kanban and shared count @@ -305,11 +315,23 @@ export class UtilsService { ); })(), // webhooks count - Noco.ncMeta.metaCount(base.id, null, MetaTable.HOOKS), + Noco.ncMeta.metaCount( + base.fk_workspace_id, + base.id, + MetaTable.HOOKS, + ), // filters count - Noco.ncMeta.metaCount(base.id, null, MetaTable.FILTER_EXP), + Noco.ncMeta.metaCount( + base.fk_workspace_id, + base.id, + MetaTable.FILTER_EXP, + ), // sorts count - Noco.ncMeta.metaCount(base.id, null, MetaTable.SORT), + Noco.ncMeta.metaCount( + base.fk_workspace_id, + base.id, + MetaTable.SORT, + ), // row count per base base.getSources().then(async (sources) => { return this.extractResultOrNull( @@ -323,12 +345,17 @@ export class UtilsService { ); }), // base users count - Noco.ncMeta.metaCount(null, null, MetaTable.PROJECT_USERS, { - condition: { - base_id: base.id, + Noco.ncMeta.metaCount( + base.fk_workspace_id, + base.id, + MetaTable.PROJECT_USERS, + { + condition: { + base_id: base.id, + }, + aggField: '*', }, - aggField: '*', - }), + ), ]), ); diff --git a/packages/nocodb/src/services/view-columns.service.ts b/packages/nocodb/src/services/view-columns.service.ts index 56649d2b7b..4859bf5476 100644 --- a/packages/nocodb/src/services/view-columns.service.ts +++ b/packages/nocodb/src/services/view-columns.service.ts @@ -14,7 +14,7 @@ import type { ViewColumnReqType, ViewColumnUpdateReqType, } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { CalendarViewColumn, View } from '~/models'; @@ -25,21 +25,25 @@ import Noco from '~/Noco'; export class ViewColumnsService { constructor(private appHooksService: AppHooksService) {} - async columnList(param: { viewId: string }) { - return await View.getColumns(param.viewId, undefined); + async columnList(context: NcContext, param: { viewId: string }) { + return await View.getColumns(context, param.viewId, undefined); } - async columnAdd(param: { - viewId: string; - column: ViewColumnReqType; - req: NcRequest; - }) { + async columnAdd( + context: NcContext, + param: { + viewId: string; + column: ViewColumnReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewColumnReq', param.column, ); const viewColumn = await View.insertOrUpdateColumn( + context, param.viewId, param.column.fk_column_id, { @@ -55,18 +59,22 @@ export class ViewColumnsService { return viewColumn; } - async columnUpdate(param: { - viewId: string; - columnId: string; - column: ViewColumnUpdateReqType; - req: NcRequest; - }) { + async columnUpdate( + context: NcContext, + param: { + viewId: string; + columnId: string; + column: ViewColumnUpdateReqType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewColumnUpdateReq', param.column, ); const result = await View.updateColumn( + context, param.viewId, param.columnId, param.column, @@ -80,27 +88,30 @@ export class ViewColumnsService { return result; } - async columnsUpdate(param: { - viewId: string; - columns: - | GridColumnReqType - | GalleryColumnReqType - | KanbanColumnReqType - | FormColumnReqType - | CalendarColumnReqType[] - | Record< - APIContext.VIEW_COLUMNS, - Record< - string, - | GridColumnReqType - | GalleryColumnReqType - | KanbanColumnReqType - | FormColumnReqType - | CalendarColumnReqType - > - >; - req: any; - }) { + async columnsUpdate( + context: NcContext, + param: { + viewId: string; + columns: + | GridColumnReqType + | GalleryColumnReqType + | KanbanColumnReqType + | FormColumnReqType + | CalendarColumnReqType[] + | Record< + APIContext.VIEW_COLUMNS, + Record< + string, + | GridColumnReqType + | GalleryColumnReqType + | KanbanColumnReqType + | FormColumnReqType + | CalendarColumnReqType + > + >; + req: any; + }, + ) { const { viewId } = param; const columns = Array.isArray(param.columns) @@ -111,7 +122,7 @@ export class ViewColumnsService { NcError.badRequest('Invalid request - fields not found'); } - const view = await View.get(viewId); + const view = await View.get(context, viewId); const updateOrInsertOptions: Promise[] = []; @@ -130,10 +141,15 @@ export class ViewColumnsService { const columnId = typeof param.columns === 'object' ? indexOrId : column['id']; - const existingCol = await ncMeta.metaGet2(null, null, table, { - fk_view_id: viewId, - fk_column_id: columnId, - }); + const existingCol = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + table, + { + fk_view_id: viewId, + fk_column_id: columnId, + }, + ); switch (view.type) { case ViewTypes.GRID: @@ -143,11 +159,12 @@ export class ViewColumnsService { ); if (existingCol) { updateOrInsertOptions.push( - GridViewColumn.update(existingCol.id, column, ncMeta), + GridViewColumn.update(context, existingCol.id, column, ncMeta), ); } else { updateOrInsertOptions.push( GridViewColumn.insert( + context, { ...(column as GridColumnReqType), fk_view_id: viewId, @@ -165,11 +182,17 @@ export class ViewColumnsService { ); if (existingCol) { updateOrInsertOptions.push( - GalleryViewColumn.update(existingCol.id, column, ncMeta), + GalleryViewColumn.update( + context, + existingCol.id, + column, + ncMeta, + ), ); } else { updateOrInsertOptions.push( GalleryViewColumn.insert( + context, { ...(column as GalleryColumnReqType), fk_view_id: viewId, @@ -187,11 +210,17 @@ export class ViewColumnsService { ); if (existingCol) { updateOrInsertOptions.push( - KanbanViewColumn.update(existingCol.id, column, ncMeta), + KanbanViewColumn.update( + context, + existingCol.id, + column, + ncMeta, + ), ); } else { updateOrInsertOptions.push( KanbanViewColumn.insert( + context, { ...(column as KanbanColumnReqType), fk_view_id: viewId, @@ -209,11 +238,12 @@ export class ViewColumnsService { ); if (existingCol) { updateOrInsertOptions.push( - MapViewColumn.update(existingCol.id, column, ncMeta), + MapViewColumn.update(context, existingCol.id, column, ncMeta), ); } else { updateOrInsertOptions.push( MapViewColumn.insert( + context, { ...(column as MapViewColumn), fk_view_id: viewId, @@ -231,11 +261,12 @@ export class ViewColumnsService { ); if (existingCol) { updateOrInsertOptions.push( - FormViewColumn.update(existingCol.id, column, ncMeta), + FormViewColumn.update(context, existingCol.id, column, ncMeta), ); } else { updateOrInsertOptions.push( FormViewColumn.insert( + context, { ...(column as FormColumnReqType), fk_view_id: viewId, @@ -253,11 +284,17 @@ export class ViewColumnsService { ); if (existingCol) { updateOrInsertOptions.push( - CalendarViewColumn.update(existingCol.id, column, ncMeta), + CalendarViewColumn.update( + context, + existingCol.id, + column, + ncMeta, + ), ); } else { updateOrInsertOptions.push( CalendarViewColumn.insert( + context, { ...(column as CalendarColumnReqType), fk_view_id: viewId, @@ -275,7 +312,7 @@ export class ViewColumnsService { await ncMeta.commit(); - await View.clearSingleQueryCache(view.fk_model_id, [view]); + await View.clearSingleQueryCache(context, view.fk_model_id, [view]); return result; } catch (e) { @@ -284,8 +321,11 @@ export class ViewColumnsService { } } - async viewColumnList(param: { viewId: string; req: any }) { - const columnList = await View.getColumns(param.viewId, undefined); + async viewColumnList( + context: NcContext, + param: { viewId: string; req: any }, + ) { + const columnList = await View.getColumns(context, param.viewId, undefined); // generate key-value pair of column id and column const columnMap = columnList.reduce((acc, column) => { diff --git a/packages/nocodb/src/services/views.service.ts b/packages/nocodb/src/services/views.service.ts index 3b2aa9ea8c..5d55bded25 100644 --- a/packages/nocodb/src/services/views.service.ts +++ b/packages/nocodb/src/services/views.service.ts @@ -5,18 +5,21 @@ import type { UserType, ViewUpdateReqType, } from 'nocodb-sdk'; -import type { NcRequest } from '~/interface/config'; +import type { NcContext, NcRequest } from '~/interface/config'; import { AppHooksService } from '~/services/app-hooks/app-hooks.service'; import { validatePayload } from '~/helpers'; import { NcError } from '~/helpers/catchError'; import { Model, ModelRoleVisibility, View } from '~/models'; // todo: move -async function xcVisibilityMetaGet(param: { - baseId: string; - includeM2M?: boolean; - models?: Model[]; -}) { +async function xcVisibilityMetaGet( + context: NcContext, + param: { + baseId: string; + includeM2M?: boolean; + models?: Model[]; + }, +) { const { includeM2M = true, baseId, models: _models } = param ?? {}; // todo: move to @@ -26,7 +29,7 @@ async function xcVisibilityMetaGet(param: { let models = _models || - (await Model.list({ + (await Model.list(context, { base_id: baseId, source_id: undefined, })); @@ -36,7 +39,7 @@ async function xcVisibilityMetaGet(param: { const result = await models.reduce(async (_obj, model) => { const obj = await _obj; - const views = await model.getViews(); + const views = await model.getViews(context); for (const view of views) { obj[view.id] = { ptn: model.table_name, @@ -53,7 +56,7 @@ async function xcVisibilityMetaGet(param: { return obj; }, Promise.resolve({})); - const disabledList = await ModelRoleVisibility.list(baseId); + const disabledList = await ModelRoleVisibility.list(context, baseId); for (const d of disabledList) { if (result[d.fk_view_id]) @@ -67,20 +70,23 @@ async function xcVisibilityMetaGet(param: { export class ViewsService { constructor(private appHooksService: AppHooksService) {} - async viewList(param: { - tableId: string; - user: { - roles?: Record | string; - base_roles?: Record; - }; - }) { - const model = await Model.get(param.tableId); + async viewList( + context: NcContext, + param: { + tableId: string; + user: { + roles?: Record | string; + base_roles?: Record; + }; + }, + ) { + const model = await Model.get(context, param.tableId); if (!model) { NcError.tableNotFound(param.tableId); } - const viewList = await xcVisibilityMetaGet({ + const viewList = await xcVisibilityMetaGet(context, { baseId: model.base_id, models: [model], }); @@ -96,10 +102,13 @@ export class ViewsService { return filteredViewList; } - async shareView(param: { viewId: string; user: UserType; req: NcRequest }) { - const res = await View.share(param.viewId); + async shareView( + context: NcContext, + param: { viewId: string; user: UserType; req: NcRequest }, + ) { + const res = await View.share(context, param.viewId); - const view = await View.get(param.viewId); + const view = await View.get(context, param.viewId); if (!view) { NcError.viewNotFound(param.viewId); @@ -114,24 +123,27 @@ export class ViewsService { return res; } - async viewUpdate(param: { - viewId: string; - view: ViewUpdateReqType; - user: UserType; - req: NcRequest; - }) { + async viewUpdate( + context: NcContext, + param: { + viewId: string; + view: ViewUpdateReqType; + user: UserType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/ViewUpdateReq', param.view, ); - const view = await View.get(param.viewId); + const view = await View.get(context, param.viewId); if (!view) { NcError.viewNotFound(param.viewId); } - const result = await View.update(param.viewId, param.view); + const result = await View.update(context, param.viewId, param.view); this.appHooksService.emit(AppEvents.VIEW_UPDATE, { view: { @@ -145,14 +157,17 @@ export class ViewsService { return result; } - async viewDelete(param: { viewId: string; user: UserType; req: NcRequest }) { - const view = await View.get(param.viewId); + async viewDelete( + context: NcContext, + param: { viewId: string; user: UserType; req: NcRequest }, + ) { + const view = await View.get(context, param.viewId); if (!view) { NcError.viewNotFound(param.viewId); } - await View.delete(param.viewId); + await View.delete(context, param.viewId); this.appHooksService.emit(AppEvents.VIEW_DELETE, { view, @@ -163,24 +178,27 @@ export class ViewsService { return true; } - async shareViewUpdate(param: { - viewId: string; - sharedView: SharedViewReqType; - user: UserType; - req: NcRequest; - }) { + async shareViewUpdate( + context: NcContext, + param: { + viewId: string; + sharedView: SharedViewReqType; + user: UserType; + req: NcRequest; + }, + ) { validatePayload( 'swagger.json#/components/schemas/SharedViewReq', param.sharedView, ); - const view = await View.get(param.viewId); + const view = await View.get(context, param.viewId); if (!view) { NcError.viewNotFound(param.viewId); } - const result = await View.update(param.viewId, param.sharedView); + const result = await View.update(context, param.viewId, param.sharedView); this.appHooksService.emit(AppEvents.SHARED_VIEW_UPDATE, { user: param.user, @@ -191,17 +209,20 @@ export class ViewsService { return result; } - async shareViewDelete(param: { - viewId: string; - user: UserType; - req: NcRequest; - }) { - const view = await View.get(param.viewId); + async shareViewDelete( + context: NcContext, + param: { + viewId: string; + user: UserType; + req: NcRequest; + }, + ) { + const view = await View.get(context, param.viewId); if (!view) { NcError.viewNotFound(param.viewId); } - await View.sharedViewDelete(param.viewId); + await View.sharedViewDelete(context, param.viewId); this.appHooksService.emit(AppEvents.SHARED_VIEW_DELETE, { user: param.user, @@ -212,17 +233,23 @@ export class ViewsService { return true; } - async showAllColumns(param: { viewId: string; ignoreIds?: string[] }) { - await View.showAllColumns(param.viewId, param.ignoreIds || []); + async showAllColumns( + context: NcContext, + param: { viewId: string; ignoreIds?: string[] }, + ) { + await View.showAllColumns(context, param.viewId, param.ignoreIds || []); return true; } - async hideAllColumns(param: { viewId: string; ignoreIds?: string[] }) { - await View.hideAllColumns(param.viewId, param.ignoreIds || []); + async hideAllColumns( + context: NcContext, + param: { viewId: string; ignoreIds?: string[] }, + ) { + await View.hideAllColumns(context, param.viewId, param.ignoreIds || []); return true; } - async shareViewList(param: { tableId: string }) { - return await View.shareViewList(param.tableId); + async shareViewList(context: NcContext, param: { tableId: string }) { + return await View.shareViewList(context, param.tableId); } } diff --git a/packages/nocodb/src/strategies/authtoken.strategy/authtoken.strategy.ts b/packages/nocodb/src/strategies/authtoken.strategy/authtoken.strategy.ts index f01b5c42b4..f3f3896a97 100644 --- a/packages/nocodb/src/strategies/authtoken.strategy/authtoken.strategy.ts +++ b/packages/nocodb/src/strategies/authtoken.strategy/authtoken.strategy.ts @@ -2,14 +2,14 @@ import { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { extractRolesObj, ProjectRoles } from 'nocodb-sdk'; import { Strategy } from 'passport-custom'; -import type { Request } from 'express'; +import type { NcRequest } from '~/interface/config'; import { ApiToken, User } from '~/models'; import { sanitiseUserObj } from '~/utils'; @Injectable() export class AuthTokenStrategy extends PassportStrategy(Strategy, 'authtoken') { // eslint-disable-next-line @typescript-eslint/ban-types - async validate(req: Request, callback: Function) { + async validate(req: NcRequest, callback: Function) { try { let user; if (req.headers['xc-token']) { @@ -29,6 +29,7 @@ export class AuthTokenStrategy extends PassportStrategy(Strategy, 'authtoken') { } const dbUser: Record = await User.getWithRoles( + req.context, apiToken.fk_user_id, { baseId: req['ncBaseId'], diff --git a/packages/nocodb/src/strategies/base-view.strategy/base-view.strategy.ts b/packages/nocodb/src/strategies/base-view.strategy/base-view.strategy.ts index 4cb32d36b8..c81c89b908 100644 --- a/packages/nocodb/src/strategies/base-view.strategy/base-view.strategy.ts +++ b/packages/nocodb/src/strategies/base-view.strategy/base-view.strategy.ts @@ -2,17 +2,18 @@ import { Injectable, UnauthorizedException } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy } from 'passport-custom'; import { extractRolesObj } from 'nocodb-sdk'; -import type { Request } from 'express'; +import type { NcRequest } from '~/interface/config'; import { Base } from '~/models'; @Injectable() export class BaseViewStrategy extends PassportStrategy(Strategy, 'base-view') { // eslint-disable-next-line @typescript-eslint/ban-types - async validate(req: Request, callback: Function) { + async validate(req: NcRequest, callback: Function) { try { let user; if (req.headers['xc-shared-base-id']) { const sharedProject = await Base.getByUuid( + req.context, req.headers['xc-shared-base-id'], ); diff --git a/packages/nocodb/src/strategies/google.strategy/google.strategy.ts b/packages/nocodb/src/strategies/google.strategy/google.strategy.ts index 0acc4440a6..8104f4e0b5 100644 --- a/packages/nocodb/src/strategies/google.strategy/google.strategy.ts +++ b/packages/nocodb/src/strategies/google.strategy/google.strategy.ts @@ -35,7 +35,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') { if (user) { // if base id defined extract base level roles if (req.ncBaseId) { - BaseUser.get(req.ncBaseId, user.id) + BaseUser.get(req.context, req.ncBaseId, user.id) .then(async (baseUser) => { user.roles = baseUser?.roles || user.roles; // + (user.roles ? `,${user.roles}` : ''); diff --git a/packages/nocodb/src/strategies/jwt.strategy.ts b/packages/nocodb/src/strategies/jwt.strategy.ts index ddaf6b3332..751498cfa6 100644 --- a/packages/nocodb/src/strategies/jwt.strategy.ts +++ b/packages/nocodb/src/strategies/jwt.strategy.ts @@ -27,7 +27,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) { ) { throw new Error('Token Expired. Please login again.'); } - const userWithRoles = await User.getWithRoles(user.id, { + const userWithRoles = await User.getWithRoles(req.context, user.id, { user, baseId: req.ncBaseId, }); diff --git a/packages/nocodb/src/types/express.d.ts b/packages/nocodb/src/types/express.d.ts index 5da805283a..2af90a4367 100644 --- a/packages/nocodb/src/types/express.d.ts +++ b/packages/nocodb/src/types/express.d.ts @@ -1,6 +1,8 @@ import type { UserType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; declare module 'express-serve-static-core' { interface Request { + context: NcContext; ncWorkspaceId?: string; ncBaseId?: string; user: UserType & { diff --git a/packages/nocodb/src/utils/acl.ts b/packages/nocodb/src/utils/acl.ts index c16e5d031d..d4624a8ac5 100644 --- a/packages/nocodb/src/utils/acl.ts +++ b/packages/nocodb/src/utils/acl.ts @@ -51,6 +51,8 @@ const permissionScopes = { // TODO: add ACL with base scope 'upload', 'uploadViaURL', + + 'notification', ], base: [ 'formViewGet', @@ -279,6 +281,7 @@ const rolePermissions: testConnection: true, isPluginActive: true, commandPalette: true, + notification: true, }, }, [OrgUserRoles.CREATOR]: { diff --git a/packages/nocodb/src/utils/globals.ts b/packages/nocodb/src/utils/globals.ts index 5b02edbfb8..e4fcc14ad5 100644 --- a/packages/nocodb/src/utils/globals.ts +++ b/packages/nocodb/src/utils/globals.ts @@ -263,3 +263,26 @@ export const DB_TYPES = [ 'pg', 'databricks', ]; + +export enum RootScopes { + ROOT = 'root', + ORG = 'org', + WORKSPACE = 'workspace', + BASE = 'base', + // This scope only used for extract-ids middleware to get initial entity + BYPASS = 'bypass', +} + +export const RootScopeTables = { + [RootScopes.ROOT]: [ + MetaTable.USERS, + MetaTable.USER_REFRESH_TOKENS, + MetaTable.API_TOKENS, + MetaTable.PLUGIN, + MetaTable.STORE, + MetaTable.NOTIFICATION, + // Temporarily added need to be discussed within team + MetaTable.AUDIT, + ], + [RootScopes.BASE]: [MetaTable.PROJECT], +}; diff --git a/packages/nocodb/src/version-upgrader/NcUpgrader.ts b/packages/nocodb/src/version-upgrader/NcUpgrader.ts index 7caa5ca98c..06ee2469c3 100644 --- a/packages/nocodb/src/version-upgrader/NcUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/NcUpgrader.ts @@ -19,6 +19,7 @@ import ncXcdbLTARIndexUpgrader from './ncXcdbLTARIndexUpgrader'; import ncXcdbCreatedAndUpdatedSystemFieldsUpgrader from './ncXcdbCreatedAndUpdatedSystemFieldsUpgrader'; import type { MetaService } from '~/meta/meta.service'; import type { NcConfig } from '~/interface/config'; +import { RootScopes } from '~/utils/globals'; const log = debug('nc:version-upgrader'); @@ -42,9 +43,14 @@ export default class NcUpgrader { } this.log(`upgrade : Getting configuration from meta database`); - const config = await ctx.ncMeta.metaGet('', '', 'nc_store', { - key: this.STORE_KEY, - }); + const config = await ctx.ncMeta.metaGet( + RootScopes.ROOT, + RootScopes.ROOT, + 'nc_store', + { + key: this.STORE_KEY, + }, + ); const NC_VERSIONS: any[] = this.getUpgraderList(); @@ -65,8 +71,8 @@ export default class NcUpgrader { // update version in meta after each upgrade config.version = version.name; await ctx.ncMeta.metaUpdate( - '', - '', + RootScopes.ROOT, + RootScopes.ROOT, 'nc_store', { value: JSON.stringify({ version: config.version }), @@ -91,10 +97,16 @@ export default class NcUpgrader { process.env.NC_CLOUD !== 'true' && (await ctx.ncMeta.baseList())?.length; configObj.version = isOld ? '0009000' : process.env.NC_VERSION; - await ctx.ncMeta.metaInsert('', '', 'nc_store', { - key: NcUpgrader.STORE_KEY, - value: JSON.stringify(configObj), - }); + await ctx.ncMeta.metaInsert2( + RootScopes.ROOT, + RootScopes.ROOT, + 'nc_store', + { + key: NcUpgrader.STORE_KEY, + value: JSON.stringify(configObj), + }, + true, + ); if (isOld) { await this.upgrade(ctx); } diff --git a/packages/nocodb/src/version-upgrader/ncAttachmentUpgrader.ts b/packages/nocodb/src/version-upgrader/ncAttachmentUpgrader.ts index 21c9864d27..5a7a66f96e 100644 --- a/packages/nocodb/src/version-upgrader/ncAttachmentUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncAttachmentUpgrader.ts @@ -46,11 +46,8 @@ function getTnPath(knex: XKnex, tb: Model) { } export default async function ({ ncMeta }: NcUpgraderCtx) { - const sources: SourceType[] = await ncMeta.metaList2( - null, - null, - MetaTable.BASES, - ); + const sources: SourceType[] = await ncMeta.knexConnection(MetaTable.BASES); + for (const _base of sources) { const source = new Source(_base); @@ -59,9 +56,19 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { continue; } - const base = await ncMeta.metaGet2(null, null, MetaTable.PROJECT, { - id: source.base_id, - }); + const context = { + workspace_id: source.fk_workspace_id, + base_id: source.base_id, + }; + + const base = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.PROJECT, + { + id: source.base_id, + }, + ); // skip if the base is missing if (!base) { @@ -73,7 +80,7 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { const knex: Knex = source.is_meta ? ncMeta.knexConnection : await NcConnectionMgrv2.get(source); - const models = await source.getModels(ncMeta); + const models = await source.getModels(context, ncMeta); // used in timeout error message const timeoutErrorInfo = { @@ -92,8 +99,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // get all attachment & primary key columns // and filter out the columns that are missing in database - const columns = await (await Model.get(model.id, ncMeta)) - .getColumns(ncMeta) + const columns = await (await Model.get(context, model.id, ncMeta)) + .getColumns(context, ncMeta) .then(async (columns) => { const filteredColumns = []; diff --git a/packages/nocodb/src/version-upgrader/ncAttachmentUpgrader_0104002.ts b/packages/nocodb/src/version-upgrader/ncAttachmentUpgrader_0104002.ts index e05e5ffd2b..5d57a046d5 100644 --- a/packages/nocodb/src/version-upgrader/ncAttachmentUpgrader_0104002.ts +++ b/packages/nocodb/src/version-upgrader/ncAttachmentUpgrader_0104002.ts @@ -37,11 +37,8 @@ function getTnPath(knex: XKnex, tb: Model) { } export default async function ({ ncMeta }: NcUpgraderCtx) { - const sources: SourceType[] = await ncMeta.metaList2( - null, - null, - MetaTable.BASES, - ); + const sources: SourceType[] = await ncMeta.knexConnection(MetaTable.BASES); + for (const _base of sources) { const source = new Source(_base); @@ -50,9 +47,19 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { continue; } - const base = await ncMeta.metaGet2(null, null, MetaTable.PROJECT, { - id: source.base_id, - }); + const context = { + workspace_id: source.fk_workspace_id, + base_id: source.base_id, + }; + + const base = await ncMeta.metaGet2( + context.workspace_id, + context.base_id, + MetaTable.PROJECT, + { + id: source.base_id, + }, + ); // skip if the base is missing if (!base) { @@ -64,7 +71,7 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { const knex: Knex = source.is_meta ? ncMeta.knexConnection : await NcConnectionMgrv2.get(source); - const models = await source.getModels(ncMeta); + const models = await source.getModels(context, ncMeta); // used in timeout error message const timeoutErrorInfo = { @@ -83,8 +90,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // get all attachment & primary key columns // and filter out the columns that are missing in database - const columns = await (await Model.get(model.id, ncMeta)) - .getColumns(ncMeta) + const columns = await (await Model.get(context, model.id, ncMeta)) + .getColumns(context, ncMeta) .then(async (columns) => { const filteredColumns = []; diff --git a/packages/nocodb/src/version-upgrader/ncFilterUpgrader.ts b/packages/nocodb/src/version-upgrader/ncFilterUpgrader.ts index 0987fd52e9..a4d5570211 100644 --- a/packages/nocodb/src/version-upgrader/ncFilterUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncFilterUpgrader.ts @@ -9,15 +9,20 @@ import Column from '~/models/Column'; // this upgrader is to retrieve the correct base id from either view, hook, or column // and update the base id export default async function ({ ncMeta }: NcUpgraderCtx) { - const filters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP); + const filters = await ncMeta.knexConnection(MetaTable.FILTER_EXP); for (const filter of filters) { + const context = { + workspace_id: filter.fk_workspace_id, + base_id: filter.fk_base_id, + }; + let model: { base_id?: string; source_id?: string }; if (filter.fk_view_id) { - model = await View.get(filter.fk_view_id, ncMeta); + model = await View.get(context, filter.fk_view_id, ncMeta); } else if (filter.fk_hook_id) { - model = await Hook.get(filter.fk_hook_id, ncMeta); + model = await Hook.get(context, filter.fk_hook_id, ncMeta); } else if (filter.fk_column_id) { - model = await Column.get({ colId: filter.fk_column_id }, ncMeta); + model = await Column.get(context, { colId: filter.fk_column_id }, ncMeta); } else { continue; } @@ -29,8 +34,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { if (filter.base_id !== model.base_id) { await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.FILTER_EXP, { source_id: model.source_id, base_id: model.base_id }, filter.id, diff --git a/packages/nocodb/src/version-upgrader/ncFilterUpgrader_0104004.ts b/packages/nocodb/src/version-upgrader/ncFilterUpgrader_0104004.ts index a1bdcac83a..e792097e11 100644 --- a/packages/nocodb/src/version-upgrader/ncFilterUpgrader_0104004.ts +++ b/packages/nocodb/src/version-upgrader/ncFilterUpgrader_0104004.ts @@ -2,6 +2,7 @@ import { UITypes } from 'nocodb-sdk'; import type { MetaService } from '~/meta/meta.service'; import type { NcUpgraderCtx } from './NcUpgrader'; import type { SelectOptionsType } from 'nocodb-sdk'; +import type { NcContext } from '~/interface/config'; import { MetaTable } from '~/utils/globals'; import Column from '~/models/Column'; import Filter from '~/models/Filter'; @@ -90,7 +91,12 @@ const migrateNullAndEmptyToBlankFilters = (filter, ncMeta) => { return actions; }; -const migrateMultiSelectEq = async (filter, col: Column, ncMeta) => { +const migrateMultiSelectEq = async ( + context: NcContext, + filter, + col: Column, + ncMeta, +) => { // only allow eq / neq if (!['eq', 'neq'].includes(filter.comparison_op)) return; // if there is no value -> delete this filter @@ -100,7 +106,7 @@ const migrateMultiSelectEq = async (filter, col: Column, ncMeta) => { // options inputted from users const options = filter.value.split(','); // retrieve the possible col options - const colOptions = (await col.getColOptions()) as SelectOptionsType; + const colOptions = (await col.getColOptions(context)) as SelectOptionsType; // only include valid options as the input value becomes dropdown type now const validOptions = []; for (const option of options) { @@ -231,12 +237,22 @@ const migrateToCheckboxFilter = (filter, ncMeta) => { }; async function migrateFilters(ncMeta: MetaService) { - const filters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP); + const filters = await ncMeta.knexConnection(MetaTable.FILTER_EXP); for (const filter of filters) { if (!filter.fk_column_id || filter.is_group) { continue; } - const col = await Column.get({ colId: filter.fk_column_id }, ncMeta); + + const context = { + workspace_id: filter.fk_workspace_id, + base_id: filter.fk_base_id, + }; + + const col = await Column.get( + context, + { colId: filter.fk_column_id }, + ncMeta, + ); if ( [ UITypes.SingleLineText, @@ -272,7 +288,7 @@ async function migrateFilters(ncMeta: MetaService) { ...removeLikeFilters(filter, ncMeta), ...migrateNullAndEmptyToBlankFilters(filter, ncMeta), ]); - await migrateMultiSelectEq(filter, col, ncMeta); + await migrateMultiSelectEq(context, filter, col, ncMeta); } else if (col.uidt === UITypes.Attachment) { await Promise.all([ ...removeArithmeticFilters(filter, ncMeta), @@ -301,7 +317,7 @@ async function migrateFilters(ncMeta: MetaService) { async function updateProjectMeta(ncMeta: MetaService) { const baseHasEmptyOrFilters: Record = {}; - const filters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP); + const filters = await ncMeta.knexConnection(MetaTable.FILTER_EXP); const actions = []; @@ -313,7 +329,7 @@ async function updateProjectMeta(ncMeta: MetaService) { } } - const bases = await ncMeta.metaList2(null, null, MetaTable.PROJECT); + const bases = await ncMeta.knexConnection(MetaTable.PROJECT); const defaultProjectMeta = { showNullAndEmptyInFilter: false, @@ -336,6 +352,10 @@ async function updateProjectMeta(ncMeta: MetaService) { actions.push( Base.update( + { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }, base.id, { meta: JSON.stringify(newProjectMeta), diff --git a/packages/nocodb/src/version-upgrader/ncFilterUpgrader_0105003.ts b/packages/nocodb/src/version-upgrader/ncFilterUpgrader_0105003.ts index b63bfe887e..f1becba76a 100644 --- a/packages/nocodb/src/version-upgrader/ncFilterUpgrader_0105003.ts +++ b/packages/nocodb/src/version-upgrader/ncFilterUpgrader_0105003.ts @@ -1,6 +1,7 @@ import { UITypes } from 'nocodb-sdk'; import type { MetaService } from '~/meta/meta.service'; import type { NcUpgraderCtx } from './NcUpgrader'; +import type { NcContext } from '~/interface/config'; import { MetaTable } from '~/utils/globals'; import Column from '~/models/Column'; import Filter from '~/models/Filter'; @@ -23,21 +24,30 @@ import Filter from '~/models/Filter'; // - remove `is like` and `is not like` // - migrate `null` or `empty` filters to `blank` -function removeLikeAndNlikeFilters(filter: Filter, ncMeta: MetaService) { +function removeLikeAndNlikeFilters( + context: NcContext, + filter: Filter, + ncMeta: MetaService, +) { const actions = []; // remove `is like` and `is not like` if (['like', 'nlike'].includes(filter.comparison_op)) { - actions.push(Filter.delete(filter.id, ncMeta)); + actions.push(Filter.delete(context, filter.id, ncMeta)); } return actions; } -function migrateEqAndNeqFilters(filter: Filter, ncMeta: MetaService) { +function migrateEqAndNeqFilters( + context: NcContext, + filter: Filter, + ncMeta: MetaService, +) { const actions = []; // remove `is like` and `is not like` if (['eq', 'neq'].includes(filter.comparison_op)) { actions.push( Filter.update( + context, filter.id, { comparison_sub_op: 'exactDate', @@ -49,13 +59,18 @@ function migrateEqAndNeqFilters(filter: Filter, ncMeta: MetaService) { return actions; } -function migrateEmptyAndNullFilters(filter: Filter, ncMeta: MetaService) { +function migrateEmptyAndNullFilters( + context: NcContext, + filter: Filter, + ncMeta: MetaService, +) { const actions = []; // remove `is like` and `is not like` if (['empty', 'null'].includes(filter.comparison_op)) { // migrate to blank actions.push( Filter.update( + context, filter.id, { comparison_op: 'blank', @@ -67,6 +82,7 @@ function migrateEmptyAndNullFilters(filter: Filter, ncMeta: MetaService) { // migrate to not blank actions.push( Filter.update( + context, filter.id, { comparison_op: 'notblank', @@ -79,22 +95,32 @@ function migrateEmptyAndNullFilters(filter: Filter, ncMeta: MetaService) { } export default async function ({ ncMeta }: NcUpgraderCtx) { - const filters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP); + const filters = await ncMeta.knexConnection(MetaTable.FILTER_EXP); for (const filter of filters) { if (!filter.fk_column_id || filter.is_group) { continue; } - const col = await Column.get({ colId: filter.fk_column_id }, ncMeta); + + const context = { + workspace_id: filter.fk_workspace_id, + base_id: filter.fk_base_id, + }; + + const col = await Column.get( + context, + { colId: filter.fk_column_id }, + ncMeta, + ); if ([UITypes.Date, UITypes.DateTime].includes(col.uidt)) { await Promise.all([ - ...removeLikeAndNlikeFilters(filter, ncMeta), - ...migrateEmptyAndNullFilters(filter, ncMeta), - ...migrateEqAndNeqFilters(filter, ncMeta), + ...removeLikeAndNlikeFilters(context, filter, ncMeta), + ...migrateEmptyAndNullFilters(context, filter, ncMeta), + ...migrateEqAndNeqFilters(context, filter, ncMeta), ]); } else if ([UITypes.Time, UITypes.Year].includes(col.uidt)) { await Promise.all([ - ...removeLikeAndNlikeFilters(filter, ncMeta), - ...migrateEmptyAndNullFilters(filter, ncMeta), + ...removeLikeAndNlikeFilters(context, filter, ncMeta), + ...migrateEmptyAndNullFilters(context, filter, ncMeta), ]); } } diff --git a/packages/nocodb/src/version-upgrader/ncHookUpgrader.ts b/packages/nocodb/src/version-upgrader/ncHookUpgrader.ts index 2eb4716c6d..55eeeb6b59 100644 --- a/packages/nocodb/src/version-upgrader/ncHookUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncHookUpgrader.ts @@ -3,12 +3,12 @@ import { MetaTable } from '~/utils/globals'; export default async function ({ ncMeta }: NcUpgraderCtx) { const actions = []; - const hooks = await ncMeta.metaList2(null, null, MetaTable.HOOKS); + const hooks = await ncMeta.knexConnection(MetaTable.HOOKS); for (const hook of hooks) { actions.push( ncMeta.metaUpdate( - null, - null, + hook.fk_workspace_id, + hook.base_id, MetaTable.HOOKS, { version: 'v1' }, hook.id, diff --git a/packages/nocodb/src/version-upgrader/ncProjectConfigUpgrader.ts b/packages/nocodb/src/version-upgrader/ncProjectConfigUpgrader.ts index fe8dc26e9d..8b5f5a7cee 100644 --- a/packages/nocodb/src/version-upgrader/ncProjectConfigUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncProjectConfigUpgrader.ts @@ -13,12 +13,17 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { const actions = []; // Get all the base sources - const sources = await ncMeta.metaList2(null, null, MetaTable.BASES); + const sources = await ncMeta.knexConnection(MetaTable.BASES); // Update the base config with the new secret key if we could decrypt the base config with the fallback secret key for (const source of sources) { let config; + const context = { + workspace_id: source.fk_workspace_id, + base_id: source.id, + }; + // Try to decrypt the base config with the fallback secret key // if we could decrypt the base config with the fallback secret key then we will update the base config with the new secret key // otherwise we will skip the base config update since it is already encrypted with the new secret key @@ -32,6 +37,7 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // Update the base config with the new secret key actions.push( Source.updateBase( + context, source.id, { id: source.id, diff --git a/packages/nocodb/src/version-upgrader/ncProjectRolesUpgrader.ts b/packages/nocodb/src/version-upgrader/ncProjectRolesUpgrader.ts index 9f33053b6f..956d30f48f 100644 --- a/packages/nocodb/src/version-upgrader/ncProjectRolesUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncProjectRolesUpgrader.ts @@ -2,11 +2,15 @@ import { OrgUserRoles } from 'nocodb-sdk'; import { NC_APP_SETTINGS } from '../constants'; import type { NcUpgraderCtx } from './NcUpgrader'; import Store from '~/models/Store'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; /** Upgrader for upgrading roles */ export default async function ({ ncMeta }: NcUpgraderCtx) { - const users = await ncMeta.metaList2(null, null, MetaTable.USERS); + const users = await ncMeta.metaList2( + RootScopes.ROOT, + RootScopes.ROOT, + MetaTable.USERS, + ); for (const user of users) { user.roles = user.roles @@ -22,8 +26,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { }) .join(','); await ncMeta.metaUpdate( - null, - null, + RootScopes.ROOT, + RootScopes.ROOT, MetaTable.USERS, { roles: user.roles }, user.id, diff --git a/packages/nocodb/src/version-upgrader/ncProjectUpgraderV2_0090000.ts b/packages/nocodb/src/version-upgrader/ncProjectUpgraderV2_0090000.ts index ef42a6d57b..266ce8091c 100644 --- a/packages/nocodb/src/version-upgrader/ncProjectUpgraderV2_0090000.ts +++ b/packages/nocodb/src/version-upgrader/ncProjectUpgraderV2_0090000.ts @@ -26,13 +26,14 @@ import View from '~/models/View'; import Sort from '~/models/Sort'; import Filter from '~/models/Filter'; import ModelRoleVisibility from '~/models/ModelRoleVisibility'; -import { MetaTable } from '~/utils/globals'; +import { MetaTable, RootScopes } from '~/utils/globals'; import Hook from '~/models/Hook'; import FormViewColumn from '~/models/FormViewColumn'; import GridViewColumn from '~/models/GridViewColumn'; import Audit from '~/models/Audit'; -export default async function (ctx: NcUpgraderCtx) { +export default async function (_ctx: NcUpgraderCtx) { + /* TODO : decide on how to handle migrating from very old versions const ncMeta = ctx.ncMeta; const bases = await ctx.ncMeta.baseList(); @@ -63,7 +64,7 @@ export default async function (ctx: NcUpgraderCtx) { } async function migrateUsers(ncMeta = Noco.ncMeta) { - const users = await ncMeta.metaList(null, null, 'xc_users'); + const users = await ncMeta.metaList2(context.workspace_id, context.base_id, 'xc_users'); const userObj: { [id: string]: User | UserType } = {}; for (const user of users) { @@ -109,7 +110,7 @@ async function migrateProjectUsers( usersObj: { [p: string]: User | UserType }, ncMeta = Noco.ncMeta, ) { - const baseUsers = await ncMeta.metaList(null, null, 'nc_projects_users'); + const baseUsers = await ncMeta.metaList2(context.workspace_id, context.base_id, 'nc_projects_users'); for (const baseUser of baseUsers) { // skip if base is missing @@ -348,11 +349,11 @@ async function migrateProjectModels( ): Promise { // @ts-ignore - const metas: ModelMetav1[] = await ncMeta.metaList(null, null, 'nc_models'); + const metas: ModelMetav1[] = await ncMeta.metaList2(context.workspace_id, context.base_id, 'nc_models'); // @ts-ignore - const relations: Relationv1[] = await ncMeta.metaList( - null, - null, + const relations: Relationv1[] = await ncMeta.metaList2( + context.workspace_id, + context.base_id, 'nc_relations', ); const models: Model[] = []; @@ -1050,7 +1051,7 @@ async function migrateUIAcl(ctx: MigrateCtxV1, ncMeta: any) { tn: string; parent_model_title: string; base_id: string; - }> = await ncMeta.metaList(null, null, 'nc_disabled_models_for_role'); + }> = await ncMeta.metaList2(context.workspace_id, context.base_id, 'nc_disabled_models_for_role'); for (const acl of uiAclList) { // if missing model name skip the view acl migration @@ -1096,7 +1097,7 @@ async function migrateSharedViews(ctx: MigrateCtxV1, ncMeta: any) { password: string; view_name: string; base_id: string; - }> = await ncMeta.metaList(null, null, 'nc_shared_views'); + }> = await ncMeta.metaList2(context.workspace_id, context.base_id, 'nc_shared_views'); for (const sharedView of sharedViews) { let fk_view_id; @@ -1143,7 +1144,7 @@ async function migrateSharedBase(ncMeta: any) { enabled: boolean; base_id: string; password: string; - }> = await ncMeta.metaList(null, null, 'nc_shared_bases'); + }> = await ncMeta.metaList2(context.workspace_id, context.base_id, 'nc_shared_bases'); for (const sharedBase of sharedBases) { await Base.update( @@ -1159,26 +1160,31 @@ async function migrateSharedBase(ncMeta: any) { } async function migratePlugins(ncMeta: any) { - const plugins: Array = await ncMeta.metaList(null, null, 'nc_plugins'); + const plugins: Array = await ncMeta.metaList2(context.workspace_id, context.base_id, 'nc_plugins'); for (const plugin of plugins) { - await ncMeta.metaInsert2(null, null, MetaTable.PLUGIN, { - title: plugin.title, - description: plugin.description, - active: plugin.active, - version: plugin.version, - docs: plugin.docs, - status: plugin.status, - status_details: plugin.status_details, - logo: plugin.logo, - tags: plugin.tags, - category: plugin.category, - input: plugin.input, - input_schema: plugin.input_schema, - creator: plugin.creator, - creator_website: plugin.creator_website, - price: plugin.price, - }); + await ncMeta.metaInsert2( + context.workspace_id, + context.base_id, + MetaTable.PLUGIN, + { + title: plugin.title, + description: plugin.description, + active: plugin.active, + version: plugin.version, + docs: plugin.docs, + status: plugin.status, + status_details: plugin.status_details, + logo: plugin.logo, + tags: plugin.tags, + category: plugin.category, + input: plugin.input, + input_schema: plugin.input_schema, + creator: plugin.creator, + creator_website: plugin.creator_website, + price: plugin.price, + }, + ); } } @@ -1203,7 +1209,7 @@ async function migrateWebhooks(ctx: MigrateCtxV1, ncMeta: any) { retry_interval: number; timeout: number; active: boolean; - }> = await ncMeta.metaList(null, null, 'nc_hooks'); + }> = await ncMeta.metaList2(context.workspace_id, context.base_id, 'nc_hooks'); for (const hookMeta of hooks) { if ( @@ -1281,7 +1287,7 @@ async function migrateAutitLog( status: string; description: string; details: string; - }> = await ncMeta.metaList(null, null, 'nc_audit'); + }> = await ncMeta.metaList2(context.workspace_id, context.base_id, 'nc_audit'); for (const audit of audits) { // skip deleted bases audit @@ -1319,4 +1325,5 @@ async function migrateAutitLog( await Audit.insert(insertObj, ncMeta); } + */ } diff --git a/packages/nocodb/src/version-upgrader/ncStickyColumnUpgrader.ts b/packages/nocodb/src/version-upgrader/ncStickyColumnUpgrader.ts index 81f0b5bbc5..95cea59f67 100644 --- a/packages/nocodb/src/version-upgrader/ncStickyColumnUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncStickyColumnUpgrader.ts @@ -6,18 +6,29 @@ import { MetaTable } from '~/utils/globals'; // this upgrader will make display value column first column in grid views export default async function ({ ncMeta }: NcUpgraderCtx) { - const grid_columns = await ncMeta.metaList2( - null, - null, - MetaTable.GRID_VIEW_COLUMNS, - ); + const grid_columns = await ncMeta.knexConnection(MetaTable.GRID_VIEW_COLUMNS); + const grid_views = [...new Set(grid_columns.map((col) => col.fk_view_id))]; + const view_meta = grid_views.reduce((acc, view_id) => { + const sampleColumn = grid_columns.find((col) => col.fk_view_id === view_id); + return { + ...acc, + [view_id]: { + base_id: sampleColumn.base_id, + workspace_id: sampleColumn.fk_workspace_id, + }, + }; + }, {}); + for (const view_id of grid_views) { + const base_id = view_meta[view_id].base_id; + const workspace_id = view_meta[view_id].workspace_id; + // get a list of view columns sorted by order const view_columns = await ncMeta.metaList2( - null, - null, + workspace_id, + base_id, MetaTable.GRID_VIEW_COLUMNS, { condition: { @@ -32,9 +43,14 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // get column meta for each view column for (const col of view_columns) { - const col_meta = await ncMeta.metaGet(null, null, MetaTable.COLUMNS, { - id: col.fk_column_id, - }); + const col_meta = await ncMeta.metaGet( + workspace_id, + base_id, + MetaTable.COLUMNS, + { + id: col.fk_column_id, + }, + ); view_columns_meta.push(col_meta); } @@ -46,16 +62,16 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { if (pkIndex === view_columns_meta.length - 1) { if (pkIndex > 0) { await ncMeta.metaUpdate( - null, - null, + workspace_id, + base_id, MetaTable.COLUMNS, { pv: true }, view_columns_meta[pkIndex - 1].id, ); } else if (view_columns_meta.length > 0) { await ncMeta.metaUpdate( - null, - null, + workspace_id, + base_id, MetaTable.COLUMNS, { pv: true }, view_columns_meta[0].id, @@ -64,8 +80,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // pk is not at the end of table } else if (pkIndex > -1) { await ncMeta.metaUpdate( - null, - null, + workspace_id, + base_id, MetaTable.COLUMNS, { pv: true }, view_columns_meta[pkIndex + 1].id, @@ -73,8 +89,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // no pk at all } else if (view_columns_meta.length > 0) { await ncMeta.metaUpdate( - null, - null, + workspace_id, + base_id, MetaTable.COLUMNS, { pv: true }, view_columns_meta[0].id, @@ -97,8 +113,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // if primary_value_column is not visible, make it visible if (!primary_value_column.show) { await ncMeta.metaUpdate( - null, - null, + workspace_id, + base_id, MetaTable.GRID_VIEW_COLUMNS, { show: true }, primary_value_column.id, @@ -121,8 +137,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // update order of all columns in view to match the order in array for (let i = 0; i < view_columns.length; i++) { await ncMeta.metaUpdate( - null, - null, + workspace_id, + base_id, MetaTable.GRID_VIEW_COLUMNS, { order: i + 1 }, view_columns[i].id, diff --git a/packages/nocodb/src/version-upgrader/ncXcdbCreatedAndUpdatedSystemFieldsUpgrader.ts b/packages/nocodb/src/version-upgrader/ncXcdbCreatedAndUpdatedSystemFieldsUpgrader.ts index 3b784c0dd6..a5dc93bc29 100644 --- a/packages/nocodb/src/version-upgrader/ncXcdbCreatedAndUpdatedSystemFieldsUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncXcdbCreatedAndUpdatedSystemFieldsUpgrader.ts @@ -65,9 +65,14 @@ async function upgradeModels({ base: Base; models: Model[]; }) { + const context = { workspace_id: base.fk_workspace_id, base_id: base.id }; // get existing columns from database const sqlClient = await NcConnectionMgrv2.getSqlClient(source, ncMeta.knex); - const sqlMgr = ProjectMgrv2.getSqlMgr({ id: source.base_id }, ncMeta); + const sqlMgr = ProjectMgrv2.getSqlMgr( + context, + { id: source.base_id }, + ncMeta, + ); await Promise.all( models.map(async (model) => { @@ -122,6 +127,7 @@ async function upgradeModels({ isCreatedTimeExists = true; if (column.uidt !== UITypes.CreatedTime || !column.system) { await Column.update( + context, column.id, { ...column, @@ -144,6 +150,7 @@ async function upgradeModels({ isLastModifiedTimeExists = true; if (column.uidt !== UITypes.LastModifiedTime || !column.system) { await Column.update( + context, column.id, { ...column, @@ -341,6 +348,7 @@ async function upgradeModels({ } for (const newColumn of [...existingDbColumns, ...newColumns]) { await Column.insert( + context, { ...newColumn, system: true, @@ -362,25 +370,23 @@ async function upgradeModels({ // database to virtual relation and create an index for it export default async function ({ ncMeta }: NcUpgraderCtx) { // get all xcdb sources - const sources = await ncMeta.metaList2(null, null, MetaTable.BASES, { - xcCondition: { - _or: [ - { - is_meta: { - eq: 1, - }, + const sources = await ncMeta.knexConnection(MetaTable.BASES).condition({ + _or: [ + { + is_meta: { + eq: 1, }, - ...(Noco.isEE() - ? [ - { - is_local: { - eq: 1, - }, + }, + ...(Noco.isEE() + ? [ + { + is_local: { + eq: 1, }, - ] - : []), - ], - }, + }, + ] + : []), + ], }); const requestQueue = new RequestQueue(); @@ -389,7 +395,12 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { sources.map(async (_source, i) => { const source = new Source(_source); - const base = await source.getProject(ncMeta); + const context = { + workspace_id: source.fk_workspace_id, + base_id: source.base_id, + }; + + const base = await source.getProject(context, ncMeta); // skip deleted base bases if (!base || base.deleted) { @@ -404,6 +415,7 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // update the meta props return requestQueue.enqueue(async () => { const models = await Model.list( + context, { base_id: source.base_id, source_id: source.id, @@ -412,7 +424,7 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { ); for (const model of models) { - await model.getColumns(ncMeta); + await model.getColumns(context, ncMeta); } logger.log( diff --git a/packages/nocodb/src/version-upgrader/ncXcdbLTARIndexUpgrader.ts b/packages/nocodb/src/version-upgrader/ncXcdbLTARIndexUpgrader.ts index f2127be992..6ec9dda791 100644 --- a/packages/nocodb/src/version-upgrader/ncXcdbLTARIndexUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncXcdbLTARIndexUpgrader.ts @@ -3,6 +3,7 @@ import { RelationTypes, UITypes } from 'nocodb-sdk'; import type { LinkToAnotherRecordColumn } from '~/models'; import type { MetaService } from '~/meta/meta.service'; import type { NcUpgraderCtx } from './NcUpgrader'; +import type { NcContext } from '~/interface/config'; import { MetaTable } from '~/utils/globals'; import { Source } from '~/models'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; @@ -11,36 +12,40 @@ import { Model } from '~/models'; const logger = new Logger('LTARIndexUpgrader'); // An upgrader for adding missing index of LTAR relations in XCDB sources -async function upgradeModelRelationsIndex({ - model, - indexes, - ncMeta, - sqlClient, -}: { - ncMeta: MetaService; - model: Model; - sqlClient: ReturnType< - (typeof NcConnectionMgrv2)['getSqlClient'] - > extends Promise - ? U - : ReturnType<(typeof NcConnectionMgrv2)['getSqlClient']>; - indexes: { - cn: string; - key_name: string; - - type: string; - rqd: boolean | number; - cst: string; - cstn: string; - }[]; -}) { +async function upgradeModelRelationsIndex( + context: NcContext, + { + model, + indexes, + ncMeta, + sqlClient, + }: { + ncMeta: MetaService; + model: Model; + sqlClient: ReturnType< + (typeof NcConnectionMgrv2)['getSqlClient'] + > extends Promise + ? U + : ReturnType<(typeof NcConnectionMgrv2)['getSqlClient']>; + indexes: { + cn: string; + key_name: string; + + type: string; + rqd: boolean | number; + cst: string; + cstn: string; + }[]; + }, +) { // Iterate over each column and upgrade LTAR - for (const column of await model.getColumns(ncMeta)) { + for (const column of await model.getColumns(context, ncMeta)) { if (column.uidt !== UITypes.LinkToAnotherRecord) { continue; } const colOptions = await column.getColOptions( + context, ncMeta, ); @@ -54,10 +59,10 @@ async function upgradeModelRelationsIndex({ case RelationTypes.BELONGS_TO: { // const parentCol = await colOptions.getParentColumn(ncMeta); - const childCol = await colOptions.getChildColumn(ncMeta); + const childCol = await colOptions.getChildColumn(context, ncMeta); // const parentModel = await parentCol.getModel(ncMeta); - const childModel = await childCol.getModel(ncMeta); + const childModel = await childCol.getModel(context, ncMeta); // check index already exists or not const indexExists = indexes.find((index) => { @@ -92,17 +97,24 @@ async function upgradeModelRelationsIndex({ } // An upgrader for adding missing index for LTAR relations in XCDB sources -async function upgradeBaseRelations({ - ncMeta, - source, -}: { - ncMeta: MetaService; - source: Source; -}) { +async function upgradeBaseRelations( + context: NcContext, + { + ncMeta, + source, + }: { + ncMeta: MetaService; + source: Source; + }, +) { const sqlClient = await NcConnectionMgrv2.getSqlClient(source, ncMeta.knex); // get models for the base - const models = await ncMeta.metaList2(null, source.id, MetaTable.MODELS); + const models = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.MODELS, + ); // get all columns and filter out relations and create index if not exists for (const model of models) { @@ -122,7 +134,7 @@ async function upgradeBaseRelations({ }); }); - await upgradeModelRelationsIndex({ + await upgradeModelRelationsIndex(context, { ncMeta, model: new Model(model), sqlClient, @@ -139,11 +151,8 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { ); // get all xcdb sources - const sources = await ncMeta.metaList2(null, null, MetaTable.BASES, { - condition: { - is_meta: 1, - }, - orderBy: {}, + const sources = await ncMeta.knexConnection(MetaTable.BASES).where({ + is_meta: 1, }); if (!sources.length) return; @@ -152,18 +161,23 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { for (const _base of sources) { const source = new Source(_base); + const context = { + workspace_id: source.fk_workspace_id, + base_id: source.id, + }; + // skip if not pg, since for other db we don't need to upgrade if (ncMeta.knex.clientType() !== 'pg') { continue; } - const base = await source.getProject(ncMeta); + const base = await source.getProject(context, ncMeta); // skip deleted bases if (!base || base.deleted) continue; logger.log(`Upgrading source '${source.alias}'(${base.title})`); - await upgradeBaseRelations({ + await upgradeBaseRelations(context, { ncMeta, source, }); diff --git a/packages/nocodb/src/version-upgrader/ncXcdbLTARUpgrader.ts b/packages/nocodb/src/version-upgrader/ncXcdbLTARUpgrader.ts index df1a662566..4d85c317e2 100644 --- a/packages/nocodb/src/version-upgrader/ncXcdbLTARUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/ncXcdbLTARUpgrader.ts @@ -2,6 +2,7 @@ import { RelationTypes, UITypes } from 'nocodb-sdk'; import type { LinkToAnotherRecordColumn } from '~/models'; import type { MetaService } from '~/meta/meta.service'; import type { NcUpgraderCtx } from './NcUpgrader'; +import type { NcContext } from '~/interface/config'; import { MetaTable } from '~/utils/globals'; import NocoCache from '~/cache/NocoCache'; import { Source } from '~/models'; @@ -13,34 +14,38 @@ import { Model } from '~/models'; // it will delete all the foreign keys and create a new index // and treat all the LTAR as virtual -async function upgradeModelRelations({ - model, - relations, - ncMeta, - sqlClient, -}: { - ncMeta: MetaService; - model: Model; - sqlClient: ReturnType< - (typeof NcConnectionMgrv2)['getSqlClient'] - > extends Promise - ? U - : ReturnType<(typeof NcConnectionMgrv2)['getSqlClient']>; - relations: { - tn: string; - rtn: string; - cn: string; - rcn: string; - cstn?: string; - }[]; -}) { +async function upgradeModelRelations( + context: NcContext, + { + model, + relations, + ncMeta, + sqlClient, + }: { + ncMeta: MetaService; + model: Model; + sqlClient: ReturnType< + (typeof NcConnectionMgrv2)['getSqlClient'] + > extends Promise + ? U + : ReturnType<(typeof NcConnectionMgrv2)['getSqlClient']>; + relations: { + tn: string; + rtn: string; + cn: string; + rcn: string; + cstn?: string; + }[]; + }, +) { // Iterate over each column and upgrade LTAR - for (const column of await model.getColumns(ncMeta)) { + for (const column of await model.getColumns(context, ncMeta)) { if (column.uidt !== UITypes.LinkToAnotherRecord) { continue; } const colOptions = await column.getColOptions( + context, ncMeta, ); @@ -57,11 +62,11 @@ async function upgradeModelRelations({ break; } - const parentCol = await colOptions.getParentColumn(ncMeta); - const childCol = await colOptions.getChildColumn(ncMeta); + const parentCol = await colOptions.getParentColumn(context, ncMeta); + const childCol = await colOptions.getChildColumn(context, ncMeta); - const parentModel = await parentCol.getModel(ncMeta); - const childModel = await childCol.getModel(ncMeta); + const parentModel = await parentCol.getModel(context, ncMeta); + const childModel = await childCol.getModel(context, ncMeta); // delete the foreign key constraint if exists const relation = relations.find((r) => { @@ -100,8 +105,8 @@ async function upgradeModelRelations({ // update the relation as virtual await ncMeta.metaUpdate( - null, - null, + context.workspace_id, + context.base_id, MetaTable.COL_RELATIONS, { virtual: true }, colOptions.id, @@ -123,23 +128,30 @@ async function upgradeModelRelations({ } // An upgrader for upgrading any existing relation in xcdb -async function upgradeBaseRelations({ - ncMeta, - source, - relations, -}: { - ncMeta: MetaService; - source: any; - relations: any; -}) { +async function upgradeBaseRelations( + context: NcContext, + { + ncMeta, + source, + relations, + }: { + ncMeta: MetaService; + source: any; + relations: any; + }, +) { const sqlClient = await NcConnectionMgrv2.getSqlClient(source, ncMeta.knex); // get models for the base - const models = await ncMeta.metaList2(null, source.id, MetaTable.MODELS); + const models = await ncMeta.metaList2( + context.workspace_id, + context.base_id, + MetaTable.MODELS, + ); // get all columns and filter out relations and upgrade for (const model of models) { - await upgradeModelRelations({ + await upgradeModelRelations(context, { ncMeta, model: new Model(model), sqlClient, @@ -151,11 +163,8 @@ async function upgradeBaseRelations({ // database to virtual relation and create an index for it export default async function ({ ncMeta }: NcUpgraderCtx) { // get all xcdb sources - const sources = await ncMeta.metaList2(null, null, MetaTable.BASES, { - condition: { - is_meta: 1, - }, - orderBy: {}, + const sources = await ncMeta.knexConnection(MetaTable.BASES).where({ + is_meta: 1, }); if (!sources.length) return; @@ -170,7 +179,11 @@ export default async function ({ ncMeta }: NcUpgraderCtx) { // iterate and upgrade each base for (const source of sources) { - await upgradeBaseRelations({ + const context = { + workspace_id: source.fk_workspace_id, + base_id: source.id, + }; + await upgradeBaseRelations(context, { ncMeta, source: new Source(source), relations, diff --git a/packages/nocodb/src/version-upgrader/v1-legacy/BaseApiBuilder.ts b/packages/nocodb/src/version-upgrader/v1-legacy/BaseApiBuilder.ts index 64e1e3a994..43b391ef58 100644 --- a/packages/nocodb/src/version-upgrader/v1-legacy/BaseApiBuilder.ts +++ b/packages/nocodb/src/version-upgrader/v1-legacy/BaseApiBuilder.ts @@ -13,6 +13,7 @@ import type { MysqlClient, PgClient, SqlClient } from 'nc-help'; import type { DbConfig, NcConfig } from '~/interface/config'; import ModelXcMetaFactory from '~/db/sql-mgr/code/models/xc/ModelXcMetaFactory'; import NcConnectionMgr from '~/utils/common/NcConnectionMgr'; +import { RootScopes } from '~/utils/globals'; const log = debug('nc:api:source'); @@ -186,8 +187,8 @@ export default abstract class BaseApiBuilder { // update version in meta after each upgrade configObj.version = version.name; await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_store', { value: JSON.stringify(configObj), @@ -205,8 +206,8 @@ export default abstract class BaseApiBuilder { } configObj.version = process.env.NC_VERSION; await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_store', { value: JSON.stringify(configObj), @@ -221,13 +222,20 @@ export default abstract class BaseApiBuilder { const configObj: NcConfig = JSON.parse(JSON.stringify(this.config)); delete configObj.envs; const isOld = ( - await this.xcMeta.metaList(this.baseId, this.dbAlias, 'nc_models') + await this.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models') )?.length; configObj.version = isOld ? '0009000' : process.env.NC_VERSION; - await this.xcMeta.metaInsert(this.baseId, this.dbAlias, 'nc_store', { - key: 'NC_CONFIG', - value: JSON.stringify(configObj), - }); + await this.xcMeta.metaInsert2( + context.workspace_id, + context.base_id, + 'nc_store', + { + key: 'NC_CONFIG', + value: JSON.stringify(configObj), + dbAlias: this.dbAlias, + }, + true, + ); if (isOld) { await this.xcUpgrade(); } @@ -340,17 +348,12 @@ export default abstract class BaseApiBuilder { } protected async ncUpManyToMany(_ctx: any): Promise { - const models = await this.xcMeta.metaList( - this.baseId, - this.dbAlias, - 'nc_models', - { - fields: ['meta'], - condition: { - type: 'table', - }, + const models = await this.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', { + fields: ['meta'], + condition: { + type: 'table', }, - ); + }); if (!models.length) { return; } @@ -381,8 +384,8 @@ export default abstract class BaseApiBuilder { ).mapDefaultDisplayValue(meta.columns); // update meta await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { meta: JSON.stringify(meta), @@ -537,8 +540,8 @@ export default abstract class BaseApiBuilder { }), ]; await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { meta: JSON.stringify(meta), @@ -555,8 +558,8 @@ export default abstract class BaseApiBuilder { // Update metadata of associative table for (const meta of assocMetas) { await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { mm: 1, diff --git a/packages/nocodb/src/version-upgrader/v1-legacy/gql/GqlApiBuilder.ts b/packages/nocodb/src/version-upgrader/v1-legacy/gql/GqlApiBuilder.ts index 8b0cc33852..69e2393a03 100644 --- a/packages/nocodb/src/version-upgrader/v1-legacy/gql/GqlApiBuilder.ts +++ b/packages/nocodb/src/version-upgrader/v1-legacy/gql/GqlApiBuilder.ts @@ -31,17 +31,12 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { } protected async ncUpAddNestedResolverArgs(_ctx: any): Promise { - const models = await this.xcMeta.metaList( - this.baseId, - this.dbAlias, - 'nc_models', - { - fields: ['meta'], - condition: { - type: 'table', - }, + const models = await this.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', { + fields: ['meta'], + condition: { + type: 'table', }, - ); + }); if (!models.length) { return; } @@ -70,8 +65,8 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { /* update schema in metadb */ await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { schema, @@ -113,8 +108,8 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { /* update schema in metadb */ await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { schema, @@ -129,9 +124,9 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { if (meta.manyToMany) { for (const mm of meta.manyToMany) { - await this.xcMeta.metaInsert( - this.baseId, - this.dbAlias, + await this.xcMeta.metaInsert2( + context.workspace_id, + context.base_id, 'nc_loaders', { title: `${mm.tn}Mm${mm.rtn}List`, @@ -139,7 +134,9 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { child: mm.rtn, relation: 'mm', resolver: 'mmlist', + dbAlias: this.dbAlias, }, + true, ); } } diff --git a/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncModelsOrderUpgrader.ts b/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncModelsOrderUpgrader.ts index 29c811525d..470f18085f 100644 --- a/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncModelsOrderUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncModelsOrderUpgrader.ts @@ -1,21 +1,16 @@ import type { NcBuilderUpgraderCtx } from '../BaseApiBuilder'; export default async function (ctx: NcBuilderUpgraderCtx) { - const models = await ctx.xcMeta.metaList( - ctx.baseId, - ctx.dbAlias, - 'nc_models', - { - xcCondition: { - _or: [{ type: { eq: 'table' } }, { type: { eq: 'view' } }], - }, + const models = await ctx.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', { + xcCondition: { + _or: [{ type: { eq: 'table' } }, { type: { eq: 'view' } }], }, - ); + }); let order = 0; for (const model of models) { await ctx.xcMeta.metaUpdate( - ctx.baseId, - ctx.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { order: ++order, @@ -24,19 +19,14 @@ export default async function (ctx: NcBuilderUpgraderCtx) { model.id, ); - const views = await ctx.xcMeta.metaList( - ctx.baseId, - ctx.dbAlias, - 'nc_models', - { - condition: { parent_model_title: model.title }, - }, - ); + const views = await ctx.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', { + condition: { parent_model_title: model.title }, + }); let view_order = 1; for (const view of views) { await ctx.xcMeta.metaUpdate( - ctx.baseId, - ctx.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { view_order: ++view_order, diff --git a/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncParentModelTitleUpgrader.ts b/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncParentModelTitleUpgrader.ts index a49b146ecb..fe7060a92b 100644 --- a/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncParentModelTitleUpgrader.ts +++ b/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncParentModelTitleUpgrader.ts @@ -1,21 +1,16 @@ import type { NcBuilderUpgraderCtx } from '../BaseApiBuilder'; export default async function (ctx: NcBuilderUpgraderCtx) { - const views = await ctx.xcMeta.metaList( - ctx.baseId, - ctx.dbAlias, - 'nc_models', - { - condition: { - type: 'vtable', - }, + const views = await ctx.xcMeta.metaList2(context.workspace_id, context.base_id, 'nc_models', { + condition: { + type: 'vtable', }, - ); + }); for (const view of views) { await ctx.xcMeta.metaUpdate( - ctx.baseId, - ctx.dbAlias, + context.workspace_id, + context.base_id, 'nc_disabled_models_for_role', { parent_model_title: view.parent_model_title, diff --git a/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncRemoveDuplicatedRelationRows.ts b/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncRemoveDuplicatedRelationRows.ts index b597a69f36..d1a35fa8c8 100644 --- a/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncRemoveDuplicatedRelationRows.ts +++ b/packages/nocodb/src/version-upgrader/v1-legacy/jobs/ncRemoveDuplicatedRelationRows.ts @@ -2,9 +2,9 @@ import type { NcBuilderUpgraderCtx } from '../BaseApiBuilder'; export default async function (ctx: NcBuilderUpgraderCtx) { try { - const relations = await ctx.xcMeta.metaList( - ctx.baseId, - ctx.dbAlias, + const relations = await ctx.xcMeta.metaList2( + context.workspace_id, + context.base_id, 'nc_relations', ); @@ -27,12 +27,11 @@ export default async function (ctx: NcBuilderUpgraderCtx) { // delete relation for (const dupRelation of duplicates) { - await ctx.xcMeta.metaDelete( - ctx.baseId, - ctx.dbAlias, - 'nc_relations', - dupRelation.id, - ); + await ctx.xcMeta.metaDeleteAll('nc_relations', { + id: dupRelation.id, + base_id: ctx.baseId, + db_alias: ctx.dbAlias, + }); { const tnModel = await ctx.xcMeta.metaGet( ctx.baseId, @@ -60,8 +59,8 @@ export default async function (ctx: NcBuilderUpgraderCtx) { } await ctx.xcMeta.metaUpdate( - ctx.baseId, - ctx.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { meta: JSON.stringify(meta) }, { @@ -96,8 +95,8 @@ export default async function (ctx: NcBuilderUpgraderCtx) { meta.hasMany.splice(meta.hasMany.indexOf(duplicateHms[1]), 1); } await ctx.xcMeta.metaUpdate( - ctx.baseId, - ctx.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { meta: JSON.stringify(meta) }, { diff --git a/packages/nocodb/src/version-upgrader/v1-legacy/rest/RestApiBuilder.ts b/packages/nocodb/src/version-upgrader/v1-legacy/rest/RestApiBuilder.ts index cc7f23d8c2..cc5977aa34 100644 --- a/packages/nocodb/src/version-upgrader/v1-legacy/rest/RestApiBuilder.ts +++ b/packages/nocodb/src/version-upgrader/v1-legacy/rest/RestApiBuilder.ts @@ -73,9 +73,9 @@ export class RestApiBuilder extends BaseApiBuilder { }, )) ) { - await this.xcMeta.metaInsert( - this.baseId, - this.dbAlias, + await this.xcMeta.metaInsert2( + context.workspace_id, + context.base_id, 'nc_routes', { acl: JSON.stringify(route.acl), @@ -85,12 +85,14 @@ export class RestApiBuilder extends BaseApiBuilder { tn: meta.tn, title: meta.tn, type: route.type, + dbAlias: this.dbAlias, }, + true, ); } else { await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_routes', { order: i, @@ -155,8 +157,8 @@ export class RestApiBuilder extends BaseApiBuilder { oldSwaggerDoc.definitions = swaggerDoc.definitions; await this.xcMeta.metaUpdate( - this.baseId, - this.dbAlias, + context.workspace_id, + context.base_id, 'nc_models', { schema: JSON.stringify(oldSwaggerDoc), diff --git a/packages/nocodb/tests/unit/factory/base.ts b/packages/nocodb/tests/unit/factory/base.ts index 99e8b3e8c5..3e7368c5fb 100644 --- a/packages/nocodb/tests/unit/factory/base.ts +++ b/packages/nocodb/tests/unit/factory/base.ts @@ -73,7 +73,13 @@ const createSakilaProject = async (context) => { .set('xc-auth', context.token) .send(sakilaProjectConfig(context)); - return (await Base.getByTitleOrId(response.body.id)) as Base; + return (await Base.getByTitleOrId( + { + workspace_id: response.body.fk_workspace_id, + base_id: response.body.id, + }, + response.body.id, + )) as Base; }; const createProject = async ( @@ -88,7 +94,13 @@ const createProject = async ( ...(process.env.EE ? { fk_workspace_id: context.fk_workspace_id } : {}), }); - return (await Base.getByTitleOrId(response.body.id)) as Base; + return (await Base.getByTitleOrId( + { + workspace_id: response.body.fk_workspace_id, + base_id: response.body.id, + }, + response.body.id, + )) as Base; }; export { createProject, createSharedBase, createSakilaProject }; diff --git a/packages/nocodb/tests/unit/factory/column.ts b/packages/nocodb/tests/unit/factory/column.ts index bc4f797a50..506e560c4d 100644 --- a/packages/nocodb/tests/unit/factory/column.ts +++ b/packages/nocodb/tests/unit/factory/column.ts @@ -184,6 +184,11 @@ const customColumns = function (type: string, options: any = {}) { }; const createColumn = async (context, table, columnAttr) => { + const ctx = { + workspace_id: table.fk_workspace_id, + base_id: table.base_id, + }; + await request(context.app) .post(`/api/v1/db/meta/tables/${table.id}/columns`) .set('xc-auth', context.token) @@ -191,7 +196,7 @@ const createColumn = async (context, table, columnAttr) => { ...columnAttr, }); - const column: Column = (await table.getColumns()).find( + const column: Column = (await table.getColumns(ctx)).find( (column) => column.title === columnAttr.title, ); return column; @@ -215,18 +220,23 @@ const createRollupColumn = async ( relatedTableColumnTitle: string; }, ) => { + const ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + const childBases = await base.getSources(); - const childTable = await Model.getByIdOrName({ + const childTable = await Model.getByIdOrName(ctx, { base_id: base.id, source_id: childBases[0].id!, table_name: relatedTableName, }); - const childTableColumns = await childTable.getColumns(); + const childTableColumns = await childTable.getColumns(ctx); const childTableColumn = await childTableColumns.find( (column) => column.title === relatedTableColumnTitle, ); - const ltarColumn = (await table.getColumns()).find( + const ltarColumn = (await table.getColumns(ctx)).find( (column) => (column.uidt === UITypes.Links || column.uidt === UITypes.LinkToAnotherRecord) && @@ -264,13 +274,18 @@ const createLookupColumn = async ( relationColumnId?: string; }, ) => { + const ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + const childBases = await base.getSources(); - const childTable = await Model.getByIdOrName({ + const childTable = await Model.getByIdOrName(ctx, { base_id: base.id, source_id: childBases[0].id!, table_name: relatedTableName, }); - const childTableColumns = await childTable.getColumns(); + const childTableColumns = await childTable.getColumns(ctx); const childTableColumn = await childTableColumns.find( (column) => column.title === relatedTableColumnTitle, ); @@ -283,11 +298,11 @@ const createLookupColumn = async ( let ltarColumn; if (relationColumnId) - ltarColumn = (await table.getColumns()).find( + ltarColumn = (await table.getColumns(ctx)).find( (column) => column.id === relationColumnId, ); else { - ltarColumn = (await table.getColumns()).find( + ltarColumn = (await table.getColumns(ctx)).find( (column) => (column.uidt === UITypes.Links || column.uidt === UITypes.LinkToAnotherRecord) && @@ -319,7 +334,12 @@ const createQrCodeColumn = async ( referencedQrValueTableColumnTitle: string; }, ) => { - const columns = await table.getColumns(); + const ctx = { + workspace_id: table.fk_workspace_id, + base_id: table.base_id, + }; + + const columns = await table.getColumns(ctx); const referencedQrValueTableColumnId = columns.find( (column) => column.title == referencedQrValueTableColumnTitle, )['id']; @@ -346,7 +366,10 @@ const createBarcodeColumn = async ( }, ) => { const referencedBarcodeValueTableColumnId = await table - .getColumns() + .getColumns({ + workspace_id: table.fk_workspace_id, + base_id: table.base_id, + }) .then( (cols) => cols.find( @@ -393,6 +416,11 @@ const updateViewColumn = async ( context, { view, column, attr }: { column: Column; view: View; attr: any }, ) => { + const ctx = { + workspace_id: view.fk_workspace_id, + base_id: view.base_id, + }; + const res = await request(context.app) .patch(`/api/v1/db/meta/views/${view.id}/columns/${column.id}`) .set('xc-auth', context.token) @@ -401,7 +429,7 @@ const updateViewColumn = async ( }); const updatedColumn: FormViewColumn | GridViewColumn | GalleryViewColumn = ( - await view.getColumns() + await view.getColumns(ctx) ).find((column) => column.id === column.id)!; return updatedColumn; @@ -411,6 +439,11 @@ const updateColumn = async ( context, { table, column, attr }: { column: Column; table: Model; attr: any }, ) => { + const ctx = { + workspace_id: table.fk_workspace_id, + base_id: table.base_id, + }; + const res = await request(context.app) .patch(`/api/v2/meta/columns/${column.id}`) .set('xc-auth', context.token) @@ -418,7 +451,7 @@ const updateColumn = async ( ...attr, }); - const updatedColumn: Column = (await table.getColumns()).find( + const updatedColumn: Column = (await table.getColumns(ctx)).find( (column) => column.id === column.id, ); return updatedColumn; diff --git a/packages/nocodb/tests/unit/factory/row.ts b/packages/nocodb/tests/unit/factory/row.ts index ecddfb6ce3..d2bcc0ce97 100644 --- a/packages/nocodb/tests/unit/factory/row.ts +++ b/packages/nocodb/tests/unit/factory/row.ts @@ -219,7 +219,7 @@ const listRow = async ({ base, table, options, - view + view, }: { base: Base; table: Model; @@ -231,8 +231,13 @@ const listRow = async ({ sortArr?: Sort[]; }; }) => { + const ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + const sources = await base.getSources(); - const baseModel = await Model.getBaseModelSQL({ + const baseModel = await Model.getBaseModelSQL(ctx, { id: table.id, dbDriver: await NcConnectionMgrv2.get(sources[0]!), viewId: view?.id, @@ -287,7 +292,12 @@ const createRow = async ( index?: number; }, ) => { - const columns = await table.getColumns(); + const ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + + const columns = await table.getColumns(ctx); const rowData = generateDefaultRowAttributes({ columns, index }); const response = await request(context.app) diff --git a/packages/nocodb/tests/unit/factory/table.ts b/packages/nocodb/tests/unit/factory/table.ts index 52d5760549..e8e1acb1d9 100644 --- a/packages/nocodb/tests/unit/factory/table.ts +++ b/packages/nocodb/tests/unit/factory/table.ts @@ -16,7 +16,13 @@ const createTable = async (context, base, args = {}) => { .set('xc-auth', context.token) .send({ ...defaultValue, ...args }); - const table: Model = await Model.get(response.body.id); + const table: Model = await Model.get( + { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }, + response.body.id, + ); return table; }; @@ -38,19 +44,31 @@ const getColumnsByAPI = async (context, base, table) => { const getTable = async ({ base, name }: { base: Base; name: string }) => { const sources = await base.getSources(); - return await Model.getByIdOrName({ - base_id: base.id, - source_id: sources[0].id!, - table_name: name, - }); + return await Model.getByIdOrName( + { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }, + { + base_id: base.id, + source_id: sources[0].id!, + table_name: name, + }, + ); }; const getAllTables = async ({ base }: { base: Base }) => { const sources = await base.getSources(); - const tables = await Model.list({ - base_id: base.id, - source_id: sources[0].id!, - }); + const tables = await Model.list( + { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }, + { + base_id: base.id, + source_id: sources[0].id!, + }, + ); return tables; }; diff --git a/packages/nocodb/tests/unit/factory/view.ts b/packages/nocodb/tests/unit/factory/view.ts index 99deecdb08..ef17b214f4 100644 --- a/packages/nocodb/tests/unit/factory/view.ts +++ b/packages/nocodb/tests/unit/factory/view.ts @@ -20,6 +20,11 @@ const createView = async ( }; }, ) => { + const ctx = { + workspace_id: table.fk_workspace_id, + base_id: table.base_id, + }; + const viewTypeStr = (type) => { switch (type) { case ViewTypes.GALLERY: @@ -49,7 +54,7 @@ const createView = async ( throw new Error('createView', response.body.message); } - return (await View.getByTitleOrId({ + return (await View.getByTitleOrId(ctx, { fk_model_id: table.id, titleOrId: title, })) as View; @@ -59,6 +64,11 @@ const getView = async ( context, { table, name }: { table: Model; name: string }, ) => { + const ctx = { + workspace_id: table.fk_workspace_id, + base_id: table.base_id, + }; + const response = await request(context.app) .get(`/api/v1/db/meta/tables/${table.id}/views`) .set('xc-auth', context.token); @@ -66,7 +76,7 @@ const getView = async ( throw new Error('List Views', response.body.message); } const _view = response.body.list.find((v) => v.title === name); - const view = View.getByTitleOrId({ + const view = View.getByTitleOrId(ctx, { titleOrId: _view.id, fk_model_id: _view.fk_model_id, }); @@ -89,6 +99,11 @@ const updateView = async ( field?: any[]; }, ) => { + const ctx = { + workspace_id: table.fk_workspace_id, + base_id: table.base_id, + }; + if (filter.length) { for (let i = 0; i < filter.length; i++) { await request(context.app) @@ -111,8 +126,8 @@ const updateView = async ( if (field.length) { for (let i = 0; i < field.length; i++) { - const columns = await table.getColumns(); - const viewColumns = await view.getColumns(); + const columns = await table.getColumns(ctx); + const viewColumns = await view.getColumns(ctx); const columnId = columns.find((c) => c.title === field[i]).id; const viewColumnId = viewColumns.find( diff --git a/packages/nocodb/tests/unit/init/cleanupMeta.ts b/packages/nocodb/tests/unit/init/cleanupMeta.ts index e03a8500a7..2ba0fd5601 100644 --- a/packages/nocodb/tests/unit/init/cleanupMeta.ts +++ b/packages/nocodb/tests/unit/init/cleanupMeta.ts @@ -14,10 +14,16 @@ const dropTablesAllNonExternalProjects = async () => { const source = base.sources && base.sources[0]; if (!source) return; - const models = await Model.list({ - base_id: base.id, - source_id: source.id!, - }); + const models = await Model.list( + { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }, + { + base_id: base.id, + source_id: source.id!, + }, + ); models.forEach((model) => { userCreatedTableNames.push(model.table_name); }); diff --git a/packages/nocodb/tests/unit/init/cleanupSakila.ts b/packages/nocodb/tests/unit/init/cleanupSakila.ts index 2587b7212d..f3a5e9089b 100644 --- a/packages/nocodb/tests/unit/init/cleanupSakila.ts +++ b/packages/nocodb/tests/unit/init/cleanupSakila.ts @@ -1,5 +1,6 @@ -import { Audit, Base } from '../../../src/models' +import { Audit, Base } from '../../../src/models'; import TestDbMngr from '../TestDbMngr'; +import { RootScopes } from '../../../src/utils/globals'; const dropTablesOfSakila = async () => { await TestDbMngr.disableForeignKeyChecks(TestDbMngr.sakilaKnex); @@ -8,7 +9,7 @@ const dropTablesOfSakila = async () => { try { if (TestDbMngr.isPg()) { await TestDbMngr.sakilaKnex.raw( - `DROP TABLE IF EXISTS "${tableName}" CASCADE` + `DROP TABLE IF EXISTS "${tableName}" CASCADE`, ); } else { await TestDbMngr.sakilaKnex.raw(`DROP TABLE ${tableName}`); @@ -41,7 +42,13 @@ const resetAndSeedSakila = async () => { const cleanUpSakila = async (forceReset) => { try { - const sakilaProject = await Base.getByTitle('sakila'); + const sakilaProject = await Base.getByTitle( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + 'sakila', + ); const audits = sakilaProject && (await Audit.baseAuditList(sakilaProject.id, {})); @@ -56,7 +63,7 @@ const cleanUpSakila = async (forceReset) => { } const tablesInSakila = await TestDbMngr.showAllTables( - TestDbMngr.sakilaKnex + TestDbMngr.sakilaKnex, ); await Promise.all( @@ -66,7 +73,7 @@ const cleanUpSakila = async (forceReset) => { try { if (TestDbMngr.isPg()) { await TestDbMngr.sakilaKnex.raw( - `DROP TABLE "${tableName}" CASCADE` + `DROP TABLE "${tableName}" CASCADE`, ); } else { await TestDbMngr.sakilaKnex.raw(`DROP TABLE ${tableName}`); @@ -74,7 +81,7 @@ const cleanUpSakila = async (forceReset) => { } catch (e) { console.error(e); } - }) + }), ); } catch (e) { console.error('cleanUpSakila', e); diff --git a/packages/nocodb/tests/unit/model/tests/baseModelSql.test.ts b/packages/nocodb/tests/unit/model/tests/baseModelSql.test.ts index a33ce60bd7..de933c661f 100644 --- a/packages/nocodb/tests/unit/model/tests/baseModelSql.test.ts +++ b/packages/nocodb/tests/unit/model/tests/baseModelSql.test.ts @@ -18,6 +18,10 @@ import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; function baseModelSqlTests() { let context; + let ctx: { + workspace_id: string; + base_id: string; + }; let base: Base; let table: Model; let view: View; @@ -27,14 +31,21 @@ function baseModelSqlTests() { console.time('#### baseModelSqlTests'); context = await init(); base = await createProject(context); + + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + table = await createTable(context, base); - view = await table.getViews()[0]; + view = await table.getViews(ctx)[0]; - const source = await Source.get(table.source_id); + const source = await Source.get(ctx, table.source_id); baseModelSql = new BaseModelSqlv2({ dbDriver: await NcConnectionMgrv2.get(source), model: table, view, + context: ctx, }); console.timeEnd('#### baseModelSqlTests'); }); @@ -44,7 +55,7 @@ function baseModelSqlTests() { clientIp: '::ffff:192.0.0.1', user: context.user, }; - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const inputData: any = generateDefaultRowAttributes({ columns }); const response = await baseModelSql.insert( @@ -74,7 +85,7 @@ function baseModelSqlTests() { }); it('Bulk insert record', async () => { - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const request = { clientIp: '::ffff:192.0.0.1', user: context.user, @@ -125,7 +136,7 @@ function baseModelSqlTests() { user: context.user, }; - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); await baseModelSql.insert(generateDefaultRowAttributes({ columns })); const rowId = 1; @@ -158,7 +169,7 @@ function baseModelSqlTests() { // Since sqlite doesn't support multiple sql connections, we can't test bulk update in sqlite if (isSqlite(context)) return; - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const request = { clientIp: '::ffff:192.0.0.1', user: context.user, @@ -202,7 +213,7 @@ function baseModelSqlTests() { }); it('Bulk update all record', async () => { - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const request = { clientIp: '::ffff:192.0.0.1', user: context.user, @@ -259,7 +270,7 @@ function baseModelSqlTests() { params: { id: 1 }, }; - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const bulkData = Array(10) .fill(0) .map((_, index) => generateDefaultRowAttributes({ columns, index })); @@ -290,7 +301,7 @@ function baseModelSqlTests() { }); it('Bulk delete records', async () => { - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const request = { clientIp: '::ffff:192.0.0.1', user: context.user, @@ -333,7 +344,7 @@ function baseModelSqlTests() { }); it('Bulk delete all record', async () => { - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const request = { clientIp: '::ffff:192.0.0.1', user: context.user, @@ -396,10 +407,10 @@ function baseModelSqlTests() { table: childTable, }); const ltarColOptions = - await ltarColumn.getColOptions(); - const childCol = await ltarColOptions.getChildColumn(); + await ltarColumn.getColOptions(ctx); + const childCol = await ltarColOptions.getChildColumn(ctx); - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const request = { clientIp: '::ffff:192.0.0.1', user: context.user, @@ -415,9 +426,12 @@ function baseModelSqlTests() { ); const childBaseModel = new BaseModelSqlv2({ - dbDriver: await NcConnectionMgrv2.get(await Source.get(table.source_id)), + dbDriver: await NcConnectionMgrv2.get( + await Source.get(ctx, table.source_id), + ), model: childTable, view, + context: ctx, }); const insertedChildRow = await childBaseModel.readByPk(childRow['Id']); expect(insertedChildRow[childCol.column_name]).to.equal(childRow['Id']); @@ -455,10 +469,10 @@ function baseModelSqlTests() { table: childTable, }); const ltarColOptions = - await ltarColumn.getColOptions(); - const childCol = await ltarColOptions.getChildColumn(); + await ltarColumn.getColOptions(ctx); + const childCol = await ltarColOptions.getChildColumn(ctx); - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const request = { clientIp: '::ffff:192.0.0.1', user: context.user, @@ -479,9 +493,12 @@ function baseModelSqlTests() { }); const childBaseModel = new BaseModelSqlv2({ - dbDriver: await NcConnectionMgrv2.get(await Source.get(table.source_id)), + dbDriver: await NcConnectionMgrv2.get( + await Source.get(ctx, table.source_id), + ), model: childTable, view, + context: ctx, }); const updatedChildRow = await childBaseModel.readByPk( insertedChildRow['Id'], @@ -523,10 +540,10 @@ function baseModelSqlTests() { table: childTable, }); const ltarColOptions = - await ltarColumn.getColOptions(); - const childCol = await ltarColOptions.getChildColumn(); + await ltarColumn.getColOptions(ctx); + const childCol = await ltarColOptions.getChildColumn(ctx); - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const request = { clientIp: '::ffff:192.0.0.1', user: context.user, @@ -554,9 +571,12 @@ function baseModelSqlTests() { }); const childBaseModel = new BaseModelSqlv2({ - dbDriver: await NcConnectionMgrv2.get(await Source.get(table.source_id)), + dbDriver: await NcConnectionMgrv2.get( + await Source.get(ctx, table.source_id), + ), model: childTable, view, + context: ctx, }); const updatedChildRow = await childBaseModel.readByPk( insertedChildRow['Id'], diff --git a/packages/nocodb/tests/unit/rest/tests/base.test.ts b/packages/nocodb/tests/unit/rest/tests/base.test.ts index 8783f4dc2f..89a785adcd 100644 --- a/packages/nocodb/tests/unit/rest/tests/base.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/base.test.ts @@ -7,6 +7,7 @@ import { Base } from '../../../../src/models'; import { createTable } from '../../factory/table'; import init from '../../init'; import { createProject, createSharedBase } from '../../factory/base'; +import { RootScopes } from '../../../../src/utils/globals'; // Test case list // 1. Get base info @@ -87,7 +88,13 @@ function baseTest() { }) .expect(200); - const newProject = await Base.getByTitleOrId(response.body.id); + const newProject = await Base.getByTitleOrId( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + response.body.id, + ); if (!newProject) return new Error('Base not created'); }); @@ -147,7 +154,13 @@ function baseTest() { }) .expect(200); - const newProject = await Base.getByTitleOrId(base.id); + const newProject = await Base.getByTitleOrId( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + base.id, + ); if (newProject.title !== 'NewTitle') { return new Error('Base not updated'); } @@ -180,7 +193,13 @@ function baseTest() { }) .expect(200); - const updatedProject = await Base.getByTitleOrId(base.id); + const updatedProject = await Base.getByTitleOrId( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + base.id, + ); if ( !updatedProject.uuid || @@ -201,7 +220,13 @@ function baseTest() { }) .expect(200); - const updatedProject = await Base.getByTitleOrId(base.id); + const updatedProject = await Base.getByTitleOrId( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + base.id, + ); if (updatedProject.roles === 'commenter') { return new Error('Shared base not configured properly'); @@ -220,7 +245,13 @@ function baseTest() { }) .expect(200); - const updatedProject = await Base.getByTitleOrId(base.id); + const updatedProject = await Base.getByTitleOrId( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + base.id, + ); if (updatedProject.roles === 'commenter') { throw new Exception('Shared base not updated properly'); @@ -238,7 +269,13 @@ function baseTest() { password: 'password123', }) .expect(200); - const updatedProject = await Base.getByTitleOrId(base.id); + const updatedProject = await Base.getByTitleOrId( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + base.id, + ); if (updatedProject.roles !== 'editor') { throw new Exception('Shared base not updated properly'); @@ -254,7 +291,13 @@ function baseTest() { .send() .expect(200); - const updatedProject = await Base.getByTitleOrId(base.id); + const updatedProject = await Base.getByTitleOrId( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + base.id, + ); if (!updatedProject.uuid) { throw new Exception('Shared base not created'); } @@ -268,7 +311,13 @@ function baseTest() { .set('xc-auth', context.token) .send() .expect(200); - const updatedProject = await Base.getByTitleOrId(base.id); + const updatedProject = await Base.getByTitleOrId( + { + workspace_id: RootScopes.BASE, + base_id: RootScopes.BASE, + }, + base.id, + ); if (updatedProject.uuid) { throw new Exception('Shared base not deleted'); } diff --git a/packages/nocodb/tests/unit/rest/tests/columnTypeSpecific.test.ts b/packages/nocodb/tests/unit/rest/tests/columnTypeSpecific.test.ts index 306660002d..f6228890ed 100644 --- a/packages/nocodb/tests/unit/rest/tests/columnTypeSpecific.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/columnTypeSpecific.test.ts @@ -106,9 +106,14 @@ function columnTypeSpecificTests() { }); it('gets deleted if the referenced column gets deleted', async () => { + const ctx = { + workspace_id: sakilaProject.fk_workspace_id, + base_id: sakilaProject.id, + }; + // delete referenced value column const columnsBeforeReferencedColumnDeleted = - await customerTable.getColumns(); + await customerTable.getColumns(ctx); expect( columnsBeforeReferencedColumnDeleted.some( @@ -122,7 +127,7 @@ function columnTypeSpecificTests() { .send({}); const columnsAfterReferencedColumnDeleted = - await customerTable.getColumns(); + await customerTable.getColumns(ctx); expect( columnsAfterReferencedColumnDeleted.some( (col) => col['title'] === qrCodeReferenceColumnTitle, @@ -158,7 +163,12 @@ function columnTypeSpecificTests() { ], }); - columns = await table.getColumns(); + const ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + + columns = await table.getColumns(ctx); const rowAttributes: any = []; for (let i = 0; i < 100; i++) { diff --git a/packages/nocodb/tests/unit/rest/tests/filter.test.ts b/packages/nocodb/tests/unit/rest/tests/filter.test.ts index 318aab464a..ace17578c3 100644 --- a/packages/nocodb/tests/unit/rest/tests/filter.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/filter.test.ts @@ -7,7 +7,7 @@ import { createProject } from '../../factory/base'; import Base from '~/models/Base'; import { createTable } from '../../factory/table'; import { createBulkRows, listRow, rowMixedValue } from '../../factory/row'; -import Model from '../../../../src/models/Model'; +import type Model from '../../../../src/models/Model'; const debugMode = true; @@ -179,6 +179,10 @@ async function retrieveRecordsAndValidate( } let context; +let ctx: { + workspace_id: string; + base_id: string; +}; let base: Base; let table: Model; let columns: any[]; @@ -206,6 +210,12 @@ function filterTextBased() { console.time('#### filterTextBased'); context = await init(); base = await createProject(context); + + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + table = await createTable(context, base, { table_name: 'textBased', title: 'TextBased', @@ -243,7 +253,7 @@ function filterTextBased() { ], }); - columns = await table.getColumns(); + columns = await table.getColumns(ctx); const rowAttributes = []; for (let i = 0; i < 400; i++) { @@ -346,6 +356,12 @@ function filterNumberBased() { console.time('#### filterNumberBased'); context = await init(); base = await createProject(context); + + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + table = await createTable(context, base, { table_name: 'numberBased', title: 'numberBased', @@ -388,7 +404,7 @@ function filterNumberBased() { ], }); - columns = await table.getColumns(); + columns = await table.getColumns(ctx); const rowAttributes = []; for (let i = 0; i < 400; i++) { @@ -506,6 +522,12 @@ function filterSelectBased() { console.time('#### filterSelectBased'); context = await init(); base = await createProject(context); + + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + table = await createTable(context, base, { table_name: 'selectBased', title: 'selectBased', @@ -530,7 +552,7 @@ function filterSelectBased() { ], }); - columns = await table.getColumns(); + columns = await table.getColumns(ctx); const rowAttributes = []; for (let i = 0; i < 400; i++) { @@ -610,6 +632,12 @@ function filterDateBased() { console.time('#### filterDateBased'); context = await init(); base = await createProject(context); + + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + table = await createTable(context, base, { table_name: 'dateBased', title: 'dateBased', @@ -627,7 +655,7 @@ function filterDateBased() { ], }); - columns = await table.getColumns(); + columns = await table.getColumns(ctx); const rowAttributes = []; for (let i = 0; i < 800; i++) { diff --git a/packages/nocodb/tests/unit/rest/tests/formula.test.ts b/packages/nocodb/tests/unit/rest/tests/formula.test.ts index c00167cb80..3b7687bb6b 100644 --- a/packages/nocodb/tests/unit/rest/tests/formula.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/formula.test.ts @@ -10,6 +10,10 @@ import type Model from '../../../../src/models/Model'; import type Base from '~/models/Base'; let context; +let ctx: { + workspace_id: string; + base_id: string; +}; let base: Base; let table: Model; let columns: any[]; @@ -20,6 +24,12 @@ function formulaRegExpBased() { beforeEach(async function () { context = await init(); base = await createProject(context); + + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + table = await createTable(context, base, { table_name: 'sampleTable', title: 'sampleTable', @@ -43,7 +53,7 @@ function formulaRegExpBased() { ], }); - columns = await table.getColumns(); + columns = await table.getColumns(ctx); const rowAttributes = []; for (let i = 0; i < 100; i++) { diff --git a/packages/nocodb/tests/unit/rest/tests/groupby.test.ts b/packages/nocodb/tests/unit/rest/tests/groupby.test.ts index 0c9f05ab4b..dab35c11b7 100644 --- a/packages/nocodb/tests/unit/rest/tests/groupby.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/groupby.test.ts @@ -12,6 +12,10 @@ import 'mocha'; function groupByTests() { let context; + let ctx: { + workspace_id: string; + base_id: string; + }; let sakilaProject: Base; let filmTable: Model; let filmColumns: Array; @@ -23,6 +27,11 @@ function groupByTests() { context = await init(); sakilaProject = await createSakilaProject(context); + ctx = { + workspace_id: sakilaProject.fk_workspace_id, + base_id: sakilaProject.id, + }; + await createProject(context); filmTable = await getTable({ @@ -30,7 +39,7 @@ function groupByTests() { name: 'film', }); filmView = await getView(context, { table: filmTable, name: 'Film' }); - filmColumns = await filmTable.getColumns(); + filmColumns = await filmTable.getColumns(ctx); const columns = ( await request(context.app) diff --git a/packages/nocodb/tests/unit/rest/tests/newDataApis.test.ts b/packages/nocodb/tests/unit/rest/tests/newDataApis.test.ts index 451188e321..68849de572 100644 --- a/packages/nocodb/tests/unit/rest/tests/newDataApis.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/newDataApis.test.ts @@ -112,6 +112,14 @@ import type Model from '../../../../src/models/Model'; const debugMode = false; let context; +let ctx: { + workspace_id: string; + base_id: string; +}; +let sakilaCtx: { + workspace_id: string; + base_id: string; +}; let base: Base; let table: Model; let columns: any[]; @@ -127,8 +135,6 @@ let countryColumns; let cityTable: Model; let cityColumns; -const unauthorizedResponse = process.env.EE !== 'true' ? 404 : 403; - // Optimisation scope for time reduction // 1. BeforeEach can be changed to BeforeAll for List and Read APIs @@ -224,7 +230,8 @@ async function ncAxiosLinkGet({ if (debugMode && status !== 200) { console.log('#### ', response.body.message || response.body.msg); } - if (!debugMode && msg) expect(response.body.message || response.body.msg).to.equal(msg); + if (!debugMode && msg) + expect(response.body.message || response.body.msg).to.equal(msg); return response; } @@ -251,7 +258,8 @@ async function ncAxiosLinkAdd({ console.log('#### ', response.body.message || response.body.msg); } - if (!debugMode && msg) expect(response.body.message || response.body.msg).to.equal(msg); + if (!debugMode && msg) + expect(response.body.message || response.body.msg).to.equal(msg); return response; } @@ -276,7 +284,8 @@ async function ncAxiosLinkRemove({ if (debugMode && status !== 200) { console.log('#### ', response.body.message || response.body.msg); } - if (!debugMode && msg) expect(response.body.message || response.body.msg).to.equal(msg); + if (!debugMode && msg) + expect(response.body.message || response.body.msg).to.equal(msg); return response; } @@ -290,29 +299,39 @@ function generalDb() { sakilaProject = await createSakilaProject(context); base = await createProject(context); + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + + sakilaCtx = { + workspace_id: sakilaProject.fk_workspace_id, + base_id: sakilaProject.id, + }; + customerTable = await getTable({ base: sakilaProject, name: 'customer', }); - customerColumns = await customerTable.getColumns(); + customerColumns = await customerTable.getColumns(sakilaCtx); actorTable = await getTable({ base: sakilaProject, name: 'actor', }); - actorColumns = await actorTable.getColumns(); + actorColumns = await actorTable.getColumns(sakilaCtx); countryTable = await getTable({ base: sakilaProject, name: 'country', }); - countryColumns = await countryTable.getColumns(); + countryColumns = await countryTable.getColumns(sakilaCtx); cityTable = await getTable({ base: sakilaProject, name: 'city', }); - cityColumns = await cityTable.getColumns(); + cityColumns = await cityTable.getColumns(sakilaCtx); }); it('Nested List - Link to another record', async function () { @@ -436,6 +455,10 @@ function textBased() { beforeEach(async function () { context = await init(false); base = await createProject(context); + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; table = await createTable(context, base, { table_name: 'textBased', title: 'TextBased', @@ -443,7 +466,7 @@ function textBased() { }); // retrieve column meta - columns = await table.getColumns(); + columns = await table.getColumns(ctx); // build records const rowAttributes = []; @@ -823,7 +846,7 @@ function textBased() { // Invalid table ID await ncAxiosGet({ url: `/api/v2/tables/123456789/records`, - status: unauthorizedResponse, + status: 404, }); // Invalid view ID @@ -885,9 +908,7 @@ function textBased() { }, status: 422, }); - expect(rsp.body.message).to.equal( - "Offset value '10000' is invalid", - ); + expect(rsp.body.message).to.equal("Offset value '10000' is invalid"); }); it('List: invalid sort, filter, fields', async function () { @@ -955,7 +976,7 @@ function textBased() { // Invalid table ID await ncAxiosPost({ url: `/api/v2/tables/123456789/records`, - status: unauthorizedResponse, + status: 404, }); // Invalid data - create should not specify ID @@ -989,7 +1010,7 @@ function textBased() { // Invalid table ID await ncAxiosGet({ url: `/api/v2/tables/123456789/records/100`, - status: unauthorizedResponse, + status: 404, }); // Invalid row ID await ncAxiosGet({ @@ -1074,7 +1095,7 @@ function textBased() { await ncAxiosPatch({ url: `/api/v2/tables/123456789/records`, body: { Id: 100, SingleLineText: 'some text' }, - status: unauthorizedResponse, + status: 404, }); // Invalid row ID await ncAxiosPatch({ @@ -1123,7 +1144,7 @@ function textBased() { await ncAxiosDelete({ url: `/api/v2/tables/123456789/records`, body: { Id: 100 }, - status: unauthorizedResponse, + status: 404, }); // Invalid row ID await ncAxiosDelete({ body: { Id: '123456789' }, status: 404 }); @@ -1135,6 +1156,10 @@ function numberBased() { beforeEach(async function () { context = await init(); base = await createProject(context); + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; table = await createTable(context, base, { table_name: 'numberBased', title: 'numberBased', @@ -1142,7 +1167,7 @@ function numberBased() { }); // retrieve column meta - columns = await table.getColumns(); + columns = await table.getColumns(ctx); // build records const rowAttributes = []; @@ -1375,6 +1400,10 @@ function selectBased() { beforeEach(async function () { context = await init(); base = await createProject(context); + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; table = await createTable(context, base, { table_name: 'selectBased', title: 'selectBased', @@ -1382,7 +1411,7 @@ function selectBased() { }); // retrieve column meta - columns = await table.getColumns(); + columns = await table.getColumns(ctx); // build records const rowAttributes = []; @@ -1565,6 +1594,10 @@ function dateBased() { beforeEach(async function () { context = await init(); base = await createProject(context); + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; table = await createTable(context, base, { table_name: 'dateBased', title: 'dateBased', @@ -1572,7 +1605,7 @@ function dateBased() { }); // retrieve column meta - columns = await table.getColumns(); + columns = await table.getColumns(ctx); // build records // 800: one year before to one year after @@ -1739,6 +1772,10 @@ function linkBased() { beforeEach(async function () { context = await init(); base = await createProject(context); + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; const columns = [ { @@ -1830,10 +1867,10 @@ function linkBased() { type: 'mm', }); - columnsFilm = await tblFilm.getColumns(); - columnsActor = await tblActor.getColumns(); - columnsCountry = await tblCountry.getColumns(); - columnsCity = await tblCity.getColumns(); + columnsFilm = await tblFilm.getColumns(ctx); + columnsActor = await tblActor.getColumns(ctx); + columnsCountry = await tblCountry.getColumns(ctx); + columnsCity = await tblCity.getColumns(ctx); } catch (e) { console.log(e); } @@ -2371,7 +2408,7 @@ function linkBased() { await ncAxiosLinkAdd({ ...validParams, urlParams: { ...validParams.urlParams, tableId: 9999 }, - status: unauthorizedResponse, + status: 404, }); // Link Add: Invalid link ID @@ -2412,7 +2449,7 @@ function linkBased() { ...validParams, body: [999, 998], status: 404, - msg: 'Record \'999\' not found', + msg: "Record '999' not found", }); } else { // Link Add: Invalid body parameter - row id invalid @@ -2422,7 +2459,7 @@ function linkBased() { ...validParams, body: [999, 998, 997], status: 404, - msg: 'Records \'999, 998, 997\' not found', + msg: "Records '999, 998, 997' not found", }); // Link Add: Invalid body parameter - repeated row id @@ -2443,7 +2480,7 @@ function linkBased() { await ncAxiosLinkRemove({ ...validParams, urlParams: { ...validParams.urlParams, tableId: 9999 }, - status: unauthorizedResponse, + status: 404, }); // Link Remove: Invalid link ID @@ -2494,7 +2531,7 @@ function linkBased() { ...validParams, body: [999, 998], status: 404, - msg: 'Records \'999, 998\' not found', + msg: "Records '999, 998' not found", }); // Link Remove: Invalid body parameter - repeated row id @@ -2515,7 +2552,7 @@ function linkBased() { await ncAxiosLinkGet({ ...validParams, urlParams: { ...validParams.urlParams, tableId: 9999 }, - status: unauthorizedResponse, + status: 404, }); // Link List: Invalid link ID @@ -2807,6 +2844,10 @@ function userFieldBased() { beforeEach(async function () { context = await init(false, 'creator'); base = await createProject(context); + ctx = { + workspace_id: context.fk_workspace_id, + base_id: base.id, + }; table = await createTable(context, base, { table_name: 'userBased', title: 'userBased', @@ -2814,7 +2855,7 @@ function userFieldBased() { }); // retrieve column meta - columns = await table.getColumns(); + columns = await table.getColumns(ctx); // add users to workspace const users = [ diff --git a/packages/nocodb/tests/unit/rest/tests/table.test.ts b/packages/nocodb/tests/unit/rest/tests/table.test.ts index 76cc042ff1..a9cfee807d 100644 --- a/packages/nocodb/tests/unit/rest/tests/table.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/table.test.ts @@ -215,6 +215,11 @@ function tableTest() { }); it('Update table', async function () { + const ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + const response = await request(context.app) .patch(`/api/v1/db/meta/tables/${table.id}`) .set('xc-auth', context.token) @@ -223,7 +228,7 @@ function tableTest() { table_name: 'new_title', }) .expect(200); - const updatedTable = await Model.get(table.id); + const updatedTable = await Model.get(ctx, table.id); if (!updatedTable.table_name.endsWith('new_title')) { return new Error('Table was not updated'); diff --git a/packages/nocodb/tests/unit/rest/tests/tableRow.test.ts b/packages/nocodb/tests/unit/rest/tests/tableRow.test.ts index c1465d757c..327477ca78 100644 --- a/packages/nocodb/tests/unit/rest/tests/tableRow.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/tableRow.test.ts @@ -42,6 +42,10 @@ function tableStaticTest() { let sakilaProject: Base; let customerTable: Model; let customerColumns; + let sakilaCtx: { + workspace_id: string; + base_id: string; + }; before(async function () { console.time('#### tableTest'); @@ -50,11 +54,16 @@ function tableStaticTest() { sakilaProject = await createSakilaProject(context); base = await createProject(context); + sakilaCtx = { + workspace_id: sakilaProject.fk_workspace_id, + base_id: sakilaProject.id, + }; + customerTable = await getTable({ base: sakilaProject, name: 'customer', }); - customerColumns = await customerTable.getColumns(); + customerColumns = await customerTable.getColumns(sakilaCtx); console.timeEnd('#### tableTest'); }); @@ -373,7 +382,7 @@ function tableStaticTest() { // todo: Add export test for views it('Nested row list hm', async () => { const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Rentals', )!; const response = await request(context.app) @@ -391,7 +400,7 @@ function tableStaticTest() { }); it('Nested row list hm with limit and offset', async () => { const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Rentals', )!; const response = await request(context.app) @@ -416,7 +425,7 @@ function tableStaticTest() { }); it('Row list hm with invalid table id', async () => { const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Rentals', )!; const response = await request(context.app) @@ -437,7 +446,7 @@ function tableStaticTest() { name: 'actor', }); await getTable({ base: sakilaProject, name: 'film' }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Films', )!; const response = await request(context.app) @@ -460,7 +469,7 @@ function tableStaticTest() { name: 'actor', }); await getTable({ base: sakilaProject, name: 'film' }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Films', )!; const response = await request(context.app) @@ -490,7 +499,7 @@ function tableStaticTest() { base: sakilaProject, name: 'actor', }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Films', )!; const response = await request(context.app) @@ -507,7 +516,7 @@ function tableStaticTest() { }); it('Create hm relation with invalid table id', async () => { const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Rentals', )!; const refId = 1; @@ -524,7 +533,7 @@ function tableStaticTest() { }); it('Create hm relation with non ltar column', async () => { const rowId = 1; - const firstNameColumn = (await customerTable.getColumns()).find( + const firstNameColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'FirstName', )!; const refId = 1; @@ -551,16 +560,14 @@ function tableStaticTest() { .set('xc-auth', context.token) .expect(404); - if ( - response.body.message !== "Field 'invalid-column' not found" - ) { + if (response.body.message !== "Field 'invalid-column' not found") { console.log(response.body); throw new Error('Wrong error message'); } }); it('List hm with non ltar column', async () => { const rowId = 1; - const firstNameColumn = (await customerTable.getColumns()).find( + const firstNameColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'FirstName', )!; @@ -573,7 +580,7 @@ function tableStaticTest() { }); it('List mm with non ltar column', async () => { const rowId = 1; - const firstNameColumn = (await customerTable.getColumns()).find( + const firstNameColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'FirstName', )!; @@ -586,7 +593,7 @@ function tableStaticTest() { }); it('Exclude list hm', async () => { const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Rentals', )!; @@ -604,7 +611,7 @@ function tableStaticTest() { }); it('Exclude list hm with limit and offset', async () => { const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Rentals', )!; @@ -635,7 +642,7 @@ function tableStaticTest() { base: sakilaProject, name: 'actor', }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Films', )!; @@ -657,7 +664,7 @@ function tableStaticTest() { base: sakilaProject, name: 'actor', }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(sakilaCtx)).find( (column) => column.title === 'Films', )!; @@ -688,7 +695,7 @@ function tableStaticTest() { base: sakilaProject, name: 'address', }); - const cityColumn = (await addressTable.getColumns()).find( + const cityColumn = (await addressTable.getColumns(sakilaCtx)).find( (column) => column.title === 'City', )!; @@ -708,7 +715,7 @@ function tableStaticTest() { base: sakilaProject, name: 'address', }); - const cityColumn = (await addressTable.getColumns()).find( + const cityColumn = (await addressTable.getColumns(sakilaCtx)).find( (column) => column.title === 'City', )!; @@ -729,7 +736,7 @@ function tableStaticTest() { it('Get grouped data list', async function () { const filmTable = await getTable({ base: sakilaProject, name: 'film' }); - const filmColumns = await filmTable.getColumns(); + const filmColumns = await filmTable.getColumns(sakilaCtx); const ratingColumn = filmColumns.find((c) => c.column_name === 'rating'); @@ -765,6 +772,10 @@ function tableTest() { let sakilaProject: Base; let customerTable: Model; let customerColumns; + let ctx: { + workspace_id: string; + base_id: string; + }; beforeEach(async function () { console.time('#### tableTest'); @@ -773,11 +784,16 @@ function tableTest() { sakilaProject = await createSakilaProject(context); base = await createProject(context); + ctx = { + workspace_id: sakilaProject.fk_workspace_id, + base_id: sakilaProject.id, + }; + customerTable = await getTable({ base: sakilaProject, name: 'customer', }); - customerColumns = await customerTable.getColumns(); + customerColumns = await customerTable.getColumns(ctx); console.timeEnd('#### tableTest'); }); @@ -1017,7 +1033,7 @@ function tableTest() { relatedTableColumnTitle: 'FirstName', }); - const returnDateColumn = (await rentalTable.getColumns()).find( + const returnDateColumn = (await rentalTable.getColumns(ctx)).find( (c) => c.title === 'ReturnDate', ); @@ -1124,15 +1140,15 @@ function tableTest() { relatedTableColumnTitle: 'RentalDate', }); - const paymentListColumn = (await customerTable.getColumns()).find( + const paymentListColumn = (await customerTable.getColumns(ctx)).find( (c) => c.title === 'Payments', ); - const activeColumn = (await customerTable.getColumns()).find( + const activeColumn = (await customerTable.getColumns(ctx)).find( (c) => c.title === 'Active', ); - const addressColumn = (await customerTable.getColumns()).find( + const addressColumn = (await customerTable.getColumns(ctx)).find( (c) => c.title === 'Address', ); @@ -1280,7 +1296,7 @@ function tableTest() { relatedTableColumnTitle: 'RentalDate', }); - const activeColumn = (await customerTable.getColumns()).find( + const activeColumn = (await customerTable.getColumns(ctx)).find( (c) => c.title === 'Active', ); @@ -1519,7 +1535,7 @@ function tableTest() { relatedTableColumnTitle: 'RentalDate', }); - const activeColumn = (await customerTable.getColumns()).find( + const activeColumn = (await customerTable.getColumns(ctx)).find( (c) => c.title === 'Active', ); @@ -1791,7 +1807,7 @@ function tableTest() { it('Bulk insert', async function () { const table = await createTable(context, base); - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const rowAttributes = Array(99) .fill(0) @@ -1828,7 +1844,7 @@ function tableTest() { it('Bulk insert 400 records', async function () { const table = await createTable(context, base); - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const rowAttributes = Array(400) .fill(0) @@ -1869,7 +1885,7 @@ function tableTest() { return; } const table = await createTable(context, base); - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const rowAttributes = Array(400) .fill(0) @@ -1897,7 +1913,7 @@ function tableTest() { it('Bulk delete', async function () { const table = await createTable(context, base); - const columns = await table.getColumns(); + const columns = await table.getColumns(ctx); const rowAttributes = Array(400) .fill(0) @@ -2014,7 +2030,7 @@ function tableTest() { it('Create list hm', async () => { const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(ctx)).find( (column) => column.title === 'Rentals', )!; const refId = 1; @@ -2064,9 +2080,7 @@ function tableTest() { .set('xc-auth', context.token) .expect(404); - if ( - response.body.message !== "Field 'invalid-column' not found" - ) { + if (response.body.message !== "Field 'invalid-column' not found") { console.log(response.body); throw new Error('Should error out'); } @@ -2078,7 +2092,7 @@ function tableTest() { base: sakilaProject, name: 'actor', }); - const firstNameColumn = (await actorTable.getColumns()).find( + const firstNameColumn = (await actorTable.getColumns(ctx)).find( (column) => column.title === 'FirstName', )!; const refId = 1; @@ -2101,7 +2115,7 @@ function tableTest() { base: sakilaProject, name: 'actor', }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(ctx)).find( (column) => column.title === 'Films', )!; const refId = 1; @@ -2123,7 +2137,7 @@ function tableTest() { base: sakilaProject, name: 'actor', }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(ctx)).find( (column) => column.title === 'Films', )!; const refId = 2; @@ -2164,7 +2178,7 @@ function tableTest() { base: sakilaProject, name: 'actor', }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(ctx)).find( (column) => column.title === 'Films', )!; const refId = 1; @@ -2204,7 +2218,7 @@ function tableTest() { if (isSqlite(context) || isPg(context)) return; const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(ctx)).find( (column) => column.title === 'Rentals', )!; const refId = 76; @@ -2280,7 +2294,7 @@ function tableTest() { it('Create nested hm relation with invalid table id', async () => { const rowId = 1; - const rentalListColumn = (await customerTable.getColumns()).find( + const rentalListColumn = (await customerTable.getColumns(ctx)).find( (column) => column.title === 'Rentals', )!; @@ -2303,7 +2317,7 @@ function tableTest() { base: sakilaProject, name: 'actor', }); - const filmListColumn = (await actorTable.getColumns()).find( + const filmListColumn = (await actorTable.getColumns(ctx)).find( (column) => column.title === 'Films', )!; const response = await request(context.app) diff --git a/packages/nocodb/tests/unit/rest/tests/viewRow.test.ts b/packages/nocodb/tests/unit/rest/tests/viewRow.test.ts index 67f0fe3a41..8565a9b0f1 100644 --- a/packages/nocodb/tests/unit/rest/tests/viewRow.test.ts +++ b/packages/nocodb/tests/unit/rest/tests/viewRow.test.ts @@ -41,6 +41,14 @@ const isColumnsCorrectInResponse = (row, columns: ColumnType[]) => { }; let context; +let sakilaCtx: { + workspace_id: string; + base_id: string; +}; +let ctx: { + workspace_id: string; + base_id: string; +}; // bases let base: Base; let sakilaProject: Base; @@ -126,11 +134,19 @@ function viewRowStaticTests() { context = await init(); sakilaProject = await createSakilaProject(context); base = await createProject(context); + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + sakilaCtx = { + workspace_id: sakilaProject.fk_workspace_id, + base_id: sakilaProject.id, + }; customerTable = await getTable({ base: sakilaProject, name: 'customer', }); - customerColumns = await customerTable.getColumns(); + customerColumns = await customerTable.getColumns(sakilaCtx); customerGridView = await createView(context, { title: 'Customer Gallery', table: customerTable, @@ -151,7 +167,7 @@ function viewRowStaticTests() { base: sakilaProject, name: 'film', }); - filmColumns = await filmTable.getColumns(); + filmColumns = await filmTable.getColumns(sakilaCtx); filmKanbanView = await createView(context, { title: 'Film Kanban', table: filmTable, @@ -163,7 +179,7 @@ function viewRowStaticTests() { name: 'rental', }); - rentalColumns = await rentalTable.getColumns(); + rentalColumns = await rentalTable.getColumns(sakilaCtx); rentalCalendarView = await createView(context, { title: 'Rental Calendar', @@ -473,11 +489,19 @@ function viewRowTests() { context = await init(); sakilaProject = await createSakilaProject(context); base = await createProject(context); + ctx = { + workspace_id: base.fk_workspace_id, + base_id: base.id, + }; + sakilaCtx = { + workspace_id: sakilaProject.fk_workspace_id, + base_id: sakilaProject.id, + }; customerTable = await getTable({ base: sakilaProject, name: 'customer', }); - customerColumns = await customerTable.getColumns(); + customerColumns = await customerTable.getColumns(sakilaCtx); customerGridView = await createView(context, { title: 'Customer Gallery', table: customerTable, @@ -498,7 +522,7 @@ function viewRowTests() { base: sakilaProject, name: 'film', }); - filmColumns = await filmTable.getColumns(); + filmColumns = await filmTable.getColumns(sakilaCtx); filmKanbanView = await createView(context, { title: 'Film Kanban', table: filmTable, @@ -510,7 +534,7 @@ function viewRowTests() { name: 'rental', }); - rentalColumns = await rentalTable.getColumns(); + rentalColumns = await rentalTable.getColumns(sakilaCtx); rentalCalendarView = await createView(context, { title: 'Rental Calendar', @@ -640,7 +664,7 @@ function viewRowTests() { relatedTableColumnTitle: 'RentalDate', }); - const activeColumn = (await customerTable.getColumns()).find( + const activeColumn = (await customerTable.getColumns(sakilaCtx)).find( (c) => c.title === 'Active', ); @@ -899,7 +923,7 @@ function viewRowTests() { attr: { show: true }, }); - const activeColumn = (await customerTable.getColumns()).find( + const activeColumn = (await customerTable.getColumns(sakilaCtx)).find( (c) => c.title === 'Active', ); @@ -1715,7 +1739,7 @@ function viewRowTests() { name: 'Film', }); - const columns = await table.getColumns(); + const columns = await table.getColumns(sakilaCtx); // get rows const rows = await listRow({