chore: add email and mailbox module
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import { EntityManager } from "@mikro-orm/core";
|
||||
import { Injectable, Logger } from "@nestjs/common";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { MailServerService } from "../../mail-server/services/mail-server.service";
|
||||
import { Role } from "../../users/entities/role.entity";
|
||||
import { User } from "../../users/entities/user.entity";
|
||||
import { RoleEnum } from "../../users/enums/role.enum";
|
||||
import { PasswordService } from "../../utils/services/password.service";
|
||||
import { Domain } from "../entities/domain.entity";
|
||||
|
||||
@Injectable()
|
||||
export class DomainAutomationService {
|
||||
private readonly logger = new Logger(DomainAutomationService.name);
|
||||
|
||||
constructor(
|
||||
private readonly em: EntityManager,
|
||||
private readonly mailServerService: MailServerService,
|
||||
private readonly passwordService: PasswordService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Create info@domain.com address when domain is verified
|
||||
*/
|
||||
async createInfoAddress(domain: Domain): Promise<void> {
|
||||
const infoEmail = `info@${domain.name}`;
|
||||
|
||||
try {
|
||||
this.logger.log(`Creating info address for domain: ${domain.name}`);
|
||||
|
||||
// Check if info address already exists in local database
|
||||
const existingUser = await this.em.findOne(User, {
|
||||
emailAddress: infoEmail,
|
||||
business: { id: domain.business.id },
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
this.logger.warn(`Info address ${infoEmail} already exists, skipping creation`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate a secure password for the info account
|
||||
const password = this.generateSecurePassword();
|
||||
const hashedPassword = await this.passwordService.hashPassword(password);
|
||||
|
||||
// Get user role
|
||||
const userRole = await this.em.findOne(Role, { name: RoleEnum.USER });
|
||||
if (!userRole) {
|
||||
throw new Error("User role not found in database");
|
||||
}
|
||||
|
||||
// Create user in mail server (WildDuck)
|
||||
const mailServerUser = await firstValueFrom(
|
||||
this.mailServerService.users.createUser({
|
||||
username: "info",
|
||||
password,
|
||||
address: infoEmail,
|
||||
name: `Info - ${domain.business.name}`,
|
||||
quota: 1073741824, // 1GB default quota
|
||||
language: "fa",
|
||||
}),
|
||||
);
|
||||
|
||||
if (!mailServerUser.success) {
|
||||
throw new Error(`Failed to create mail server user`);
|
||||
}
|
||||
|
||||
// Create user in local database
|
||||
const user = this.em.create(User, {
|
||||
title: `Info - ${domain.business.name}`,
|
||||
userName: "info",
|
||||
password: hashedPassword,
|
||||
emailAddress: infoEmail,
|
||||
emailEnabled: true,
|
||||
emailQuota: 1073741824, // 1GB default
|
||||
wildduckUserId: mailServerUser.id,
|
||||
displayName: `Info - ${domain.business.name}`,
|
||||
isActive: true,
|
||||
business: domain.business,
|
||||
domain: domain,
|
||||
role: userRole,
|
||||
});
|
||||
|
||||
await this.em.persistAndFlush(user);
|
||||
|
||||
this.logger.log(`Successfully created info address: ${infoEmail} for business ${domain.business.name}`);
|
||||
this.logger.log(`Info account credentials - Email: ${infoEmail}, Password: [GENERATED]`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to create info address for domain ${domain.name}:`, error);
|
||||
// Don't throw the error to prevent domain verification from failing
|
||||
// The domain should still be marked as verified even if info address creation fails
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure password for the info account
|
||||
*/
|
||||
private generateSecurePassword(): string {
|
||||
const length = 16;
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*";
|
||||
let password = "";
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
password += charset.charAt(Math.floor(Math.random() * charset.length));
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if info address exists for a domain
|
||||
*/
|
||||
async infoAddressExists(domain: Domain): Promise<boolean> {
|
||||
const infoEmail = `info@${domain.name}`;
|
||||
const existingUser = await this.em.findOne(User, {
|
||||
emailAddress: infoEmail,
|
||||
business: { id: domain.business.id },
|
||||
});
|
||||
|
||||
return !!existingUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get info address details for a domain
|
||||
*/
|
||||
async getInfoAddressDetails(domain: Domain): Promise<User | null> {
|
||||
const infoEmail = `info@${domain.name}`;
|
||||
return this.em.findOne(
|
||||
User,
|
||||
{
|
||||
emailAddress: infoEmail,
|
||||
business: { id: domain.business.id },
|
||||
},
|
||||
{ populate: ["role", "business", "domain"] },
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user