diff --git a/src/app.module.ts b/src/app.module.ts index 50555dc..d0bfb0c 100755 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -44,6 +44,7 @@ import { UsersModule } from "./modules/users/users.module"; import { WalletsModule } from "./modules/wallets/wallets.module"; import { DkalaModule } from "./modules/dkala/dkala.module"; import { DpageModule } from './modules/dpage/dpage.module'; +import { DmailModule } from './modules/dmail/dmail.module'; @Module({ imports: [ // TelegrafModule.forRootAsync(telegrafConfig()), @@ -90,7 +91,8 @@ import { DpageModule } from './modules/dpage/dpage.module'; AccessLogsModule, DmenuModule, DkalaModule, - DpageModule + DpageModule, + DmailModule ], controllers: [], }) diff --git a/src/configs/dmail.config.ts b/src/configs/dmail.config.ts new file mode 100644 index 0000000..6e855bd --- /dev/null +++ b/src/configs/dmail.config.ts @@ -0,0 +1,20 @@ +import { ConfigService } from "@nestjs/config"; + +export function dmailConfig() { + return { + inject: [ConfigService], + useFactory: async (configService: ConfigService) => { + return { + baseUrl: configService.get("DMAIL_BACKEND_URL")??'https://dmail-api.danakcorp.com', + username: configService.get("DMAIL_USERNAME")??'danak@dsc.com', + password: configService.get("DMAIL_PASSWORD")??'DsCdAnAk?@ABC', + }; + }, + }; +} + +export interface IDMailConfig { + baseUrl: string; + username: string; + password: string; +} diff --git a/src/modules/dmail/constants/index.ts b/src/modules/dmail/constants/index.ts new file mode 100644 index 0000000..89d361a --- /dev/null +++ b/src/modules/dmail/constants/index.ts @@ -0,0 +1 @@ +export const DMAIL_CONFIG = "DMAIL_CONFIG"; diff --git a/src/modules/dmail/dmail.controller.ts b/src/modules/dmail/dmail.controller.ts new file mode 100644 index 0000000..c14a98e --- /dev/null +++ b/src/modules/dmail/dmail.controller.ts @@ -0,0 +1,34 @@ +import { Controller, Get, Body, Patch, Param, Query } from '@nestjs/common'; +import { DmailService } from './dmail.service'; +import { UpdateDmailAciveStatusDto } from './dto/update-dmail.dto'; +import { FindBusinessesDto } from './dto/find-businesses.dto'; +import { AuthGuards } from '../../common/decorators/auth-guard.decorator'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { AdminRoute } from '../../common/decorators/admin.decorator'; + +@Controller('dmail') +@ApiTags('d-mail') +@AuthGuards() +@ApiBearerAuth() +export class DmailController { + constructor(private readonly dmailService: DmailService) { } + + @Get() + @AdminRoute() + findAll(@Query() query: FindBusinessesDto) { + return this.dmailService.findAllBusinesses(query) + } + + // @Get(':id') + // @AdminRoute() + // findOne(@Param('id') id: string) { + // return this.dmailService.findOne(+id); + // } + + @Patch(':id/active') + @AdminRoute() + update(@Param('id') id: string, @Body() updateDmailDto: UpdateDmailAciveStatusDto) { + return this.dmailService.updateDMailActiveStatus(id, updateDmailDto.isActive); + } + +} diff --git a/src/modules/dmail/dmail.module.ts b/src/modules/dmail/dmail.module.ts new file mode 100644 index 0000000..a909d15 --- /dev/null +++ b/src/modules/dmail/dmail.module.ts @@ -0,0 +1,18 @@ +import { Module } from '@nestjs/common'; +import { DmailService } from './dmail.service'; +import { DmailController } from './dmail.controller'; +import { DMAIL_CONFIG } from './constants'; +import { dmailConfig } from '../../configs/dmail.config'; + +@Module({ + controllers: [DmailController], + providers: [DmailService, + { + provide: DMAIL_CONFIG, + useFactory: dmailConfig().useFactory, + inject: dmailConfig().inject, + }, + ], + exports:[DmailService] +}) +export class DmailModule { } diff --git a/src/modules/dmail/dmail.service.ts b/src/modules/dmail/dmail.service.ts new file mode 100644 index 0000000..d21132b --- /dev/null +++ b/src/modules/dmail/dmail.service.ts @@ -0,0 +1,91 @@ +import { HttpException, Injectable, Logger } from "@nestjs/common"; +import { HttpService } from "@nestjs/axios"; +import { Inject } from "@nestjs/common"; +import { AxiosError } from "axios"; +import { catchError, firstValueFrom, throwError } from "rxjs"; +import { IDMailConfig } from "../../configs/dmail.config"; +import { FindBusinessesDto } from "./dto/find-businesses.dto"; +import { DMAIL_CONFIG } from "./constants"; + +@Injectable() +export class DmailService { + private readonly logger = new Logger(DmailService.name); + constructor( + @Inject(DMAIL_CONFIG) private readonly config: IDMailConfig, + private readonly httpService: HttpService, + ) { } + + private getHeaders(): Record { + const credentials = Buffer.from(`${this.config.username}:${this.config.password}`).toString("base64"); + return { + "Content-Type": "application/json", + Authorization: `Basic ${credentials}`, + }; + } + + async findAllBusinesses(dto: FindBusinessesDto) { + + try { + // 2. Login with userSubscriptionId + const { data } = await firstValueFrom( + this.httpService + .get(`${this.config.baseUrl}/business/list`, + { + params: dto, + headers: this.getHeaders(), + }) + .pipe( + catchError((err: AxiosError) => { + this.logger.error(`Failed to get list of dmail businesses: ${err.message}`, err.stack); + return throwError(() => err); + }), + ), + ); + return data; + } catch (error: unknown) { + if (error instanceof AxiosError && error.response) { + this.logger.error(`External API error response:`, error.response.data); + const errorResponse = { + ...error.response.data, + message: error.response.data.error?.message || error.message, + }; + throw new HttpException(errorResponse, error.response.status); + } + this.logger.error(`Error performing direct login: ${error instanceof Error ? error.message : "Unknown error"}`); + throw error; + } + + } + + async updateDMailActiveStatus(id: string, isActive: boolean) { + try { + const { data } = await firstValueFrom( + this.httpService + .patch(`${this.config.baseUrl}/business/${id}/active`, { isActive }, + { + headers: this.getHeaders(), + }) + .pipe( + catchError((err: AxiosError) => { + this.logger.error(`Failed to perform update business account: ${err.message}`, err.stack); + return throwError(() => err); + }), + ), + ); + return data; + } catch (error: unknown) { + if (error instanceof AxiosError && error.response) { + this.logger.error(`External API error response:`, error.response.data); + const errorResponse = { + ...error.response.data, + message: error.response.data.error?.message || error.message, + }; + throw new HttpException(errorResponse, error.response.status); + } + this.logger.error(`Error performing setup account: ${error instanceof Error ? error.message : "Unknown error"}`); + throw error; + } + } + + +} diff --git a/src/modules/dmail/dto/create-dmail.dto.ts b/src/modules/dmail/dto/create-dmail.dto.ts new file mode 100644 index 0000000..a650eb4 --- /dev/null +++ b/src/modules/dmail/dto/create-dmail.dto.ts @@ -0,0 +1 @@ +export class CreateDmailDto {} diff --git a/src/modules/dmail/dto/find-businesses.dto.ts b/src/modules/dmail/dto/find-businesses.dto.ts new file mode 100644 index 0000000..9b3a577 --- /dev/null +++ b/src/modules/dmail/dto/find-businesses.dto.ts @@ -0,0 +1,35 @@ +import { IsOptional, IsNumber, IsString, IsIn, IsBoolean } from 'class-validator'; +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; + +export class FindBusinessesDto { + @IsOptional() + @IsNumber() + @Type(() => Number) + @ApiPropertyOptional({ example: 1 }) + page?: number; + + @IsOptional() + @IsNumber() + @Type(() => Number) + @ApiPropertyOptional({ example: 10 }) + limit?: number; + + + @IsOptional() + @IsString() + @ApiPropertyOptional({ example: 'createdAt' }) + orderBy?: string; + + @IsOptional() + @IsIn(['asc', 'desc']) + @ApiPropertyOptional({ example: 'desc' }) + order?: 'asc' | 'desc'; + + + @IsOptional() + @IsBoolean() + @Type(() => Boolean) + @ApiPropertyOptional({ example: true }) + isActive?: boolean; +} diff --git a/src/modules/dmail/dto/update-dmail.dto.ts b/src/modules/dmail/dto/update-dmail.dto.ts new file mode 100644 index 0000000..0bfcee4 --- /dev/null +++ b/src/modules/dmail/dto/update-dmail.dto.ts @@ -0,0 +1,10 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsBoolean, IsNotEmpty } from "class-validator"; + + +export class UpdateDmailAciveStatusDto { + @IsNotEmpty() + @IsBoolean() + @ApiProperty() + isActive: boolean; +}