Compare commits

...
48 Commits
Author SHA1 Message Date
Gabriel Amorim aaf99b8c2e FEAT: passport salesforce and improvements connector manager
Merge pull request #111 from dadosfera/feature/passport-salesforce
2022-06-30 10:28:58 -03:00
Gabriel Rosa 8060cd769f merge connector-manager 2022-06-29 17:27:21 -03:00
Gabriel Rosa 89eed11561 FIX: get salesforce access token and refresh token 2022-06-29 17:25:29 -03:00
Victor Radael 0895922b1c Merge main 2022-06-29 14:12:01 -03:00
Victor Radael 1cc094d40b Merge main 2022-06-29 14:09:33 -03:00
Victor Radael d13aa2b72a Swagger 2022-06-29 13:59:46 -03:00
Victor Radael a98ec4bf32 Merge branch 'merge/auth+connectors-manager' of github.com:dadosfera/maestro into merge/auth+connectors-manager 2022-06-29 13:59:15 -03:00
Victor Radael d5b1cb51b4 Search Adapt fields 2022-06-29 13:58:32 -03:00
Arthur Simas 5d3510639e FEAT: salesforce passport 2022-06-29 12:39:54 -03:00
Gabriel Amorim dd4a1ecd46 FEAT: passport+connector manager
Merge pull request #110 from dadosfera/feat/passport+connector-manager
2022-06-28 19:09:40 -03:00
Gabriel Rosa 6eaaa746d0 FIX: merge conflict fixed 2022-06-28 18:40:52 -03:00
Gabriel Rosa df79fbdab0 Merge branch 'merge/auth+connectors-manager' of github.com:dadosfera/maestro into merge/auth+connectors-manager 2022-06-28 18:37:44 -03:00
Gabriel Rosa 0f34152b02 Merge branch 'feat/passport+connector-manager' of github.com:dadosfera/maestro into feat/passport+connector-manager 2022-06-28 18:36:49 -03:00
Gabriel Rosa 08d576432e FIX: new permissions 2022-06-28 18:36:41 -03:00
arthur simas ce0362217c Merge pull request #109 from dadosfera/feat/new-permissions
FEAT: new orchest permissions
2022-06-28 18:31:03 -03:00
Arthur Simas 3399f125e5 Merge branch 'feat/new-permissions' into feat/passport+connector-manager 2022-06-28 18:02:53 -03:00
Arthur Simas 9e0a58b4b7 FEAT: new orchest permissions 2022-06-28 18:02:01 -03:00
Gabriel Rosa 49a9c93d6f merge main 2022-06-28 15:24:21 -03:00
Gabriel Rosa ddb81d3082 REFACTOR: removed unused imports 2022-06-28 12:31:56 -03:00
Gabriel Rosa 9d9d903335 FIX: Better error handling on pipeline create 2022-06-28 12:22:00 -03:00
Gabriel Rosa e1d0aa00f5 swagfer changed 2022-06-28 10:24:54 -03:00
Gabriel Rosa 4209b5b23e merge with connector manager 2022-06-28 09:26:45 -03:00
Arthur Simas d6607b1d9f FEAT: connector manager 2022-06-27 19:22:36 -03:00
Gabriel Rosa 91aefe7d61 FEAT: passport mailchimp 2022-06-27 17:50:45 -03:00
Gabriel Rosa b584c80e24 FIX: google-oauth redirect_uri fixed 2022-06-27 16:13:58 -03:00
Gabriel Rosa 74a6eb8132 FIX: google redirect uri fixed 2022-06-27 15:51:24 -03:00
Gabriel Rosa 7012a6e2ac FIX: google strategy different callbacks for google 2022-06-27 14:13:18 -03:00
Gabriel Rosa 2f5d940b46 FIX: google strategy custom scopes 2022-06-27 14:02:51 -03:00
Gabriel Rosa 06a0ed3299 merge new auth with passport oAuth 2022-06-27 11:16:16 -03:00
Gabriel Rosa f08e9dc1a8 FEAT: mailchimp config 2022-06-27 10:03:49 -03:00
Arthur Simas a0c19b587c FIX: logging errors only if auth is required 2022-06-25 20:07:34 -03:00
Arthur Simas 3fe91ad4e8 FIX: logging errors only if auth is required 2022-06-25 20:07:16 -03:00
Gabriel Rosa 07f2d56b9b FEAT: Mailchimp strategy 2022-06-24 16:20:19 -03:00
Arthur Simas 1668d55679 MERGE: auth + connector manager 2022-06-24 14:46:37 -03:00
Gabriel Rosa 498ea61c06 google oauth working 2022-06-24 13:03:16 -03:00
Gabriel Rosa 07f123e528 New strategies 2022-06-24 11:08:38 -03:00
Gabriel Rosa e439823319 update libs 2022-06-24 10:28:05 -03:00
Arthur Simas 55fb1a8b34 FIX: suppressing health check not authenticated log 2022-06-23 23:38:24 -03:00
Arthur Simas 8ce7a692b6 CHORE: added protospack@v2 correct version 2022-06-23 22:03:04 -03:00
Arthur Simas c7997ed8aa FEAT: squash - auth guard
nestjs access controll mock

