diff --git a/docsfera.json b/docsfera.json index f509fa0..4a9cad2 100644 --- a/docsfera.json +++ b/docsfera.json @@ -2854,7 +2854,16 @@ "/catalog/data-asset/{id}": { "get": { "operationId": "CatalogController_getDataAsset", - "parameters": [], + "parameters": [ + { + "name": "shared", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + } + ], "responses": { "200": { "description": "" @@ -3405,7 +3414,7 @@ } }, "info": { - "title": "Maestro - feature/upload-to-s3-presigned", + "title": "Maestro - feat/embed-private", "description": "Documentation for Maestro gateway", "version": "1.0.0", "contact": {} @@ -5911,6 +5920,14 @@ }, "embed": { "$ref": "#/components/schemas/EmbedObject" + }, + "share_type": { + "type": "string", + "enum": [ + "none", + "public", + "private" + ] } }, "required": [ diff --git a/src/modules/catalog/catalog.controller.ts b/src/modules/catalog/catalog.controller.ts index dcbe404..71f69f3 100644 --- a/src/modules/catalog/catalog.controller.ts +++ b/src/modules/catalog/catalog.controller.ts @@ -1,11 +1,14 @@ import { + BadRequestException, Body, Controller, Delete, + ForbiddenException, Get, Headers, HttpException, Inject, + NotFoundException, Param, Post, Put, @@ -98,7 +101,7 @@ export class CatalogController { }); if (!pipeline || !object) { - throw new HttpException('Query params not provided', 400); + throw new BadRequestException('Query params not provided'); } const is_data_manager = permissions.includes( @@ -136,9 +139,8 @@ export class CatalogController { return { data_asset }; } - throw new HttpException( + throw new ForbiddenException( 'You do not have permission to access this data asset.', - 403, ); } @@ -172,12 +174,12 @@ export class CatalogController { ) async getDataAsset( @User() user: RequestUser, - @Headers() headers, @Param('id') id, + @Query('shared') shared?: 'true', ) { const { username, user_id, customer_id, customer_name, permissions } = user; - this.logger.info(`/catalog - ON GET ONE DASHBOARD METABASE ROUTE`, { + this.logger.info(`GET /data-asset/${id}`, { username, customer_name, }); @@ -200,25 +202,24 @@ export class CatalogController { id, metadata, }); + has_permission = + is_data_manager || + data_asset?.owner === username || + (user_roles as Array).some((r) => data_asset.p_roles.includes(r)) || + data_asset.p_users.includes(user_id); + if ( + shared === 'true' && + (data_asset.share_type === undefined || data_asset.share_type === 'none') + ) + throw new NotFoundException(); + if (!has_permission) + throw new ForbiddenException( + 'You do not have permission to access this data asset.', + ); + delete data_asset.p_roles; + delete data_asset.p_users; - if (data_asset?.owner === username) has_permission = true; - - for (const role of user_roles) { - if (data_asset.p_roles.includes(role)) has_permission = true; - } - - if (data_asset.p_users.includes(user_id)) has_permission = true; - - if (is_data_manager || has_permission) { - delete data_asset.p_roles; - delete data_asset.p_users; - return { data_asset }; - } - - throw new HttpException( - 'You do not have permission to access this data asset.', - 403, - ); + return { data_asset }; } @Get('data-asset/rls/:id') @@ -271,9 +272,8 @@ export class CatalogController { return { data_asset }; } - throw new HttpException( + throw new ForbiddenException( 'You do not have permission to access this data asset.', - 403, ); } @@ -376,7 +376,7 @@ export class CatalogController { async updateDataAsset( @User() user: RequestUser, @Headers('Dadosfera-Lang') language, - @Param('id') id, + @Param('id') data_asset_id, @Body() body: IUpdateDataRequest, ): Promise { const { customer_id, customer_name, user_id, username } = user; @@ -390,7 +390,7 @@ export class CatalogController { const result = await this.catalogService.updateOneDataAsset({ body, - data_asset_id: id, + data_asset_id, customer_id, metadata, }); diff --git a/src/modules/catalog/dtos/index.ts b/src/modules/catalog/dtos/index.ts index 16604b2..e55872f 100644 --- a/src/modules/catalog/dtos/index.ts +++ b/src/modules/catalog/dtos/index.ts @@ -1,6 +1,11 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { CreateDataAssetRequest } from '@dadosfera/protospack-v2/dist/lib/Catalog/interfaces/messages'; +export enum DataAssetShareType { + none = 'none', + public = 'public', + private = 'private', +} export class EmbedObject { @ApiProperty() url: string; @@ -135,6 +140,8 @@ export class IUpdateDataRequest { tags: string[]; @ApiPropertyOptional() embed: EmbedObject; + @ApiPropertyOptional({ enum: DataAssetShareType }) + share_type: DataAssetShareType; } export class ICreateDataAsset implements CreateDataAssetRequest { @ApiProperty() diff --git a/src/modules/duc/client.config.ts b/src/modules/duc/client.config.ts index 3b0ecc7..1bcd08e 100644 --- a/src/modules/duc/client.config.ts +++ b/src/modules/duc/client.config.ts @@ -9,6 +9,8 @@ import { ProtoPaths, } from '@dadosfera/protospack-v2/dist/lib/Duc'; +const isLocalConnection = !!process.env.DUC_URL?.includes('0.0.0.0'); + export class DucClient { public name = 'DucClient'; @@ -17,10 +19,7 @@ export class DucClient { options: { url: process.env.DUC_URL, package: [ProtoPackages.WritePackage, ProtoPackages.ReadPackage], - credentials: - process.env.LOCAL_ENV || process.env.ENV === 'local' - ? undefined - : credentials.createSsl(), + credentials: isLocalConnection ? undefined : credentials.createSsl(), protoPath: [ProtoPaths.WriteFilePath, ProtoPaths.ReadFilePath], loader: { keepCase: true, diff --git a/src/modules/inputs/inputs-client.config.ts b/src/modules/inputs/inputs-client.config.ts index 7834231..b52009f 100644 --- a/src/modules/inputs/inputs-client.config.ts +++ b/src/modules/inputs/inputs-client.config.ts @@ -2,10 +2,11 @@ import { Input } from '@dadosfera/protospack-v2'; import { credentials } from '@grpc/grpc-js'; import { ClientProviderOptions, - GrpcOptions, Transport, + type GrpcOptions, } from '@nestjs/microservices'; +const isLocalConnection = !!process.env.INFACTORY_URL?.includes('0.0.0.0'); export class InputsGrpcClient { public readonly name = 'InputsGrpcClient'; private config: GrpcOptions = { @@ -16,10 +17,7 @@ export class InputsGrpcClient { Input.ProtoPackages.WritePackage, Input.ProtoPackages.ReadPackage, ], - credentials: - process.env.LOCAL_ENV || process.env.ENV === 'local' - ? undefined - : credentials.createSsl(), + credentials: isLocalConnection ? undefined : credentials.createSsl(), protoPath: [ Input.ProtoPaths.WriteFilePath, Input.ProtoPaths.ReadFilePath, diff --git a/src/modules/mixpanel/mixpanel.module.ts b/src/modules/mixpanel/mixpanel.module.ts index 41b4a68..98f130d 100644 --- a/src/modules/mixpanel/mixpanel.module.ts +++ b/src/modules/mixpanel/mixpanel.module.ts @@ -1,5 +1,5 @@ import { Module } from '@nestjs/common'; -import { getSecreteFromSecreteManager } from 'src/utils/SecretManager'; +import { getSecretFromSecretsManager } from 'src/utils/SecretManager'; import { MixpanelController } from './mixpanel.controller'; @Module({ @@ -7,7 +7,7 @@ import { MixpanelController } from './mixpanel.controller'; providers: [ { provide: 'MIXPANEL_TOKEN', - useValue: getSecreteFromSecreteManager( + useValue: getSecretFromSecretsManager( `${process.env.ENV}/root/mixpanel_token`, ), }, diff --git a/src/modules/productboard/productboard.controller.ts b/src/modules/productboard/productboard.controller.ts index c28bf7f..55327df 100644 --- a/src/modules/productboard/productboard.controller.ts +++ b/src/modules/productboard/productboard.controller.ts @@ -2,7 +2,7 @@ import { Body, Controller, HttpException, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import axios from 'axios'; import { User, RequestUser } from 'src/authentication/user.decorator'; -import { getSecreteFromSecreteManager } from 'src/utils/SecretManager'; +import { getSecretFromSecretsManager } from 'src/utils/SecretManager'; import { INote } from './dtos'; @ApiTags('Productboard') @@ -18,7 +18,7 @@ export class ProductboardController { : username + `@${customer_name}.default`; const path = process.env.PB_TOKEN_PATH; - const token = await getSecreteFromSecreteManager(path); + const token = await getSecretFromSecretsManager(path); const response = await axios .post( diff --git a/src/utils/SecretManager.ts b/src/utils/SecretManager.ts index 08419bd..98fcc7c 100644 --- a/src/utils/SecretManager.ts +++ b/src/utils/SecretManager.ts @@ -3,7 +3,7 @@ import { GetSecretValueCommand, } from '@aws-sdk/client-secrets-manager'; -export async function getSecreteFromSecreteManager(path: string) { +export async function getSecretFromSecretsManager(path: string) { const secretsManagerClient = new SecretsManagerClient({}); const getSecretComand = new GetSecretValueCommand({