171 lines
5.0 KiB
TypeScript
171 lines
5.0 KiB
TypeScript
import { Injectable, NotFoundException, Inject } from "@nestjs/common";
|
|
import { Logger } from "nestjs-pino";
|
|
import { getErrorMessage } from "@bff/core/utils/error.util";
|
|
import { WhmcsConnectionOrchestratorService } from "../connection/services/whmcs-connection-orchestrator.service";
|
|
import { WhmcsCacheService } from "../cache/whmcs-cache.service";
|
|
import {
|
|
WhmcsValidateLoginParams,
|
|
WhmcsAddClientParams,
|
|
WhmcsClientResponse,
|
|
} from "../types/whmcs-api.types";
|
|
import type {
|
|
WhmcsAddClientResponse,
|
|
WhmcsValidateLoginResponse,
|
|
} from "@customer-portal/domain/customer";
|
|
import {
|
|
Providers as CustomerProviders,
|
|
type Customer,
|
|
type CustomerAddress,
|
|
} from "@customer-portal/domain/customer";
|
|
|
|
@Injectable()
|
|
export class WhmcsClientService {
|
|
constructor(
|
|
private readonly connectionService: WhmcsConnectionOrchestratorService,
|
|
private readonly cacheService: WhmcsCacheService,
|
|
@Inject(Logger) private readonly logger: Logger
|
|
) {}
|
|
|
|
/**
|
|
* Validate client login credentials
|
|
*/
|
|
async validateLogin(
|
|
email: string,
|
|
password: string
|
|
): Promise<{ userId: number; passwordHash: string }> {
|
|
try {
|
|
const params: WhmcsValidateLoginParams = {
|
|
email,
|
|
password2: password,
|
|
};
|
|
|
|
const response = await this.connectionService.validateLogin(params);
|
|
|
|
this.logger.log(`Validated login for email: ${email}`);
|
|
return {
|
|
userId: response.userid,
|
|
passwordHash: response.passwordhash,
|
|
};
|
|
} catch (error) {
|
|
this.logger.error(`Failed to validate login for email: ${email}`, {
|
|
error: getErrorMessage(error),
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get client details by ID
|
|
*/
|
|
async getClientDetails(clientId: number): Promise<Customer> {
|
|
try {
|
|
// Try cache first
|
|
const cached = await this.cacheService.getClientData(clientId);
|
|
if (cached) {
|
|
this.logger.debug(`Cache hit for client: ${clientId}`);
|
|
return cached;
|
|
}
|
|
|
|
const response = await this.connectionService.getClientDetails(clientId);
|
|
|
|
if (!response || !response.client) {
|
|
this.logger.error(`WHMCS API did not return client data for client ID: ${clientId}`, {
|
|
hasResponse: !!response,
|
|
responseKeys: response ? Object.keys(response) : [],
|
|
});
|
|
throw new NotFoundException(`Client ${clientId} not found`);
|
|
}
|
|
|
|
const customer = CustomerProviders.Whmcs.transformWhmcsClientResponse(response);
|
|
|
|
await this.cacheService.setClientData(clientId, customer);
|
|
|
|
this.logger.log(`Fetched client details for client ${clientId}`);
|
|
return customer;
|
|
} catch (error) {
|
|
this.logger.error(`Failed to fetch client details for client ${clientId}`, {
|
|
error: getErrorMessage(error),
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get client details by email
|
|
*/
|
|
async getClientDetailsByEmail(email: string): Promise<Customer> {
|
|
try {
|
|
const response = await this.connectionService.getClientDetailsByEmail(email);
|
|
|
|
if (!response || !response.client) {
|
|
this.logger.error(`WHMCS API did not return client data for email: ${email}`, {
|
|
hasResponse: !!response,
|
|
responseKeys: response ? Object.keys(response) : [],
|
|
});
|
|
throw new NotFoundException(`Client with email ${email} not found`);
|
|
}
|
|
|
|
const customer = CustomerProviders.Whmcs.transformWhmcsClientResponse(response);
|
|
|
|
await this.cacheService.setClientData(customer.id, customer);
|
|
|
|
this.logger.log(`Fetched client details by email: ${email}`);
|
|
return customer;
|
|
} catch (error) {
|
|
this.logger.error(`Failed to fetch client details by email: ${email}`, {
|
|
error: getErrorMessage(error),
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update client details
|
|
*/
|
|
async updateClient(
|
|
clientId: number,
|
|
updateData: Partial<WhmcsClientResponse["client"]>
|
|
): Promise<void> {
|
|
try {
|
|
await this.connectionService.updateClient(clientId, updateData);
|
|
|
|
// Invalidate client cache after update
|
|
await this.cacheService.invalidateClientCache(clientId);
|
|
|
|
this.logger.log(`Successfully updated WHMCS client ${clientId}`);
|
|
} catch (error: unknown) {
|
|
this.logger.error(`Failed to update WHMCS client ${clientId}`, {
|
|
error: getErrorMessage(error),
|
|
updateData,
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add new client
|
|
*/
|
|
async addClient(clientData: WhmcsAddClientParams): Promise<{ clientId: number }> {
|
|
try {
|
|
const response = await this.connectionService.addClient(clientData);
|
|
|
|
this.logger.log(`Created new client: ${response.clientid}`);
|
|
return { clientId: response.clientid };
|
|
} catch (error) {
|
|
this.logger.error(`Failed to create new client`, {
|
|
error: getErrorMessage(error),
|
|
email: clientData.email,
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invalidate cache for a user
|
|
*/
|
|
async invalidateUserCache(userId: string): Promise<void> {
|
|
await this.cacheService.invalidateUserCache(userId);
|
|
this.logger.log(`Invalidated cache for user ${userId}`);
|
|
}
|
|
}
|