From f04c8d3d6e392d5c9c6ef0df947035faa55f61f1 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Mon, 10 Apr 2023 00:14:13 +0530 Subject: [PATCH] feat: public shared meta apis Signed-off-by: Pranav C --- packages/nocodb-nest/src/app.module.ts | 3 +- .../public-metas.controller.spec.ts | 20 ++++ .../public-metas/public-metas.controller.ts | 27 +++++ .../public-metas/public-metas.module.ts | 9 ++ .../public-metas/public-metas.service.spec.ts | 18 ++++ .../public-metas/public-metas.service.ts | 102 ++++++++++++++++++ 6 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 packages/nocodb-nest/src/modules/public-metas/public-metas.controller.spec.ts create mode 100644 packages/nocodb-nest/src/modules/public-metas/public-metas.controller.ts create mode 100644 packages/nocodb-nest/src/modules/public-metas/public-metas.module.ts create mode 100644 packages/nocodb-nest/src/modules/public-metas/public-metas.service.spec.ts create mode 100644 packages/nocodb-nest/src/modules/public-metas/public-metas.service.ts diff --git a/packages/nocodb-nest/src/app.module.ts b/packages/nocodb-nest/src/app.module.ts index 3068a3d5e7..ff8ea9eff7 100644 --- a/packages/nocodb-nest/src/app.module.ts +++ b/packages/nocodb-nest/src/app.module.ts @@ -38,9 +38,10 @@ import { AuditsModule } from './modules/audits/audits.module'; import { DatasModule } from './modules/datas/datas.module'; import { DataAliasModule } from './modules/data-alias/data-alias.module'; import { ApiDocsModule } from './modules/api-docs/api-docs.module'; +import { PublicMetasModule } from './modules/public-metas/public-metas.module'; @Module({ - imports: [AuthModule, UsersModule, UtilsModule, ProjectsModule, TablesModule, ViewsModule, FiltersModule, SortsModule, ColumnsModule, ViewColumnsModule, BasesModule, HooksModule, SharedBasesModule, FormsModule, GridsModule, KanbansModule, GalleriesModule, FormColumnsModule, GridColumnsModule, MapsModule, ProjectUsersModule, ModelVisibilitiesModule, HookFiltersModule, ApiTokensModule, AttachmentsModule, OrgLcenseModule, OrgTokensModule, OrgUsersModule, MetaDiffsModule, AuditsModule, DatasModule, DataAliasModule, ApiDocsModule], + imports: [AuthModule, UsersModule, UtilsModule, ProjectsModule, TablesModule, ViewsModule, FiltersModule, SortsModule, ColumnsModule, ViewColumnsModule, BasesModule, HooksModule, SharedBasesModule, FormsModule, GridsModule, KanbansModule, GalleriesModule, FormColumnsModule, GridColumnsModule, MapsModule, ProjectUsersModule, ModelVisibilitiesModule, HookFiltersModule, ApiTokensModule, AttachmentsModule, OrgLcenseModule, OrgTokensModule, OrgUsersModule, MetaDiffsModule, AuditsModule, DatasModule, DataAliasModule, ApiDocsModule, PublicMetasModule], controllers: [], providers: [Connection, MetaService, JwtStrategy, ExtractProjectIdMiddleware], exports: [Connection, MetaService], diff --git a/packages/nocodb-nest/src/modules/public-metas/public-metas.controller.spec.ts b/packages/nocodb-nest/src/modules/public-metas/public-metas.controller.spec.ts new file mode 100644 index 0000000000..f182488233 --- /dev/null +++ b/packages/nocodb-nest/src/modules/public-metas/public-metas.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PublicMetasController } from './public-metas.controller'; +import { PublicMetasService } from './public-metas.service'; + +describe('PublicMetasController', () => { + let controller: PublicMetasController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [PublicMetasController], + providers: [PublicMetasService], + }).compile(); + + controller = module.get(PublicMetasController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/packages/nocodb-nest/src/modules/public-metas/public-metas.controller.ts b/packages/nocodb-nest/src/modules/public-metas/public-metas.controller.ts new file mode 100644 index 0000000000..60add2b1d5 --- /dev/null +++ b/packages/nocodb-nest/src/modules/public-metas/public-metas.controller.ts @@ -0,0 +1,27 @@ +import { Controller, Get, Request, Param } from '@nestjs/common'; +import { PublicMetasService } from './public-metas.service'; + +@Controller('public-metas') +export class PublicMetasController { + constructor(private readonly publicMetasService: PublicMetasService) {} + + @Get('/api/v1/db/public/shared-view/:sharedViewUuid/meta') + async viewMetaGet( + @Request() req, + @Param('sharedViewUuid') sharedViewUuid: string, + ) { + return await this.publicMetasService.viewMetaGet({ + password: req.headers?.['xc-password'] as string, + sharedViewUuid: sharedViewUuid, + }); + } + + @Get('/api/v1/db/public/shared-base/:sharedBaseUuid/meta') + async publicSharedBaseGet( + @Param('sharedBaseUuid') sharedBaseUuid: string, + ): Promise { + return await this.publicMetasService.publicSharedBaseGet({ + sharedBaseUuid, + }); + } +} diff --git a/packages/nocodb-nest/src/modules/public-metas/public-metas.module.ts b/packages/nocodb-nest/src/modules/public-metas/public-metas.module.ts new file mode 100644 index 0000000000..78e1a3f2a0 --- /dev/null +++ b/packages/nocodb-nest/src/modules/public-metas/public-metas.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { PublicMetasService } from './public-metas.service'; +import { PublicMetasController } from './public-metas.controller'; + +@Module({ + controllers: [PublicMetasController], + providers: [PublicMetasService] +}) +export class PublicMetasModule {} diff --git a/packages/nocodb-nest/src/modules/public-metas/public-metas.service.spec.ts b/packages/nocodb-nest/src/modules/public-metas/public-metas.service.spec.ts new file mode 100644 index 0000000000..4b7f9dc37b --- /dev/null +++ b/packages/nocodb-nest/src/modules/public-metas/public-metas.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PublicMetasService } from './public-metas.service'; + +describe('PublicMetasService', () => { + let service: PublicMetasService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [PublicMetasService], + }).compile(); + + service = module.get(PublicMetasService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/packages/nocodb-nest/src/modules/public-metas/public-metas.service.ts b/packages/nocodb-nest/src/modules/public-metas/public-metas.service.ts new file mode 100644 index 0000000000..dd32aff976 --- /dev/null +++ b/packages/nocodb-nest/src/modules/public-metas/public-metas.service.ts @@ -0,0 +1,102 @@ +import { Injectable } from '@nestjs/common'; +import { + ErrorMessages, + LinkToAnotherRecordType, + RelationTypes, + UITypes, +} from 'nocodb-sdk'; +import { NcError } from '../../helpers/catchError'; +import { + Base, + Column, + LinkToAnotherRecordColumn, + Model, + Project, + View, +} from '../../models'; + +@Injectable() +export class PublicMetasService { + async viewMetaGet(param: { sharedViewUuid: string; password: string }) { + const view: View & { + relatedMetas?: { [ket: string]: Model }; + client?: string; + } = await View.getByUUID(param.sharedViewUuid); + + if (!view) NcError.notFound('Not found'); + + if (view.password && view.password !== param.password) { + NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); + } + + await view.getFilters(); + await view.getSorts(); + + await view.getViewWithInfo(); + await view.getColumns(); + await view.getModelWithInfo(); + await view.model.getColumns(); + + const base = await Base.get(view.model.base_id); + view.client = base.type; + + // todo: return only required props + delete view['password']; + + view.model.columns = view.columns + .filter((c) => { + const column = view.model.columnsById[c.fk_column_id]; + return ( + c.show || + (column.rqd && !column.cdf && !column.ai) || + column.pk || + view.model.columns.some( + (c1) => + c1.uidt === UITypes.LinkToAnotherRecord && + (c1.colOptions).type === + RelationTypes.BELONGS_TO && + view.columns.some((vc) => vc.fk_column_id === c1.id && vc.show) && + (c1.colOptions).fk_child_column_id === + c.fk_column_id, + ) + ); + }) + .map( + (c) => + new Column({ + ...c, + ...view.model.columnsById[c.fk_column_id], + } as any), + ) as any; + + const relatedMetas = {}; + + // load related table metas + for (const col of view.model.columns) { + if (UITypes.LinkToAnotherRecord === col.uidt) { + const colOpt = await col.getColOptions(); + relatedMetas[colOpt.fk_related_model_id] = await Model.getWithInfo({ + id: colOpt.fk_related_model_id, + }); + if (colOpt.type === 'mm') { + relatedMetas[colOpt.fk_mm_model_id] = await Model.getWithInfo({ + id: colOpt.fk_mm_model_id, + }); + } + } + } + + view.relatedMetas = relatedMetas; + + return view; + } + async publicSharedBaseGet(param: { sharedBaseUuid: string }): Promise { + const project = await Project.getByUuid(param.sharedBaseUuid); + + if (!project) { + NcError.notFound(); + } + + return { project_id: project.id }; + } +}