import { BadRequestException, Body, Controller, Delete, ForbiddenException, Get, Headers, HttpException, Inject, NotFoundException, Param, Post, Put, Query, UseFilters, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { Authenticated, RequireSomePermission, } from '../../authentication/authentication.decorator'; import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum'; import { CatalogService } from './catalog.service'; import { DadosferaLogger } from '@dadosfera/dadosfera-logs'; import { PackTheMetadata } from 'src/utils/ PackTheMetadata'; import { RequestUser, User } from 'src/authentication/user.decorator'; import { ICatalogAllResponse, IColumnsMetadataResponse, ICreateDataAsset, IDeleteComment, IDocsResponse, IMakeAComment, IOneDataAsset, IPreviewResponse, IUpdateDataRequest, } from './dtos'; import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter'; @ApiTags('Catalog') @Controller('catalog') @UseFilters(new GrpcToHttpExceptionFilter()) @Authenticated() export class CatalogController { logger: DadosferaLogger; constructor( @Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger, private catalogService: CatalogService, ) { this.logger = dadosferaLogger.logger; } @Get() @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.GET, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async searchCatalog( @User() user: RequestUser, @Query() query, ): Promise { const { user_id, customer_name, customer_id, username, permissions } = user; this.logger.info(`/catalog - searchCatalog`, { user_id, customer_name, }); const is_data_manager = permissions.includes( PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid, ); const roles = await this.catalogService.getUserRolesIds(user_id); const metadata = PackTheMetadata({ user_id, customer_id, customer_name, username, roles, is_data_manager, }); const res = await this.catalogService.searchDataAssets( query, metadata, customer_id, ); return res; } @Get('data-asset') async findByPipelineAndObject(@User() user: RequestUser, @Query() query) { const { username, user_id, customer_id, customer_name, permissions } = user; const { pipeline, object } = query; this.logger.info(`/catalog - ON GET DATA ASSET BY PIPELINE AND OBJECT`, { username, customer_name, }); if (!pipeline || !object) { throw new BadRequestException('Query params not provided'); } const is_data_manager = permissions.includes( PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid, ); let has_permission = false; const metadata = PackTheMetadata({ username, user_id: undefined, customer_id, customer_name, }); const user_roles = await this.catalogService.getUserRolesIds(user_id); const { data_asset } = await this.catalogService.getOneDataAssetByPipelineAndObject({ pipeline: query.pipeline, object: query.object, customer_id, metadata, }); 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 ForbiddenException( 'You do not have permission to access this data asset.', ); } @Get('tags') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.GET, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async findAllTags(@Body() body) { this.logger.info(`/catalog - ON FIND ALL TAGS ROUTE`, { user: body.info.user_id, customer: body.info.customer, }); const { user_id, customer, customer_id } = body.info; const metadata = PackTheMetadata({ user_id, customer_id, customer_name: customer, }); const res = await this.catalogService.findAllTags(body, metadata); return res; } @Get('data-asset/:id') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.GET, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async getDataAsset( @User() user: RequestUser, @Param('id') id, @Query('shared') shared?: 'true', ) { const { username, user_id, customer_id, customer_name, permissions } = user; this.logger.info(`GET /data-asset/${id}`, { username, customer_name, }); const is_data_manager = permissions.includes( PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid, ); let has_permission = false; const metadata = PackTheMetadata({ username, user_id: undefined, customer_id, customer_name, }); const user_roles = await this.catalogService.getUserRolesIds(user_id); const { data_asset } = await this.catalogService.getOneDataAsset({ customer_id, 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; return { data_asset }; } @Get('data-asset/rls/:id') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.GET, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async getDataAssetRls( @User() user: RequestUser, @Headers() headers, @Param('id') id, ) { const { username, user_id, customer_id, customer_name, permissions } = user; this.logger.info(`/catalog - ON GET ONE DASHBOARD METABASE ROUTE`, { username, customer_name, }); const is_data_manager = permissions.includes( PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER.seqid, ); let has_permission = false; const metadata = PackTheMetadata({ username, user_id, customer_id, customer_name, }); const user_roles = await this.catalogService.getUserRolesIds(user_id); const { data_asset } = await this.catalogService.getOneDataAsset({ customer_id, id, metadata, }); 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 ForbiddenException( 'You do not have permission to access this data asset.', ); } @Get('data-asset/:id/columns-metadata') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.GET, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async getDataAssetColumnsMetadata( @User() user: RequestUser, @Headers('Dadosfera-Lang') language, @Param('id') id, ): Promise { const { customer_name, customer_id, user_id, username } = user; this.logger.info(`/catalog - columns-metadata`, { user_id, customer_name, }); const metadata = PackTheMetadata({ customer_name, customer_id, user_id, username, language, }); const columns_metadata = await this.catalogService.getDatasetColumnsMetadata(id, metadata); return { columns_metadata }; } @Get('data-asset/:id/preview') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.GET, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async getDataAssetPreview( @User() user: RequestUser, @Headers('Dadosfera-lang') language, @Param('id') id, ): Promise { const { customer_name, customer_id, user_id, username } = user; this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, { user_id, customer_name, }); const metadata = PackTheMetadata({ customer_name, customer_id, user_id, username, language, }); const preview = await this.catalogService.getDatasetPreview(id, metadata); return { preview }; } @Get('data-asset/:id/docs') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.GET, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async getDataAssetDocs( @User() user: RequestUser, @Headers('Dadosfera-Lang') language, @Param('id') id, ): Promise { const { customer_name, customer_id, user_id, username } = user; this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, { user_id, customer_name, }); const metadata = PackTheMetadata({ customer_name, customer_id, user_id, username, language, }); const docs = await this.catalogService.getDataDocs(id, metadata); return { docs }; } @Put('data-asset/:id') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async updateDataAsset( @User() user: RequestUser, @Headers('Dadosfera-Lang') language, @Param('id') data_asset_id, @Body() body: IUpdateDataRequest, ): Promise { const { customer_id, customer_name, user_id, username } = user; const metadata = PackTheMetadata({ customer_id, customer_name, user_id, username, language, }); const result = await this.catalogService.updateOneDataAsset({ body, data_asset_id, customer_id, metadata, }); delete result.data_asset.p_roles; delete result.data_asset.p_users; return result; } @Post('data-asset/:id/docs') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async manageDataAssetDocs( @User() user: RequestUser, @Headers() headers, @Param('id') table_id: string, @Body('docs') docs: string, ) { const { user_id, customer_name } = user; this.logger.info(`/catalog - ON GET DATA DOCS ROUTE`, { user_id, customer_name, }); const res = await this.catalogService.createDataDocs({ table_id, docs, info: { customer: customer_name, }, }); return res; } @Put('data-asset/:id/manage-permissions') async manageDataAssetPermissions( @Param('id') id: string, @User() user: RequestUser, @Body() body, ) { const { customer_id, customer_name, user_id, username } = user; const metadata = PackTheMetadata({ customer_id, customer_name, user_id, username, }); const response = await this.catalogService.managePermissions( { ...body, id }, metadata, ); return { data_asset: JSON.parse(response.data_asset) }; } @Put('data-asset/:id/revoke-permissions') async revokeDataAssetPermissions( @Param('id') id: string, @User() user: RequestUser, @Body() body, ) { const { customer_id, customer_name, user_id, username } = user; const metadata = PackTheMetadata({ customer_id, customer_name, user_id, username, }); const response = await this.catalogService.revokePermissions( { ...body, id }, metadata, ); return { message: response.message }; } @Post() @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.CREATE, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async createDataAsset( @User() user: RequestUser, @Body() body: ICreateDataAsset, ) { const { customer_id, customer_name, user_id, username } = user; const metadata = PackTheMetadata({ customer_id, customer_name, user_id, username, }); const { data_asset } = await this.catalogService.createDataAsset( body, metadata, ); return { data_asset: JSON.parse(data_asset) }; } @Post('data-asset/:id/comment') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async commentOnDataAsset( @Param('id') id: string, @User() user: RequestUser, @Body() body: IMakeAComment, ) { const { message } = body; const { customer_id, customer_name, user_id, username } = user; const metadata = PackTheMetadata({ customer_id, customer_name, user_id, username, }); const response = await this.catalogService.commentOnDataAsset( { data_asset_id: id, username, message }, metadata, ); return response; } @Delete('data-asset/:id') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.DELETE, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async deleteDataAsset(@Param('id') id: string, @User() user: RequestUser) { const { customer_id, customer_name, user_id, username } = user; const metadata = PackTheMetadata({ customer_id, customer_name, user_id, username, }); const response = await this.catalogService.deleteDataAsset( { id, type: undefined }, metadata, ); return response; } @Delete('data-asset/:id/comment') @RequireSomePermission( PERMISSIONS_GROUPS.CATALOG.permissions.UPDATE, PERMISSIONS_GROUPS.CATALOG.permissions.DATA_MANAGER, ) async deleteComment( @Param('id') id: string, @User() user: RequestUser, @Body() body: IDeleteComment, ) { const { customer_id, customer_name, user_id, username } = user; const metadata = PackTheMetadata({ customer_id, customer_name, user_id, username, }); const response = await this.catalogService.deleteComment( { data_asset_id: id, comment: body.comment }, metadata, ); return response; } }