diff --git a/docsfera.json b/docsfera.json index 0f21c43..96f6350 100644 --- a/docsfera.json +++ b/docsfera.json @@ -5371,92 +5371,6 @@ ] } }, - "/customers/{id}/theme": { - "post": { - "operationId": "CustomersController_saveCustomertheme", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomerThemeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomerThemeResponse" - } - } - } - }, - "201": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomerThemeResponse" - } - } - } - } - }, - "tags": [ - "Customers" - ], - "security": [ - { - "access-token": [] - }, - { - "access-token": [] - } - ] - }, - "get": { - "operationId": "CustomersController_getCustomerTheme", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CustomerThemeResponse" - } - } - } - } - }, - "tags": [ - "Customers" - ] - } - }, "/customers/token": { "get": { "operationId": "CustomersController_getCustomerToken", @@ -5517,20 +5431,6 @@ ] } }, - "/health": { - "get": { - "operationId": "HealthController_check", - "parameters": [], - "responses": { - "200": { - "description": "" - } - }, - "tags": [ - "Health" - ] - } - }, "/open-data/sharing-ocean-data": { "post": { "operationId": "OpenDataController_createUser", @@ -5546,6 +5446,37 @@ ], "type": "string" } + }, + { + "name": "language", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "OpenData" + ] + } + }, + "/customers/{id}/theme": { + "post": { + "operationId": "ThemeController_saveCustomertheme", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } } ], "requestBody": { @@ -5553,18 +5484,78 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateUserOpenDataDTO" + "$ref": "#/components/schemas/CustomerThemeRequest" } } } }, "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerThemeResponse" + } + } + } + }, "201": { "description": "" } }, "tags": [ - "OpenData" + "Theme" + ], + "security": [ + { + "access-token": [] + }, + { + "access-token": [] + } + ] + }, + "get": { + "operationId": "ThemeController_getCustomerTheme", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerThemeResponse" + } + } + } + } + }, + "tags": [ + "Theme" + ] + } + }, + "/health": { + "get": { + "operationId": "HealthController_check", + "parameters": [], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "Health" ] } } @@ -8344,27 +8335,37 @@ "links" ] }, + "CustomerLinkRequest": { + "type": "object", + "properties": { + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerLink" + } + } + }, + "required": [ + "links" + ] + }, "CustomerThemeRequest": { "type": "object", "properties": { + "displayName": { + "type": "string" + }, "backgroundColor": { "type": "string" }, "textColor": { "type": "string" - }, - "logoWhite": { - "type": "string" - }, - "logoBlack": { - "type": "string" } }, "required": [ + "displayName", "backgroundColor", - "textColor", - "logoWhite", - "logoBlack" + "textColor" ] }, "CustomerTheme": { @@ -8400,47 +8401,6 @@ "required": [ "theme" ] - }, - "CustomerLinkRequest": { - "type": "object", - "properties": { - "links": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CustomerLink" - } - } - }, - "required": [ - "links" - ] - }, - "CreateUserOpenDataDTO": { - "type": "object", - "properties": { - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "organization": { - "type": "string" - }, - "enquiryType": { - "type": "string" - } - }, - "required": [ - "firstName", - "lastName", - "email", - "organization", - "enquiryType" - ] } } } diff --git a/package-lock.json b/package-lock.json index c1ea922..839fb46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@aws-sdk/client-secrets-manager": "^3.414.0", "@dadosfera/dadosfera-logs": "^1.0.0-beta.4", "@dadosfera/protospack": "2.5.3", - "@dadosfera/protospack-v2": "3.37.0-beta.1", + "@dadosfera/protospack-v2": "3.37.0-beta.3", "@grpc/grpc-js": "^1.9.3", "@grpc/proto-loader": "^0.7.9", "@nestjs/cli": "^9.5.0", @@ -53,7 +53,7 @@ "@types/jest": "27.0.2", "@types/jsonwebtoken": "^8.5.9", "@types/jwk-to-pem": "^2.0.1", - "@types/multer": "^1.4.7", + "@types/multer": "^1.4.12", "@types/node": "^16.18.52", "@types/passport-facebook": "^2.1.11", "@types/passport-google-oauth20": "^2.0.11", @@ -1403,9 +1403,9 @@ } }, "node_modules/@dadosfera/protospack-v2": { - "version": "3.37.0-beta.1", - "resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.37.0-beta.1.tgz", - "integrity": "sha512-AcDxeg7KruBJncOXbLJFHKH/5GQ9VHR8MxU7s1o1lrZVfZY4Ht3UWmvwL1F2b+6DIhTDqzVOsKjfg7KAbuDYuw==", + "version": "3.37.0-beta.3", + "resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.37.0-beta.3.tgz", + "integrity": "sha512-9YSgzkXVqe9QsBxJjfxYxttAiyCXxgq49Xjs3OvnTLCXRDn3XtTlPaC+yHrTEUgCkQyhlDZuswe6f6oBImqIRQ==", "license": "ISC", "dependencies": { "@grpc/grpc-js": "^1.9.3", @@ -3527,10 +3527,11 @@ "dev": true }, "node_modules/@types/multer": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.11.tgz", - "integrity": "sha512-svK240gr6LVWvv3YGyhLlA+6LRRWA4mnGIU7RcNmgjBYFl6665wcXrRfxGp5tEPVHUNm5FMcmq7too9bxCwX/w==", + "version": "1.4.12", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.12.tgz", + "integrity": "sha512-pQ2hoqvXiJt2FP9WQVLPRO+AmiIm/ZYkavPlIQnx282u4ZrVdztx0pkh3jjpQt0Kz+YI0YhSG264y08UJKoUQg==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } diff --git a/package.json b/package.json index 8300759..41ac8c1 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@aws-sdk/client-secrets-manager": "^3.414.0", "@dadosfera/dadosfera-logs": "^1.0.0-beta.4", "@dadosfera/protospack": "2.5.3", - "@dadosfera/protospack-v2": "3.37.0-beta.1", + "@dadosfera/protospack-v2": "3.37.0-beta.3", "@grpc/grpc-js": "^1.9.3", "@grpc/proto-loader": "^0.7.9", "@nestjs/cli": "^9.5.0", @@ -74,7 +74,7 @@ "@types/jest": "27.0.2", "@types/jsonwebtoken": "^8.5.9", "@types/jwk-to-pem": "^2.0.1", - "@types/multer": "^1.4.7", + "@types/multer": "^1.4.12", "@types/node": "^16.18.52", "@types/passport-facebook": "^2.1.11", "@types/passport-google-oauth20": "^2.0.11", diff --git a/src/app.module.ts b/src/app.module.ts index 1cf1611..3e54fde 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -27,6 +27,7 @@ import { ProductboardModule } from './modules/productboard/productboard.module'; import { MixpanelModule } from './modules/mixpanel/mixpanel.module'; import { CustomersModule } from './modules/customers/customers.module'; import { OpenDataModule } from './modules/open-data/open-data.module'; +import { ThemeModule } from './modules/theme/theme.module'; @Module({ providers: [ @@ -58,9 +59,10 @@ import { OpenDataModule } from './modules/open-data/open-data.module'; ProductboardModule, MixpanelModule, CustomersModule, - //Always leave HealthModule last, so it is on the bottom of swagger - HealthModule, OpenDataModule, + ThemeModule, + //Always leave HealthModule last, so it is on the bottom of swagger + HealthModule ], }) export class AppModule {} diff --git a/src/modules/customers/customers.controller.ts b/src/modules/customers/customers.controller.ts index 7afc3fb..1bd9835 100644 --- a/src/modules/customers/customers.controller.ts +++ b/src/modules/customers/customers.controller.ts @@ -1,15 +1,12 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs'; -import { IdResponse } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages'; import { Body, Controller, Get, HttpCode, - HttpException, HttpStatus, Inject, Param, - Post, Put, Query, UseFilters, @@ -22,11 +19,10 @@ import { } from 'src/decorators/authentication.decorator'; import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter'; import { CustomersService } from './customers.service'; -import { CustomerLinkRequest, CustomerLinksResponse, CustomerThemeRequest, CustomerThemeResponse } from './dtos/customers'; +import { CustomerLinkRequest, CustomerLinksResponse } from './dtos/customers'; import { RequestUser, User } from 'src/decorators/user.decorator'; import type { StringValue } from 'ms'; import { PackTheMetadata } from 'src/utils/ PackTheMetadata'; -import ErrorCodes from 'src/utils/errorCodes'; @ApiTags('Customers') @Controller('customers') @@ -51,51 +47,6 @@ export class CustomersController { return { links }; } - @Post(':id/theme') - @Authenticated() - @RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN) - @ApiOkResponse({ type: CustomerThemeResponse }) - async saveCustomertheme(@Param('id') id: string, @Body() data: CustomerThemeRequest) { - this.logger.info('saveCustomertheme', JSON.stringify({ - id, theme: data - })); - - try { - // const theme = await this.customersService.createThemeByCustomer(id, data); - this.logger.info('saveCustomertheme', JSON.stringify(data)); - return { theme: null }; - } catch (err) { - if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND) { - this.logger.error('Error - saveCustomertheme - Expect CUSTOMER.NOT_FOUND'); - throw new HttpException(err.details, HttpStatus.NOT_FOUND); - } else { - this.logger.error('Error - saveCustomertheme Unknown Error:' + err?.message); - return { theme: null }; - }; - } - - } - - @Get(':id/theme') - @ApiOkResponse({ type: CustomerThemeResponse }) - async getCustomerTheme(@Param('id') id: string) { - this.logger.info('getCustomerTheme with id' + id); - - try { - const data = await this.customersService.getThemeByCustomer(id); - this.logger.info('Success - getCustomerTheme with id'+ id); - return data; - }catch (err) { - if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND) { - this.logger.error('Error - getCustomerTheme - Expect CUSTOMER.NOT_FOUND'); - throw new HttpException(err.details, HttpStatus.NOT_FOUND); - } else { - this.logger.error('Error - getCustomerTheme Unknown Error:' + err?.message); - return { theme: null }; - }; - } - } - @Put(':id/links') @Authenticated() @RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN) diff --git a/src/modules/customers/customers.service.ts b/src/modules/customers/customers.service.ts index 4e2ce3a..cd7f472 100644 --- a/src/modules/customers/customers.service.ts +++ b/src/modules/customers/customers.service.ts @@ -28,7 +28,6 @@ import { } from '@dadosfera/protospack-v2/dist/lib/PipelineV2'; import { Metadata } from '@grpc/grpc-js'; import { PipelinesClientConfiguration } from '../pipelinesV2/pipelines-client'; -import { CustomerThemeRequest, CustomerThemeResponse } from './dtos/customers'; import DadosferaLogger from '@dadosfera/dadosfera-logs'; // This function will accept any string, which may result in a bug. @@ -90,39 +89,6 @@ export class CustomersService implements OnModuleInit { } } - async createThemeByCustomer(id: string, theme: CustomerThemeRequest): Promise { - if (!id) { - this.logger.error('Error - saveCustomertheme - not found id:' + id); - throw new HttpException(null, HttpStatus.BAD_REQUEST); - } - - const result = await firstValueFrom( - this.customerService.CustomerCreateTheme({ - customerId: id, - theme - }), - ); - return { theme: result }; - - } - - async getThemeByCustomer(id: string): Promise { - if (!id) { - this.logger.error('Error - getCustomerTheme - not found id:' + id); - throw new HttpException(null, HttpStatus.BAD_REQUEST); - } - - const result = await firstValueFrom( - this.customerService.CustomerGetTheme({ - id - }), - ); - - return { - theme: result - } - } - async generateToken( expiresIn = '30m', data: { customerId: string; userId: string; customerName: string }, diff --git a/src/modules/customers/dtos/customers.ts b/src/modules/customers/dtos/customers.ts index e26fc94..db56ee3 100644 --- a/src/modules/customers/dtos/customers.ts +++ b/src/modules/customers/dtos/customers.ts @@ -1,4 +1,4 @@ -import { Link, Theme } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities'; +import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export class CustomerLink implements Link { @@ -21,29 +21,3 @@ export class CustomerLinksResponse { links: CustomerLink[]; } -export class CustomerTheme implements Theme { - @ApiProperty() - backgroundColor: string; - @ApiProperty() - textColor: string; - @ApiProperty() - logoWhite: string; - @ApiProperty() - logoBlack: string; -} - -export class CustomerThemeResponse { - @ApiProperty() - theme: CustomerTheme; -} - -export class CustomerThemeRequest { - @ApiProperty() - backgroundColor: string; - @ApiProperty() - textColor: string; - @ApiProperty() - logoWhite: string; - @ApiProperty() - logoBlack: string; -} diff --git a/src/modules/duc/client.config.ts b/src/modules/duc/client.config.ts index 25ce28b..4cf4124 100644 --- a/src/modules/duc/client.config.ts +++ b/src/modules/duc/client.config.ts @@ -29,6 +29,8 @@ export class DucClient { objects: true, arrays: true, }, + maxSendMessageLength: 15 * 1024 * 1024, // 15 MB por mensagem + maxReceiveMessageLength: 15 * 1024 * 1024, }, }; diff --git a/src/modules/theme/dtos/customers.ts b/src/modules/theme/dtos/customers.ts new file mode 100644 index 0000000..5d87b8b --- /dev/null +++ b/src/modules/theme/dtos/customers.ts @@ -0,0 +1,47 @@ +import { Link, Theme } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; + +export class CustomerLink implements Link { + @ApiProperty() + href: string; + @ApiProperty() + name: string; + @ApiProperty() + description: string; + @ApiPropertyOptional() + iconSrc: string; +} +export class CustomerLinkRequest { + @ApiProperty({ type: [CustomerLink] }) + links: CustomerLink[]; +} + +export class CustomerLinksResponse { + @ApiProperty({ type: [CustomerLink] }) + links: CustomerLink[]; +} + +export class CustomerTheme implements Theme { + @ApiProperty() + backgroundColor: string; + @ApiProperty() + textColor: string; + @ApiProperty() + logoWhite: string; + @ApiProperty() + logoBlack: string; +} + +export class CustomerThemeResponse { + @ApiProperty() + theme: CustomerTheme; +} + +export class CustomerThemeRequest { + @ApiProperty() + displayName: string; + @ApiProperty() + backgroundColor: string; + @ApiProperty() + textColor: string; +} diff --git a/src/modules/theme/theme.controller.ts b/src/modules/theme/theme.controller.ts new file mode 100644 index 0000000..f04fb7a --- /dev/null +++ b/src/modules/theme/theme.controller.ts @@ -0,0 +1,124 @@ +import { DadosferaLogger } from '@dadosfera/dadosfera-logs'; +import { + Body, + Controller, + Get, + HttpException, + HttpStatus, + Inject, + Param, + Post, + Put, + Query, + UploadedFiles, + UseFilters, + UseInterceptors, +} from '@nestjs/common'; +import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; +import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum'; +import { + Authenticated, + RequireAllPermissions, +} from 'src/decorators/authentication.decorator'; +import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter'; +import { CustomerThemeRequest, CustomerThemeResponse } from './dtos/customers'; + +import ErrorCodes from 'src/utils/errorCodes'; +import { AnyFilesInterceptor } from '@nestjs/platform-express'; +import { ThemeService } from './theme.service'; + +@ApiTags('Theme') +@Controller('customers') +@UseFilters(GrpcToHttpExceptionFilter) +export class ThemeController { + logger: DadosferaLogger; + + constructor( + @Inject(DadosferaLogger) + dadosferaLogger: DadosferaLogger, + private themeService: ThemeService, + ) { + this.logger = dadosferaLogger.logger; + } + + + @Post('/:id/theme') + @Authenticated() + @RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN) + @ApiOkResponse({ type: CustomerThemeResponse }) + @UseInterceptors(AnyFilesInterceptor()) + async saveCustomertheme( + @Param('id') id: string, + @Body() data: CustomerThemeRequest, + @UploadedFiles() files: Array + ) { + + this.logger.info('saveCustomertheme' + JSON.stringify({ + id, + })); + + const logoWhite = files.find(file => file.fieldname === 'logoWhite'); + const logoBlack = files.find(file => file.fieldname === 'logoBlack'); + console.log(logoWhite) + + this.validFileSize(logoWhite); + this.validFileSize(logoBlack); + this.validMimeType(logoWhite); + this.validMimeType(logoBlack); + + try { + const theme = await this.themeService.createThemeByCustomer(id, { + ...data, + logoWhite, + logoBlack + }); + this.logger.info('saveCustomertheme' + JSON.stringify(theme)); + return { theme: theme }; + } catch (err) { + if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND) { + this.logger.error('Error - saveCustomertheme - Expect CUSTOMER.NOT_FOUND'); + throw new HttpException(err.details, HttpStatus.NOT_FOUND); + } else { + this.logger.error('Error - saveCustomertheme Unknown Error:' + err?.message); + return { theme: null }; + }; + } + } + + private validFileSize(file: Express.Multer.File) { + const maxFileSize = 10 * 1024 * 1024; // 10MB + + if (file && file.size > maxFileSize) { + throw new HttpException(`O Arquivo ${file.filename} possui mais de 10MB`, HttpStatus.BAD_REQUEST); + } + } + + private validMimeType(file: Express.Multer.File) { + const mimeTypesValid = ['image/jpeg', 'image/jpg', 'image/png']; + + if (file && !mimeTypesValid.includes(file.mimetype)) { + throw new HttpException(`O Arquivo ${file.fieldname} deve ser jpeg, jpg ou png`, HttpStatus.BAD_REQUEST); + } + } + + @Get('/:id/theme') + @ApiOkResponse({ type: CustomerThemeResponse }) + async getCustomerTheme(@Param('id') id: string) { + this.logger.info('getCustomerTheme with id' + id); + + try { + const data = await this.themeService.getThemeByCustomer(id); + this.logger.info('Success - getCustomerTheme with id'+ id); + return data; + }catch (err) { + if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND) { + this.logger.error('Error - getCustomerTheme - Expect CUSTOMER.NOT_FOUND'); + throw new HttpException(err.details, HttpStatus.NOT_FOUND); + } else { + this.logger.error('Error - getCustomerTheme Unknown Error:' + err?.message); + return { theme: null }; + }; + } + } + +} diff --git a/src/modules/theme/theme.module.ts b/src/modules/theme/theme.module.ts new file mode 100644 index 0000000..4fc3d53 --- /dev/null +++ b/src/modules/theme/theme.module.ts @@ -0,0 +1,20 @@ +import { Module } from '@nestjs/common'; +import { DadosferaLogger } from '@dadosfera/dadosfera-logs'; +import { ClientsModule } from '@nestjs/microservices'; +import { ThemeController } from './theme.controller'; +import { ThemeService } from './theme.service'; +import { DucClient } from '../duc/client.config'; + +const ducClient = new DucClient(); + +@Module({ + imports: [ + ClientsModule.register([ + ducClient.providerOptions, + ]), + ], + controllers: [ThemeController], + providers: [ThemeService, DadosferaLogger], + exports: [ThemeService], +}) +export class ThemeModule {} diff --git a/src/modules/theme/theme.service.ts b/src/modules/theme/theme.service.ts new file mode 100644 index 0000000..4c5f33f --- /dev/null +++ b/src/modules/theme/theme.service.ts @@ -0,0 +1,133 @@ +import { + OnModuleInit, + Inject, + Injectable, + HttpException, + HttpStatus, + InternalServerErrorException, +} from '@nestjs/common'; + +import { firstValueFrom, lastValueFrom, ReplaySubject } from 'rxjs'; +import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities'; +import { DucClient } from '../duc/client.config'; +import { ClientGrpc } from '@nestjs/microservices'; +import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc'; +import { CustomerUpdateRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages'; +import { ThemeProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service'; +import { ThemeRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages'; +import { CustomerThemeRequest, CustomerThemeResponse } from './dtos/customers'; +import DadosferaLogger from '@dadosfera/dadosfera-logs'; +import { resolve } from 'path'; +import { Readable } from 'stream'; + +type Files = { + logoWhite: Express.Multer.File, + logoBlack: Express.Multer.File, +} + +// This function will accept any string, which may result in a bug. +@Injectable() +export class ThemeService implements OnModuleInit { + private themeService: ThemeProtoService; + private logger: DadosferaLogger; + + constructor( + @Inject(DucClient.name) private readonly grpcClient: ClientGrpc, + @Inject(DadosferaLogger) + dadosferaLogger: DadosferaLogger, + ) { + this.logger = dadosferaLogger.logger; + } + + onModuleInit() { + this.themeService = this.grpcClient.getService( + ProtoServices.ThemeProtoService, + ); + } + + async createThemeByCustomer(id: string, theme: CustomerThemeRequest & Files) { + if (!id) { + this.logger.error('Error - saveCustomertheme - not found id:' + id); + throw new HttpException(null, HttpStatus.BAD_REQUEST); + } + + const customerThemeRequest$ = new ReplaySubject(); + + customerThemeRequest$.next({ + customerId: id, + displayName: theme.displayName, + backgroundColor: theme.backgroundColor, + textColor: theme.textColor, + isMetadata: true, + filename: '', + chunk: Buffer.alloc(0) + }) + + if(theme.logoBlack) { + await this.sendFile(theme.logoBlack, customerThemeRequest$); + } + + if(theme.logoWhite) { + await this.sendFile(theme.logoWhite, customerThemeRequest$); + } + customerThemeRequest$.complete(); + + const stream = this.themeService.CustomerCreateTheme(customerThemeRequest$); + + return lastValueFrom(stream); + } + + async getThemeByCustomer(id: string): Promise { + if (!id) { + this.logger.error('Error - getCustomerTheme - not found id:' + id); + throw new HttpException(null, HttpStatus.BAD_REQUEST); + } + + const { theme } = await firstValueFrom( + this.themeService.CustomerGetTheme({ + id + }), + ); + + return { + theme + } + } + + private async sendFile(file: Express.Multer.File, stream$: ReplaySubject) { + const bufferStream = new Readable({ + highWaterMark: 1024 * 1024, // 1 MB por chunk + read() {} + }); + bufferStream.push(file.buffer); + bufferStream.push(null); + + return new Promise((resolve, reject) => { + bufferStream.on('data', (chunk) => { + console.log('enviando chunk', file.fieldname) + const mimetype = file.mimetype.split('/')[1]; // example image/jpeg + const filename = file.fieldname.concat(".", mimetype); + stream$.next({ + customerId: '', + displayName: '', + backgroundColor: '', + textColor: '', + isMetadata: false, + filename: filename, + chunk: chunk + }); + }); + + bufferStream.on('end', () => { + console.log('terminou de enviar') + resolve(file.filename) + }); + + bufferStream.on('error', (err) => { + console.error('Erro no stream:', err); + reject(err); + }); + }); + } + +}