Compare commits

...
36 Commits
Author SHA1 Message Date
Anderson Feitosa 7dab555009 Merge pull request #194 from dadosfera/feature/download-logs
feature/download-logs
2022-12-27 16:41:11 -03:00
Anderson Feitosa 27dacf1257 FEAT: update protospack version 2022-12-27 12:24:15 -03:00
Anderson Feitosa f71bb523ff FEAT: add download logs api route 2022-12-27 12:23:03 -03:00
Anderson Feitosa 5c6f36a760 Merge pull request #192 from dadosfera/feature/pipeline-object-to-data-asset
feature/pipeline-object-to-data-asset
2022-12-23 14:07:33 -03:00
Anderson Feitosa db4a2d9d2e FEAT: update protospack version 2022-12-22 17:43:54 -03:00
Anderson Feitosa 9a1b3e0bf4 FEAT: update protospack 2022-12-22 17:38:58 -03:00
Gabriel Rosa 67d9b3a06e Send metabaseUserId undefined to user update 2022-12-22 17:14:51 -03:00
Anderson Feitosa 1150d21763 FEAT: remove metabase user id 2022-12-22 17:02:03 -03:00
Anderson Feitosa b38e9f26c3 FEAT: add route to get data asset by pipeline and object 2022-12-22 17:00:56 -03:00
Anderson Feitosa 5a23923e53 DOCS: docsfera 2022-12-22 13:16:56 -03:00
Anderson Feitosa 3db7e99d9e FEAT: parse objects 2022-12-22 13:16:44 -03:00
Anderson Feitosa c85cd37f3a FEAT: add new api route to get pipeline objects 2022-12-22 13:08:08 -03:00
Gabriel Amorim 0fc8c427a2 Merge pull request #191 from dadosfera/fix/refresh-token
Fix/refresh token
2022-12-16 09:40:56 -03:00
Gabriel Rosa 59c3ce7ed9 FIX: do not use User() on non-authenticated routes 2022-12-16 08:09:20 -03:00
Victor Radael c5c428d3d4 FIX: Refresh token 2022-12-15 19:57:52 -03:00
Victor Radael cda7f9a9b5 FEAT: Edit connection 2022-12-15 16:01:24 -03:00
Victor Radael bb3b71d5f0 Merge remote-tracking branch 'origin' into feat/upload-csv 2022-12-15 16:01:02 -03:00
Victor Radael e47459eb9a FEAT: Edit connection 2022-12-15 16:00:54 -03:00
Gabriel Amorim a2de729e0e Merge pull request #190 from dadosfera/feat/cognito-app-client
Feat/cognito app client
2022-12-14 13:20:29 -03:00
Gabriel Rosa e2cb02e51a new protospack version 2022-12-14 10:49:33 -03:00
Gabriel Rosa 8a0c91eca5 new protospack version 2022-12-14 10:02:02 -03:00
Gabriel Rosa 15302d80bc Merge branch 'main' into feat/cognito-app-client 2022-12-13 16:12:19 -03:00
Gabriel Rosa 5aa63154c5 new protospack version 2022-12-13 15:34:57 -03:00
Gabriel Rosa 48af897e79 FEAT: send customer_name on refresh token 2022-12-13 09:28:42 -03:00
Victor Radael 9eb61a0ac9 Merge pull request #189 from dadosfera/feat/upload-csv
FIX: Upload CSV
2022-12-12 17:41:44 -03:00
Victor Radael 4a9e5b0ffc FIX: Upload CSV 2022-12-12 17:04:16 -03:00
Victor Radael 23fe522cc1 Merge pull request #188 from dadosfera/feat/upload-csv
Feat/upload csv
2022-12-09 17:14:36 -03:00
Victor Radael ea8dfa2e12 FEAT: Deploy Merge 2022-12-09 17:10:50 -03:00
Victor Radael ff5e735121 FEAT: Find a file pipeline 2022-12-09 08:29:27 -03:00
Victor Radael eaddca7eb3 FEAT: Creat a Upload CSV Pipeline 2022-12-06 18:06:32 -03:00
Victor Radael 98e865c48a FEAT: Create Upload CSV Pipeline 2022-12-05 20:35:35 -03:00
Victor Radael 2c207f068c FEAT: Create Upload CSV Pipeline 2022-12-05 20:34:04 -03:00
Victor Radael ea7ec52e1f FEAT: upload 50MB file 2022-12-01 18:55:48 -03:00
Victor Radael be228b7425 FEAT: upload 50MB file 2022-12-01 17:50:44 -03:00
Victor Radael 90edc6552a FEAT: Upload CSV 2022-12-01 14:57:44 -03:00
Victor Radael ed96609011 FEAT: Upload CSV 2022-12-01 14:56:41 -03:00
13 changed files with 1209 additions and 236 deletions
+892 -219
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -12,7 +12,7 @@
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "3.22.0",
"@dadosfera/protospack-v2": "3.27.0",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
@@ -1727,9 +1727,9 @@
}
},
"node_modules/@dadosfera/protospack-v2": {
"version": "3.22.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.22.0.tgz",
"integrity": "sha512-tkHqNiSeuiGtuFieOOaTTaB1OOKzcFd+7bTlDXj6FdorIHXt+FtHxslWX5b9XERzkQg7nseak1gFw2w4krOdbg==",
"version": "3.27.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.27.0.tgz",
"integrity": "sha512-yI9KiO6KwhFTyOLJv/Gqf1HqaSQ0FokPhoQxP+RvJCKi62aW1mSkA4PyYVeQNnj9lzyn+mKjSvWWe9puFficNw==",
"dependencies": {
"@grpc/grpc-js": "^1.6.7",
"rxjs": "^7.5.5",
@@ -12324,9 +12324,9 @@
}
},
"@dadosfera/protospack-v2": {
"version": "3.22.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.22.0.tgz",
"integrity": "sha512-tkHqNiSeuiGtuFieOOaTTaB1OOKzcFd+7bTlDXj6FdorIHXt+FtHxslWX5b9XERzkQg7nseak1gFw2w4krOdbg==",
"version": "3.27.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.27.0.tgz",
"integrity": "sha512-yI9KiO6KwhFTyOLJv/Gqf1HqaSQ0FokPhoQxP+RvJCKi62aW1mSkA4PyYVeQNnj9lzyn+mKjSvWWe9puFficNw==",
"requires": {
"@grpc/grpc-js": "^1.6.7",
"rxjs": "^7.5.5",
+1 -1
View File
@@ -28,7 +28,7 @@
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "3.22.0",
"@dadosfera/protospack-v2": "3.27.0",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
+13 -5
View File
@@ -11,7 +11,6 @@ import {
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
AuthRefreshAccessTokenRequest,
AuthChangePasswordRequest,
AuthResetPasswordRequest,
AuthVerifyResetPasswordCodeRequest,
@@ -31,7 +30,12 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { GrpcToHttpExceptionFilter } from '../../error/grpc-to-http-exception.filter';
import { RequestUser, User } from 'src/authentication/user.decorator';
import { Metadata } from '@grpc/grpc-js';
import { AuthSignInReq, AuthSignInRes } from './dtos/login';
import {
AuthRefreshAccessTokenReq,
AuthSignInReq,
AuthSignInRes,
} from './dtos/login';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
@ApiTags('Auth')
@UseFilters(new GrpcToHttpExceptionFilter())
@@ -77,12 +81,16 @@ export class AuthController {
@Post('refresh-access-token')
@HttpCode(HttpStatus.OK)
async refreshAccessToken(
@Body() { refreshToken }: AuthRefreshAccessTokenRequest,
@Body()
{ refreshToken, customerName: customer_name }: AuthRefreshAccessTokenReq,
@Headers('Dadosfera-Lang') language: string,
) {
this.logger.info('/auth - RefreshAccessToken');
const metadata = new Metadata();
metadata.add('language', language || 'pt-br');
const metadata = PackTheMetadata({
customer_name,
language,
});
return this.authClient.refreshAccessToken({ refreshToken }, metadata);
}
+7
View File
@@ -97,3 +97,10 @@ export class AuthSignInRes implements AuthSignInResponse {
@ApiPropertyOptional()
termsOfUse?: TermsOfUseStatus;
}
export class AuthRefreshAccessTokenReq {
@ApiProperty()
refreshToken: string;
@ApiProperty()
customerName: string;
}
+54
View File
@@ -88,6 +88,60 @@ export class CatalogController {
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 HttpException('Query params not provided', 400);
}
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 HttpException(
'You do not have permission to access this data asset.',
403,
);
}
@Get('tags')
@RequireSomePermission(
PERMISSIONS_GROUPS.CATALOG.permissions.GET,
+24
View File
@@ -197,6 +197,30 @@ class CatalogService implements OnModuleInit {
return { data_asset: asset[0] };
}
async getOneDataAssetByPipelineAndObject(data: {
customer_id: string;
pipeline: string;
object: string;
metadata: Metadata;
}) {
const { customer_id, metadata, pipeline, object } = data;
const { data_asset } = await lastValueFrom(
this.catalogReadService.GetOneDataAssetByPipelineAndObject(
{ pipeline, object },
metadata,
),
);
let asset = JSON.parse(data_asset);
asset = {
...asset,
p_roles: asset.roles,
p_users: asset.users,
};
asset = await this.getAssetsUsersAndRoles([asset], customer_id);
return { data_asset: asset[0] };
}
async updateOneDataAsset(data: {
data_asset_id: string;
customer_id: string;
@@ -164,11 +164,15 @@ export class ConnectionController {
@Headers('Dadosfera-Lang') language,
@User() user: RequestUser,
@Param('id') id,
@Query('details') details,
@Query() queries,
): Promise<ConnectionDetailsRes> {
this.logger.info('/connections - Get Connection Details');
if (!language) language = 'en-us';
console.log(queries);
const { details, sensitive } = queries;
const { user_id, customer_id, customer_name, username } = user;
const metadata = PackTheMetadata({
user_id,
@@ -177,6 +181,7 @@ export class ConnectionController {
username,
details,
language,
sensitive,
});
const response: any = await this.clientService.getConnectionDetails({
+20
View File
@@ -66,3 +66,23 @@ export interface IGetPipelineLogsRequest {
id: string;
details: string;
}
export class IUploadCSVFile {
@ApiProperty({ format: 'binary' })
file: string;
@ApiProperty()
name: string;
@ApiProperty()
description: string;
@ApiProperty()
encoding: string;
@ApiProperty()
sep: string;
@ApiProperty()
header: boolean;
}
+131 -2
View File
@@ -13,13 +13,20 @@ import {
HttpCode,
HttpStatus,
Patch,
UseInterceptors,
UploadedFile,
HttpException,
} from '@nestjs/common';
import {
ApiConsumes,
ApiCreatedResponse,
ApiNoContentResponse,
ApiTags,
} from '@nestjs/swagger';
import { AuthenticateCondition } from 'src/authentication/authentication.decorator';
import {
AuthenticateCondition,
RequireAllPermissions,
} from 'src/authentication/authentication.decorator';
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
import { PipelinesService } from './pipelines.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
@@ -28,8 +35,13 @@ import { RequestUser, User } from 'src/authentication/user.decorator';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { PipelinesService as OldPipelineService } from 'src/modules/pipelines/pipelines.service';
import { ICreatePipelineV2Req, IPipelineV2 } from './interfaces';
import {
ICreatePipelineV2Req,
IPipelineV2,
IUploadCSVFile,
} from './interfaces';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { FileInterceptor } from '@nestjs/platform-express';
@UseFilters(new GrpcToHttpExceptionFilter())
@ApiTags('PipelinesV2')
@@ -121,6 +133,39 @@ export class PipelinesController {
};
}
@Get('/download-logs')
async downloadLogs(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Query() query,
) {
this.logger.info('PipelinesController - downloadLogs', { user });
if (!language) language = 'en-us';
if (!query) {
throw new HttpException('Query params not provided', 400);
}
const { customer_id, customer_name, user_id, username } = user;
const metadata = PackTheMetadata({
customer_id,
customer_name,
user_id,
username,
language,
});
const url = await this.pipelinesClientService.downloadLogs(
query.pipeline_run_id,
metadata,
);
return {
url,
};
}
@Get(':id/config')
async getPipelineproperties(
@Headers('Dadosfera-Lang') language,
@@ -135,6 +180,20 @@ export class PipelinesController {
return this.pipelinesClientService.findOneProperties(id, metadata);
}
@Get(':id/objects')
async getPipelineObjects(
@Headers('Dadosfera-Lang') language,
@User() user: RequestUser,
@Param('id') id,
) {
this.logger.info('PipelinesController - getPipelineObjects', { user });
const metadata = PackTheMetadata({
...user,
language: language || 'pt-br',
});
return this.pipelinesClientService.findOneObjects(id, metadata);
}
@Get('/:id')
async findOne(
@Headers('Dadosfera-Lang') language,
@@ -240,4 +299,74 @@ export class PipelinesController {
await this.pipelinesClientService.remove({ id, metadata, user });
this.logger.info('PipelinesController - delete: OK');
}
@Post('/upload')
@RequireAllPermissions(PERMISSIONS_GROUPS.PIPELINE.permissions.CREATE)
@ApiConsumes('multipart/form-data')
@UseInterceptors(
FileInterceptor('file', { limits: { fileSize: 50 * 1000 * 1000 + 1 } }),
)
async uploadFile(
@User() user: RequestUser,
@UploadedFile() file,
@Body() body: IUploadCSVFile,
) {
this.logger.info('/upload - Upload Connector Route');
const metadata = PackTheMetadata({ ...user });
const parts_of_file_name = file.originalname.split('.');
const file_format = parts_of_file_name.pop();
const file_name = parts_of_file_name.join('.');
let name = `${new Date().getTime()}_${file_name}`;
body.name ? (name = `${new Date().getTime()}_${body.name}`) : name;
const source_prefix = `${user.customer_name}/${name}.${file_format}`;
const response = await this.pipelinesClientService.uploadFile(
{
file,
name,
},
metadata,
);
if (!response.url) {
this.logger.info('pipeline/upload - Failed File pipeline');
throw new HttpException(
'Upload failed, try again in a few minutes, if the problem persists, contact support.',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
const { sep, header, encoding, description } = body;
const upload_pipeline = {
connection_id: process.env.UPLOAD_FILE_AGENT_CONNECTION,
connector_name: 'Amazon S3',
connector_plugin: 'aws_s3',
connector_version: '1.0.0',
image_url: 'https://assets.dadosfera.ai/images/connectors/csv.svg',
name: body.name || file_name,
description,
transformations_ids: [],
tags: [],
cron: '@once',
config: { cron: '@once', tables: [] },
properties: {
engine: 'csv',
source_bucket: process.env.BUCKET_CUSTOMER_CSV_ASSETS,
source_prefix,
file_format_params: { sep, encoding, header: Boolean(header) },
is_a_upload_csv: true,
},
input_id: undefined,
};
const pipeline = await this.pipelinesClientService.create(
upload_pipeline,
metadata,
);
return pipeline;
}
}
+51 -1
View File
@@ -1,4 +1,10 @@
import { BadRequestException, Inject, OnModuleInit } from '@nestjs/common';
import {
BadRequestException,
HttpException,
HttpStatus,
Inject,
OnModuleInit,
} from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import {
Messages,
@@ -243,4 +249,48 @@ export class PipelinesService implements OnModuleInit {
},
};
}
async findOneObjects(id: string, metadata: Metadata) {
this.logger.info('PipelinesClientService - FindOneObjects');
const { objects } = await lastValueFrom(
this.pipelineReadService.PipelineV2FindObjects({ id }, metadata),
);
this.logger.info('Done');
return { objects: JSON.parse(objects) };
}
async uploadFile(uploadFile, metadata) {
const body: Messages.PipelineV2UploadFileRequest = {
file: {
buffer: uploadFile.file.buffer,
mimetypes: uploadFile.file.mimetype,
},
name: uploadFile.name,
};
return lastValueFrom(
this.pipelineWriteService.PipelineV2UploadFile(body, metadata),
).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
}
async downloadLogs(pipeline_run_id: string, metadata: Metadata) {
this.logger.info('PipelinesClientService - DownloadLogs');
const { url } = await lastValueFrom(
this.pipelineReadService.PipelineV2DownloadLogs(
{ pipeline_run_id },
metadata,
),
);
this.logger.info('Done');
return url;
}
}
+2
View File
@@ -122,6 +122,7 @@ export class UsersService implements OnModuleInit {
if (roleNames) {
await this.setRoles({ roleNames, userId: id }, customerId);
}
const { user } = await lastValueFrom(
this.usersClientService.UserUpdate({
name,
@@ -131,6 +132,7 @@ export class UsersService implements OnModuleInit {
hierarchy,
jobTitle,
email,
metabaseUserId: undefined,
}),
);
return { user: this.adjustUsersPayload([user])[0] };
+1
View File
@@ -7,6 +7,7 @@ interface IMetadata {
user_id?: string;
language?: string;
details?: string;
sensitive?: string;
roles?: string[];
is_data_manager?: boolean;
}