swagger implementation

middleware changes and lib

permissions file back to maestro

FEAT: sending permissions to duc on startup


FEAT: new permissions.enum format


FEAT: permissions injection (maestro -> duc)


FIX: changing method invocation order


FEAT: refactored permission enum + duc permission injector + grpcHandler


FEAT: auth guards


FEAT: seq ids updated
2022-06-23 22:02:49 -03:00
Victor Radael 0e2f935807 Add insomnia file att 2022-06-23 16:59:08 -03:00
Victor Radael 9e25a1ffa7 Add change body to query params 2022-06-23 16:09:45 -03:00
Victor Radael 44ceee0671 Add change body to query params 2022-06-23 16:08:17 -03:00
Victor Radael 44337dc4ed Add Insomnia Folder 2022-06-21 18:05:56 -03:00
Victor Radael 80e7aa7b9c Fix and add upload file 2022-06-21 18:01:21 -03:00
Victor Radael 6f4bb9ce6d Fix and add upload file 2022-06-21 18:01:06 -03:00
Victor Radael 92afbb5e55 Find All 2022-06-21 10:23:14 -03:00
Victor Radael 953c0ac41e Register Connector 2022-06-20 15:37:45 -03:00
33 changed files with 1859 additions and 763 deletions
+6 -6
View File
@@ -5,18 +5,18 @@
{
"preset": "eslint",
"releaseRules": [
{ "tag": "FIX", "release": "patch" },
{ "tag": "BREAKING", "release": "major" },
{ "tag": "FEAT", "release": "minor" },
{ "tag": "UPDATE", "release": "minor" },
{ "tag": "UPGRADE", "release": "minor" },
{ "tag": "BREAKING", "release": "major" },
{ "tag": "DOCS", "release": "patch" },
{ "tag": "CHORE", "release": "minor" },
{ "tag": "BUILD", "release": "patch" },
{ "tag": "REFACTOR", "release": "minor" },
{ "tag": "PERF", "release": "minor" },
{ "tag": "FIX", "release": "patch" },
{ "tag": "DOCS", "release": "patch" },
{ "tag": "BUILD", "release": "patch" },
{ "tag": "TEST", "release": "patch" },
{ "tag": "CI", "release": "patch" },
{ "tag": "PERF", "release": "minor" }
{ "tag": "CI", "release": "patch" }
]
}
],
Binary file not shown.
+845 -668
View File
File diff suppressed because it is too large Load Diff
+31 -24
View File
@@ -1,5 +1,5 @@
{
"name": "grpc-server-and-client-nestjs-micro-pattern",
"name": "maestro",
"version": "0.0.0",
"description": "",
"author": "",
@@ -25,59 +25,66 @@
},
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@grpc/grpc-js": "^1.5.10",
"@grpc/proto-loader": "^0.6.9",
"@nestjs/common": "^8.4.3",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
"@nestjs/config": "^1.2.1",
"@nestjs/core": "^8.4.3",
"@nestjs/core": "^8.4.7",
"@nestjs/mapped-types": "*",
"@nestjs/microservices": "^8.4.3",
"@nestjs/microservices": "^8.4.7",
"@nestjs/passport": "^8.2.2",
"@nestjs/platform-express": "^8.4.3",
"@nestjs/platform-express": "^8.4.7",
"@nestjs/schedule": "^1.1.0",
"@nestjs/swagger": "^5.2.1",
"@victorradael/protospack": "2.5.0",
"@victorradael/protospack-v2": "1.1.1",
"axios": "^0.25.0",
"cron-parser": "^4.4.0",
"dotenv": "^14.2.0",
"helmet": "^5.0.2",
"dotenv": "^14.3.2",
"helmet": "^5.1.0",
"jsonwebtoken": "^8.5.1",
"jwk-to-pem": "^2.0.5",
"passport": "^0.6.0",
"passport-hubspot": "^0.1.0",
"passport-facebook": "^3.0.0",
"passport-forcedotcom": "^0.1.5",
"passport-google-oauth20": "^2.0.0",
"passport-hubspot-oauth2": "^1.0.3",
"passport-mailchimp": "^1.1.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.5.5",
"swagger-ui-express": "^4.3.0"
"swagger-ui-express": "^4.4.0"
},
"overrides": {
"multer": "1.4.5-lts.1"
},
"devDependencies": {
"@nestjs/cli": "^8.2.4",
"@nestjs/schematics": "^8.0.8",
"@nestjs/testing": "^8.4.3",
"@nestjs/cli": "^8.2.8",
"@nestjs/schematics": "^8.0.11",
"@nestjs/testing": "^8.4.7",
"@types/express": "^4.17.13",
"@types/jest": "27.0.2",
"@types/jsonwebtoken": "^8.5.8",
"@types/jwk-to-pem": "^2.0.1",
"@types/node": "^16.11.26",
"@types/multer": "^1.4.7",
"@types/node": "^16.11.41",
"@types/passport-facebook": "^2.1.11",
"@types/passport-google-oauth20": "^2.0.11",
"@types/passport-oauth2": "^1.4.11",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^5.17.0",
"@typescript-eslint/parser": "^5.17.0",
"eslint": "^8.12.0",
"@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0",
"eslint": "^8.18.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.5.1",
"nock": "^13.2.4",
"prettier": "^2.6.1",
"nock": "^13.2.7",
"prettier": "^2.7.1",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"ts-jest": "^27.1.4",
"ts-loader": "^9.2.7",
"ts-node": "^10.7.0",
"supertest": "^6.2.3",
"ts-jest": "^27.1.5",
"ts-loader": "^9.3.1",
"ts-node": "^10.8.1",
"tsconfig-paths": "^3.14.1",
"typescript": "^4.6.3"
},
+19 -1
View File
@@ -29,17 +29,25 @@ import { InputsClientConfiguration } from './clients/inputs/client.config';
import { PipelinesClientConfiguration } from './clients/pipelines/client.config';
import { CatalogController } from './modules/catalog/catalog.controller';
import { CatalogService } from './modules/catalog/catalog.service';
import { HubspotStrategy } from './modules/oauth/passport-strategies/hubspot';
import { OauthController } from './modules/oauth/oauth.controller';
import { getOauthSecrets } from './utils/OauthSecrets';
import { HubspotStrategy } from './modules/oauth/passport-strategies/hubspot-strategy';
import { FacebookStrategy } from './modules/oauth/passport-strategies/facebook-strategy';
import { AuthenticationGuard } from './authentication/authentication.guard';
import { APP_GUARD } from '@nestjs/core';
import { GoogleStrategy } from './modules/oauth/passport-strategies/google-strategy';
import { MailChimpStrategy } from './modules/oauth/passport-strategies/mailchimp-strategy';
import { SalesforceStrategy } from './modules/oauth/passport-strategies/salesforce-strategy';
import { ConnectorClientConfiguration } from './clients/connector/client.config';
import { ConnectorController } from './modules/connector/connector.controller';
import { ConnectorClientService } from './clients/connector/client.service';
const ducClient = new DucClient();
const inputClient = new InputsClientConfiguration();
const outputClient = new OutputsClientConfiguration();
const pipelineClient = new PipelinesClientConfiguration();
const transformationClient = new TransformationsClientConfiguration();
const connectorClient = new ConnectorClientConfiguration();
@Module({
controllers: [
@@ -51,6 +59,7 @@ const transformationClient = new TransformationsClientConfiguration();
HealthController,
CatalogController,
OauthController,
ConnectorController,
],
providers: [
{ provide: 'OAUTH_SECRETS', useValue: getOauthSecrets() },
@@ -58,6 +67,7 @@ const transformationClient = new TransformationsClientConfiguration();
TransformationsService,
OutputsService,
PipelinesService,
ConnectorClientService,
HealthService,
InputsClientService,
TransformationsClientService,
@@ -67,6 +77,10 @@ const transformationClient = new TransformationsClientConfiguration();
PermissionsClientService,
CatalogService,
HubspotStrategy,
FacebookStrategy,
GoogleStrategy,
MailChimpStrategy,
SalesforceStrategy,
{
provide: APP_GUARD,
useClass: AuthenticationGuard,
@@ -98,6 +112,10 @@ const transformationClient = new TransformationsClientConfiguration();
name: 'PIPELINES_PACKAGE',
...pipelineClient.config(),
},
{
name: 'CONNECTOR_PACKAGE',
...connectorClient.config(),
},
]),
],
})
+17 -4
View File
@@ -14,8 +14,11 @@ export interface Permission {
usage: PermissionUsages;
}
// like field numbers in gRPC, avoid to change (or reuse previously used) seqids once its
// deployed to DUC
/*
- like field numbers in gRPC, avoid to change (or reuse previously used) seqids once its deployed to DUC
- it is possible to update claim and usage, not seqid
*/
/*export const Permissions: {
[P in keyof any]: { [Q in keyof any]: Permission };
} = {*/
@@ -201,9 +204,19 @@ export const Permissions = {
},
ORCHEST: {
USE: {
INTELLIGENCE: {
seqid: 31,
claim: 'orchest:use',
claim: 'intelligence:open',
usage: PermissionUsages.PUBLIC,
},
APP_BUILDER: {
seqid: 32,
claim: 'app-builder:open',
usage: PermissionUsages.PUBLIC,
},
MACHINE_LEARNING: {
seqid: 33,
claim: 'machine-learning:open',
usage: PermissionUsages.PUBLIC,
},
},
+31
View File
@@ -0,0 +1,31 @@
import { credentials } from '@grpc/grpc-js';
import { ClientOptions, Transport } from '@nestjs/microservices';
import { ConnectorManager } from '@victorradael/protospack-v2';
export class ConnectorClientConfiguration {
config(): ClientOptions {
return {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: [
ConnectorManager.ProtoPackages.WritePackage,
ConnectorManager.ProtoPackages.ReadPackage,
],
credentials:
process.env.LOCAL_ENV === 'local'
? undefined
: credentials.createSsl(),
protoPath: [
ConnectorManager.ProtoPaths.WriteFilePath,
ConnectorManager.ProtoPaths.ReadFilePath,
],
loader: {
enums: String,
objects: true,
arrays: true,
},
},
};
}
}
+266
View File
@@ -0,0 +1,266 @@
import {
OnModuleInit,
Inject,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { ConnectorManager } from '@victorradael/protospack-v2';
import { from } from 'rxjs';
export class ConnectorClientService implements OnModuleInit {
private connectorServiceRead: ConnectorManager.ReadService.ConnectorManagerReadServices;
private connectorServiceWrite: ConnectorManager.WriteService.ConnectorManagerWriteServices;
constructor(
@Inject('CONNECTOR_PACKAGE') private readonly grpcClient: ClientGrpc,
) {}
onModuleInit() {
this.connectorServiceWrite =
this.grpcClient.getService<ConnectorManager.WriteService.ConnectorManagerWriteServices>(
ConnectorManager.ProtoServices.ConnectorManagerWriteServices,
);
this.connectorServiceRead =
this.grpcClient.getService<ConnectorManager.ReadService.ConnectorManagerReadServices>(
ConnectorManager.ProtoServices.ConnectorManagerReadServices,
);
}
async uploadConnector(uploadConnector) {
const connector: ConnectorManager.Entities.ConnectorCreateRequest = {
file: {
buffer: uploadConnector.file.buffer,
mimetypes: uploadConnector.file.mimetype,
},
connector: JSON.stringify(uploadConnector.connector),
};
const serviceBody: ConnectorManager.Messages.RegisterConnectorRequest = {
connector,
};
const observable = from(
this.connectorServiceWrite.RegisterConnector(serviceBody),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
console.log('Observable Error');
reject(err);
},
complete() {
console.log('done');
},
});
}).catch((err) => {
console.log(err.details);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
console.log('ConnectorClientService', 'Upload');
return result;
}
async uploadFile(uploadFile) {
const body: ConnectorManager.Messages.UploadFileRequest = {
file: {
buffer: uploadFile.file.buffer,
mimetypes: uploadFile.file.mimetype,
},
name: uploadFile.name,
};
const observable = from(this.connectorServiceWrite.UploadFile(body));
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
console.log('Observable Error');
reject(err);
},
complete() {
console.log('done');
},
});
}).catch((err) => {
console.log(err.details);
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
console.log('ConnectorClientService', 'Upload');
return result;
}
async getAllConnectors(body) {
const observable = from(
this.connectorServiceRead.GetAllConnectors({
search: body.search,
filters: JSON.stringify(body.filters),
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
console.log('Observable Error');
reject(err);
},
complete() {
console.log('done');
},
});
}).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
console.log('ConnectorClientService', 'getAllConnectors');
return result;
}
async getConnectorDetails(plugin: string) {
const observable = from(
this.connectorServiceRead.GetConnectorDetails({
plugin,
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
console.log('Observable Error');
reject(err);
},
complete() {
console.log('done');
},
});
}).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
console.log('ConnectorClientService', 'getAllConnectors');
return result;
}
async getConnector(plugin: string) {
const observable = from(
this.connectorServiceRead.GetConnector({
plugin,
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
console.log('Observable Error');
reject(err);
},
complete() {
console.log('done');
},
});
}).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
console.log('ConnectorClientService', 'getAllConnectors');
return result;
}
async deleteConnector(plugin: string, version: string) {
const observable = from(
this.connectorServiceWrite.DeleteConnector({
version,
plugin,
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
console.log('Observable Error');
reject(err);
},
complete() {
console.log('done');
},
});
}).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
console.log('ConnectorClientService', 'getAllConnectors');
return result;
}
async updateConnector({ plugin, changes }) {
const observable = from(
this.connectorServiceWrite.UpdateConnector({
plugin,
changes,
}),
);
const result = await new Promise((resolve, reject) => {
observable.subscribe({
next(x) {
resolve(x);
},
error(err) {
console.log('Observable Error');
reject(err);
},
complete() {
console.log('done');
},
});
}).catch((err) => {
throw new HttpException(
err.details,
err.code === 6 ? HttpStatus.CONFLICT : 400,
);
});
console.log('ConnectorClientService', 'getAllConnectors');
return result;
}
}
+1 -1
View File
@@ -64,7 +64,7 @@ export class InputsClientService implements OnModuleInit {
const structReturn = await lastValueFrom(
this.inputService.Create(grpcPayload),
).catch((err) => {
).catch((err: { details: string }) => {
if (err.details === 'Item Not found!') {
throw new NotFoundException('Input not found');
}
+17 -25
View File
@@ -1,9 +1,15 @@
import { HttpException, Inject, OnModuleInit } from '@nestjs/common';
import {
BadRequestException,
Inject,
InternalServerErrorException,
OnModuleInit,
} from '@nestjs/common';
import { ClientGrpc, Payload } from '@nestjs/microservices';
import {
PipelineServicesNames,
PipelinesServiceInterface,
} from '@victorradael/protospack';
import { lastValueFrom } from 'rxjs';
import {
objectCamelToSnake,
objectSnakeToCamel,
@@ -30,30 +36,16 @@ export class PipelinesClientService implements OnModuleInit {
async create(@Payload() createPipelineDto: ICreatePipelineDto) {
console.log('PipelinesClientService', 'Create');
const createPipelineResponse = await new Promise((resolve, reject) => {
this.pipelineService
.Create(objectSnakeToCamel(createPipelineDto))
.subscribe({
next(x) {
resolve(x);
},
error(err) {
console.log('Observable Error');
reject(err);
},
complete() {
console.log('done');
},
});
})
.then((res) => res)
.catch((err) => {
if (err.details == 'Invalid Request') {
throw new HttpException(err.details, 400);
}
throw new HttpException(err.details, 500);
});
const createPipelineResponse = await lastValueFrom(
this.pipelineService.Create(objectSnakeToCamel(createPipelineDto)),
).catch((error: { details: string }) => {
if (error.details.includes('INVALID_REQUEST')) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [errorType, message] = error.details.split('|');
throw new BadRequestException(message);
}
throw new InternalServerErrorException(error.details);
});
return createPipelineResponse;
}
+7 -3
View File
@@ -1,8 +1,9 @@
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { writeFileSync } from 'fs';
import helmet from 'helmet';
import documentEmpty from '../swagger_empty.json';
import { AppModule } from './app.module';
async function bootstrap() {
@@ -18,17 +19,20 @@ async function bootstrap() {
app.use(helmet());
const config = new DocumentBuilder()
.setTitle('Maestro Grpc Documentation')
.setTitle('Maestro')
.setDescription('Documentation for Maestro gateway')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
writeFileSync('./swagger.json', JSON.stringify(document));
if (process.env.ENV != 'stg' && process.env.ENV != 'prd')
SwaggerModule.setup('api', app, document);
const swaggerDoc = process.env.ENV === 'dev' ? document : documentEmpty;
SwaggerModule.setup('api', app, swaggerDoc);
await app.listen(3333);
}
bootstrap();
+1
View File
@@ -26,6 +26,7 @@ import { PermissionsClientService } from '../../clients/permissions/client.servi
import { Permissions } from '../../authentication/permissions.enum';
import ErrorBuilder from '../../utils/ErrorBuilder';
import { LoginDto } from './dtos/login';
@ApiTags('Auth')
@Controller('auth')
+12
View File
@@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
export class LoginDto {
@ApiProperty()
username: string;
@ApiProperty()
password: string;
@ApiProperty({ required: false })
totp: string;
}
@@ -0,0 +1,210 @@
import {
Body,
Controller,
Delete,
Get,
HttpException,
Param,
Put,
Post,
Query,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { ConnectorClientService } from 'src/clients/connector/client.service';
import { AddTagDto } from './dtos/add-tag';
import { CreateConnectorDto } from './dtos/create-connector';
import { DeleteConnectorDto } from './dtos/delete-connector';
import { GetAllDto } from './dtos/get-all';
import { RemoveTagDto } from './dtos/remove-tag';
import { UpdateDto } from './dtos/update';
import { UploadFileDto } from './dtos/upload-file';
@ApiTags('connectors')
@ApiBearerAuth()
@Controller('connectors')
export class ConnectorController {
constructor(private connectorClientService: ConnectorClientService) {}
@Post()
@ApiConsumes('multipart/form-data')
@UseInterceptors(FileInterceptor('file'))
async uploadConnector(
@UploadedFile() file,
@Body() body: CreateConnectorDto,
) {
console.log(`/upload`, 'Upload Connector Route');
const response = await this.connectorClientService.uploadConnector({
file,
connector: JSON.parse(body.connector),
});
return response;
}
@Post('/upload')
@ApiConsumes('multipart/form-data')
@UseInterceptors(FileInterceptor('file'))
async uploadFile(@UploadedFile() file, @Body() { name }: UploadFileDto) {
console.log(`/upload`, 'Upload Connector Route');
const response = await this.connectorClientService.uploadFile({
file,
name,
});
return response;
}
@Get()
async getAllConnectors(@Query() queries: GetAllDto) {
console.log(`/upload`, 'Upload Connector Route');
const { search, ...filters } = queries;
const response: any = await this.connectorClientService.getAllConnectors({
filters: filters || {},
search: search || '',
});
const connectors = JSON.parse(response.connectors).connectors;
return {
message: response.message,
connectors,
};
}
@Get('/:plugin')
async getConnector(
@Param('plugin') plugin: string,
@Query('version') version: string,
) {
console.log(`/upload`, 'Upload Connector Route');
const pluginId = `${plugin}-${version}`;
const response: any = await this.connectorClientService.getConnector(
pluginId,
);
return {
message: response.message || 'ok',
connector: { ...JSON.parse(response.connector) },
};
}
@Get('/:plugin/details')
async getConnectorDetails(
@Param('plugin') plugin: string,
@Query('version') version: string,
) {
console.log(`/upload`, 'Upload Connector Route');
const pluginId = `${plugin}-${version}`;
const response: any = await this.connectorClientService.getConnectorDetails(
pluginId,
);
return {
message: response.message || 'ok',
connector: { ...JSON.parse(response.connector) },
};
}
@Put('/:plugin')
@ApiConsumes('multipart/form-data')
async updateConnector(
@Param('plugin') plugin: string,
@Body() body: UpdateDto,
) {
console.log(`/upload`, 'Upload Connector Route');
const changes = body;
const response: any = await this.connectorClientService.updateConnector({
plugin,
changes: JSON.stringify(changes),
});
return {
message: response.message || 'ok',
connector: { ...JSON.parse(response.connector) },
};
}
@Put('/:plugin/add-tag')
async addTagOnConnector(
@Param('plugin') plugin: string,
@Body() body: AddTagDto,
) {
console.log(`/upload`, 'Upload Connector Route');
const { tags } = body;
if (!tags || !(typeof tags === 'object') || !tags.length) {
throw new HttpException('Not found tags attributes', 400);
}
const changes = { plugin, tags };
const response: any = await this.connectorClientService.updateConnector({
plugin,
changes: JSON.stringify(changes),
});
return {
message: response.message || 'ok',
connector: { ...JSON.parse(response.connector) },
};
}
@Put('/:plugin/remove-tag')
async removeTagOnConnector(
@Param('plugin') plugin: string,
@Body() body: RemoveTagDto,
) {
console.log(`/upload`, 'Upload Connector Route');
const { tags } = body;
const remove = tags;
if (!remove || !(typeof remove === 'object') || !remove.length) {
throw new HttpException('Not found remove attribute', 400);
}
const changes = { plugin, remove };
const response: any = await this.connectorClientService.updateConnector({
plugin,
changes: JSON.stringify(changes),
});
return {
message: response.message || 'ok',
connector: { ...JSON.parse(response.connector) },
};
}
@Delete('/:plugin')
async deleteConnector(
@Param('plugin') plugin: string,
@Body() { version }: DeleteConnectorDto,
) {
console.log(`/upload`, 'Upload Connector Route');
const response: any = await this.connectorClientService.deleteConnector(
plugin,
version,
);
return {
message: response.message || 'ok',
connector: { ...JSON.parse(response.connector) },
};
}
}
+6
View File
@@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
export class AddTagDto {
@ApiProperty()
tags: string[];
}
@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';
export class CreateConnectorDto {
@ApiProperty({ format: 'binary' })
file: string;
@ApiProperty()
connector: string;
}
@@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
export class DeleteConnectorDto {
@ApiProperty()
version: string;
}
+9
View File
@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';
export class GetAllDto {
@ApiProperty()
search: string;
@ApiProperty()
filters: any;
}
+6
View File
@@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
export class RemoveTagDto {
@ApiProperty()
tags: string[];
}
+42
View File
@@ -0,0 +1,42 @@
import { ApiProperty } from '@nestjs/swagger';
export class UpdateDto {
@ApiProperty({ format: 'binary', required: false })
file?: string;
@ApiProperty()
version: string;
@ApiProperty({ required: false })
category?: string;
@ApiProperty({ required: false })
plugin?: string;
@ApiProperty({ required: false })
image?: string;
@ApiProperty({ required: false })
docs?: string;
@ApiProperty({ required: false })
name?: string;
@ApiProperty({
required: false,
description: 'skip_select_entities: boolean skip_select_columns: boolean;',
})
options?: {
skip_select_entities: boolean;
skip_select_columns: boolean;
};
@ApiProperty({
required: false,
type: 'array',
items: {
properties: {},
},
})
connection_controls?: object[];
}
@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';
export class UploadFileDto {
@ApiProperty({ format: 'binary' })
file: string;
@ApiProperty()
name: string;
}
-1
View File
@@ -10,7 +10,6 @@ import {
import { InputsService } from './inputs.service';
import { InputsClientService } from 'src/clients/inputs/client.service';
import { UpdateInputRequest } from 'src/clients/inputs/interfaces';
import { InputNewCreateRequest } from '@victorradael/protospack';
import { Permissions } from '../../authentication/permissions.enum';
import { AuthenticateCondition } from 'src/authentication/authentication.decorator';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
+91 -15
View File
@@ -1,16 +1,9 @@
import {
BadRequestException,
Controller,
Get,
Query,
Redirect,
Req,
UseGuards,
} from '@nestjs/common';
import { Controller, Get, Redirect, Req, UseGuards } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { InputsClientService } from 'src/clients/inputs/client.service';
import { InputsService } from '../inputs/inputs.service';
import { Request } from 'express';
@ApiTags('oauth')
@Controller('oauth')
@@ -40,15 +33,98 @@ export class OauthController {
@Get('hubspot/callback')
@UseGuards(AuthGuard('hubspot'))
@Redirect()
async oauthHubspotCallback(@Req() req, @Query('state') customer_id) {
const { authInfo } = req;
if (!authInfo) throw new BadRequestException('Oauth tokens not found');
const { accessToken, refreshToken } = authInfo;
async oauthHubspotCallback(@Req() req) {
return await this.callback(req, 'hubspot');
}
@Get('googleads')
@UseGuards(AuthGuard('google'))
async oauthGoogleAds() {
return true;
}
@Get('googleads/callback')
@UseGuards(AuthGuard('google'))
@Redirect()
async oauthGoogleAdsCallback(@Req() req) {
return await this.callback(req, 'googleads');
}
@Get('google-sheets')
@UseGuards(AuthGuard('google'))
async oauthGoogleSheets() {
return true;
}
@Get('google-sheets/callback')
@UseGuards(AuthGuard('google'))
@Redirect()
async oauthGoogleSheetsCallback(@Req() req) {
return await this.callback(req, 'google-sheets');
}
@Get('facebook')
@UseGuards(AuthGuard('facebook'))
async oauthFacebook() {
return true;
}
@Get('facebook/callback')
@UseGuards(AuthGuard('facebook'))
@Redirect()
async oauthFacebookCallback(@Req() req) {
return await this.callback(req, 'facebook');
}
@Get('mailchimp')
@UseGuards(AuthGuard('mailchimp'))
async oauthMailchimp() {
return true;
}
@Get('mailchimp/callback')
@UseGuards(AuthGuard('mailchimp'))
@Redirect()
async oauthMailchimpCallback(@Req() req) {
return await this.callback(req, 'mailchimp');
}
@Get('salesforce')
@UseGuards(AuthGuard('salesforce'))
async oauthSalesforce() {
return true;
}
@Get('salesforce/callback')
@UseGuards(AuthGuard('salesforce'))
@Redirect()
async oauthSalesforceCallback(@Req() req) {
return await this.callback(req, 'salesforce');
}
async callback(@Req() req: Request, plugin) {
const { error, state: customer_id } = req.query;
if (error)
return {
url: `${this.frontendRedirectUri}?error=${error}`,
};
const request: any = req;
const { authInfo } = request;
if (!authInfo)
return {
url: `${this.frontendRedirectUri}?error=invalid_credentials`,
};
const { accessToken: access_token, refreshToken: refresh_token } = authInfo;
const response = await this.inputService.create({
info: { customer_id, customer: 'customer', user_id: 'empty' },
plugin: 'hubspot',
credentials: { access_token: accessToken, refresh_token: refreshToken },
plugin,
credentials: { access_token, refresh_token },
});
return { url: `${this.frontendRedirectUri}?input_id=${response.input.id}` };
}
}
@@ -0,0 +1,32 @@
import {
Profile,
Strategy,
StrategyOptionWithRequest,
VerifyFunction,
} from 'passport-facebook';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
@Injectable()
export class FacebookStrategy extends PassportStrategy(Strategy) {
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
) {
const options: StrategyOptionWithRequest = {
clientID: oauthSecrets.facebook.client_id,
clientSecret: oauthSecrets.facebook.client_secret,
callbackURL: oauthSecrets.facebook.redirect_uri,
passReqToCallback: true,
};
const verify: VerifyFunction = (
accessToken: string,
refreshToken: string,
profile: Profile,
done: (error: any, user?: any, info?: any) => void,
) => done(null, profile, { accessToken, refreshToken });
super(options, verify);
}
}
@@ -0,0 +1,68 @@
import { Profile, Strategy, StrategyOptions } from 'passport-google-oauth20';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
redirect_uri: string;
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
) {
const options: StrategyOptions = {
clientID: oauthSecrets.google.client_id,
clientSecret: oauthSecrets.google.client_secret,
callbackURL: '/oauth/googleads/callback',
};
const verify = (
accessToken: string,
refreshToken: string,
profile: Profile,
done,
) => {
console.log('verify');
return done(null, profile, { accessToken, refreshToken });
};
super(options, verify);
switch (process.env.ENV) {
case 'dev':
case 'stg':
this.redirect_uri = `https://maestro.${process.env.ENV}.dadosfera.ai/oauth`;
break;
case 'prd':
this.redirect_uri = `https://maestro.dadosfera.ai/oauth`;
break;
default:
this.redirect_uri = `/oauth`;
break;
}
}
authenticate(req, options) {
const plugin: string = req.route.path
.replace('/oauth/', '')
.replace('/callback', '');
const { customer_id } = req.query;
options.scope = ['https://www.googleapis.com/auth/userinfo.email'];
options.callbackURL = `${this.redirect_uri}/${plugin}/callback`;
switch (plugin) {
case 'googleads':
options.scope.push('https://www.googleapis.com/auth/adwords');
break;
case 'google-sheets':
options.scope.push(
'https://www.googleapis.com/auth/drive.metadata.readonly',
'https://www.googleapis.com/auth/spreadsheets.readonly',
);
break;
}
options.state = customer_id;
options.accessType = 'offline';
options.prompt = 'consent';
super.authenticate(req, options);
}
}
@@ -14,7 +14,6 @@ export class HubspotStrategy extends PassportStrategy(Strategy) {
clientID: oauthSecrets.hubspot.client_id,
clientSecret: oauthSecrets.hubspot.client_secret,
callbackURL: oauthSecrets.hubspot.redirect_uri,
redirectUri: oauthSecrets.hubspot.redirect_uri,
scope:
'automation business-intelligence oauth forms integration-sync sales-email-read crm.lists.read crm.objects.contacts.read crm.schemas.contacts.read crm.objects.companies.read crm.objects.deals.read crm.schemas.companies.read crm.schemas.deals.read crm.objects.owners.read crm.objects.quotes.read crm.schemas.quotes.read crm.objects.line_items.read crm.schemas.line_items.read',
passReqToCallback: true,
@@ -0,0 +1,35 @@
import { Strategy } from 'passport-mailchimp';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable, Req } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
@Injectable()
export class MailChimpStrategy extends PassportStrategy(Strategy, 'mailchimp') {
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
) {
const options = {
clientID: oauthSecrets.mailchimp.client_id,
clientSecret: oauthSecrets.mailchimp.client_secret,
callbackURL: oauthSecrets.mailchimp.redirect_uri,
scope: '',
};
const verify = (
accessToken: string,
refreshToken: string,
profile: any,
done,
) => {
return done(null, profile, { accessToken, refreshToken });
};
super(options, verify);
}
authenticate(@Req() req, options) {
const { customer_id } = req.query;
options.state = customer_id;
super.authenticate(req, options);
}
}
@@ -0,0 +1,47 @@
import { Strategy } from 'passport-forcedotcom';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
@Injectable()
export class SalesforceStrategy extends PassportStrategy(
Strategy,
'salesforce',
) {
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
) {
const options = {
clientID: oauthSecrets.salesforce.client_id,
clientSecret: oauthSecrets.salesforce.client_secret,
callbackURL: oauthSecrets.salesforce.redirect_uri,
scope: [
'wave_api',
'chatter_api',
'chatbot_api',
'cdp_ingest_api',
'cdp_profile_api',
'api',
'pardot_api',
'cdp_segment_api',
'cdp_query_api',
'refresh_token',
'offline_access',
],
};
const verify = ({ params }, refreshToken: string, profile: any, done) => {
return done(null, profile, {
accessToken: params.access_token,
refreshToken,
});
};
super(options, verify);
}
authenticate(req, options) {
const { customer_id } = req.query;
options.state = customer_id;
super.authenticate(req, options);
}
}
+6 -11
View File
@@ -17,19 +17,14 @@ export class PipelinesService {
}
async create(createPipelineDto) {
try {
const createPipelineResponse = await this.pipelineClient.create(
createPipelineDto,
);
const createPipelineResponse = await this.pipelineClient.create(
createPipelineDto,
);
const pipeline = objectCamelToSnake(createPipelineResponse);
this.adjustPayload(pipeline.pipeline);
const pipeline = objectCamelToSnake(createPipelineResponse);
this.adjustPayload(pipeline.pipeline);
return pipeline;
} catch (err) {
console.log(err);
throw new HttpException(err.message, HttpStatus.NOT_FOUND);
}
return pipeline;
}
async findOne(data: IIdRequest) {
+11 -1
View File
@@ -13,6 +13,8 @@ export class OauthSecrets {
hubspot = new OauthSecretsObject();
google = new OauthSecretsObject();
mailchimp = new OauthSecretsObject();
facebook = new OauthSecretsObject();
salesforce = new OauthSecretsObject();
}
export async function getOauthSecrets() {
const secrets = new OauthSecrets();
@@ -25,7 +27,15 @@ export async function getOauthSecrets() {
const res = await secretsManagerClient
.send(getSecretComand)
.catch(() => null);
if (res) secrets[key] = JSON.parse(res.SecretString);
if (res) {
secrets[key] = JSON.parse(res.SecretString);
} else {
secrets[key] = {
client_id: 'id',
client_secret: 'id',
redirect_uri: 'id',
};
}
}
return secrets;
}
-1
View File
File diff suppressed because one or more lines are too long
+17
View File
@@ -0,0 +1,17 @@
{
"openapi": "3.0.0",
"paths": {
},
"info": {
"title": "404",
"description": "",
"version": "",
"contact": {}
},
"tags": [],
"servers": [],
"components": {
"schemas": {}
}
}
+2 -1
View File
@@ -17,6 +17,7 @@
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false
"noFallthroughCasesInSwitch": false,
"resolveJsonModule": true
}
}