diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index efc7003..b18106e 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -62,7 +62,7 @@ export const enum AuthMessage { TOKEN_EXPIRED_OR_INVALID = "توکن منقضی شده یا نامعتبر است", ACCESS_DENIED = "دسترسی شما محدود شده است", USER_ACCOUNT_INACTIVE = "حساب کاربری شما غیر فعال است", - TOKEN_MISSED_OR_EXPIRED = "TOKEN_MISSED_OR_EXPIRED", + TOKEN_MISSED_OR_EXPIRED = "توکن مفقود یا منقضی شده است", } export const enum UserMessage { @@ -102,6 +102,10 @@ export const enum UserMessage { STATUS_UPDATED = "وضعیت کاربر با موفقیت تغییر کرد", TEMPLATE_UUID = "شناسه قالب باید یک یو یو آی دی باشد", TEMPLATE_NOT_EMPTY = "شناسه قالب نمیتواند خالی باشد", + ALIASES_EMAIL = "آدرس ایمیل الیاس باید معتبر باشد", + FORWARDERS_EMAIL_VALID = "آدرس ایمیل فوروارد باید معتبر باشد", + FORWARDERS_ARRAY = "آدرس های فوروارد باید یک آرایه باشد", + FORWARDERS_STRING = "آدرس های فوروارد باید یک رشته باشد", } export const enum CommonMessage { @@ -425,7 +429,7 @@ export const enum DomainMessage { export const enum MailServerMessage { FAILED_TO_CREATE_ACCOUNT = "خطا در ایجاد ایمیل", - FAILED_TO_CREATE_DKIM_KEY = "FAILED_TO_CREATE_DKIM_KEY", + FAILED_TO_CREATE_DKIM_KEY = "خطا در ایجاد کلید DKIM", } export const enum DnsRecordMessage { diff --git a/src/modules/users/DTO/create-email-user.dto.ts b/src/modules/users/DTO/create-email-user.dto.ts index 72c8ead..7f9fce3 100644 --- a/src/modules/users/DTO/create-email-user.dto.ts +++ b/src/modules/users/DTO/create-email-user.dto.ts @@ -1,6 +1,6 @@ import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; import { Transform } from "class-transformer"; -import { IsArray, IsNotEmpty, IsNumber, IsOptional, IsString, IsUUID, Matches, MinLength } from "class-validator"; +import { IsArray, IsEmail, IsNotEmpty, IsNumber, IsOptional, IsString, IsUUID, Matches, MinLength } from "class-validator"; import { UserMessage } from "../../../common/enums/message.enum"; @@ -53,4 +53,14 @@ export class CreateEmailUserDto { @IsUUID("7", { message: UserMessage.TEMPLATE_UUID }) @ApiPropertyOptional({ description: "Template ID", example: "713e5000-0000-0000-0000-000000000000" }) templateId?: string; + + @IsOptional() + @IsEmail({}, { each: true, message: UserMessage.FORWARDERS_EMAIL_VALID }) + @IsArray({ message: UserMessage.FORWARDERS_ARRAY }) + @IsString({ each: true, message: UserMessage.FORWARDERS_STRING }) + @ApiPropertyOptional({ + description: "Array of email addresses to forward all messages to", + example: ["forward1@example.com", "forward2@example.com"], + }) + forwarders?: string[]; } diff --git a/src/modules/users/DTO/update-email-user.dto.ts b/src/modules/users/DTO/update-email-user.dto.ts index 5351933..b1d64a3 100644 --- a/src/modules/users/DTO/update-email-user.dto.ts +++ b/src/modules/users/DTO/update-email-user.dto.ts @@ -1,6 +1,6 @@ import { ApiPropertyOptional } from "@nestjs/swagger"; import { Transform } from "class-transformer"; -import { IsArray, IsNotEmpty, IsNumber, IsOptional, IsString, IsUUID, Matches, MinLength } from "class-validator"; +import { IsArray, IsEmail, IsNotEmpty, IsNumber, IsOptional, IsString, IsUUID, Matches, MinLength } from "class-validator"; import { UserMessage } from "../../../common/enums/message.enum"; @@ -44,4 +44,14 @@ export class UpdateEmailUserDto { @IsUUID("7", { message: UserMessage.TEMPLATE_UUID }) @ApiPropertyOptional({ description: "Template ID", example: "713e5000-0000-0000-0000-000000000000" }) templateId?: string; + + @IsOptional() + @IsEmail({}, { each: true, message: UserMessage.FORWARDERS_EMAIL_VALID }) + @IsArray({ message: UserMessage.FORWARDERS_ARRAY }) + @IsString({ each: true, message: UserMessage.FORWARDERS_STRING }) + @ApiPropertyOptional({ + description: "Array of email addresses to forward all messages to", + example: ["forward1@example.com", "forward2@example.com"], + }) + forwarders?: string[]; } diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index 0d00cfe..fc440a1 100644 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -42,6 +42,9 @@ export class User extends BaseEntity { @Property({ type: "timestamptz", nullable: true }) lastQuotaSync?: Date; + @Property({ type: "json", nullable: true }) + forwarders?: string[]; + @Property({ default: true, nullable: false }) isActive: boolean & Opt; diff --git a/src/modules/users/services/users.service.ts b/src/modules/users/services/users.service.ts index 7756ecc..8f398cf 100644 --- a/src/modules/users/services/users.service.ts +++ b/src/modules/users/services/users.service.ts @@ -71,6 +71,7 @@ export class UsersService { remainingInGB: Math.round(Number(user.emailQuota - user.emailQuotaUsed) / (1024 * 1024 * 1024)), usagePercentage: Math.round((Number(user.emailQuotaUsed) / Number(user.emailQuota)) * 100), }, + forwarders: user.forwarders || [], }; } /*******************************/ @@ -83,7 +84,7 @@ export class UsersService { /*******************************/ async createEmailUser(createEmailUserDto: CreateEmailUserDto, businessId: string) { - const { username, password, domainId, displayName, quota, aliases, title, templateId } = createEmailUserDto; + const { username, password, domainId, displayName, quota, aliases, title, templateId, forwarders } = createEmailUserDto; const business = await this.em.findOne(Business, { id: businessId }); if (!business) throw new BadRequestException(BusinessMessage.NOT_FOUND); @@ -122,6 +123,7 @@ export class UsersService { address: emailAddress, name: displayName || username, quota: userQuota, + targets: forwarders || [], }), ); @@ -140,6 +142,7 @@ export class UsersService { business, domain, role: userRole, + forwarders: forwarders || [], }); // Update business quota after successful user creation @@ -189,6 +192,7 @@ export class UsersService { emailQuota: user.emailQuota!, emailEnabled: user.emailEnabled, domain: domain.name, + forwarders: user.forwarders || [], createdAt: user.createdAt, isActive: user.isActive, }, @@ -245,7 +249,7 @@ export class UsersService { /*******************************/ async updateEmailUser(userId: string, businessId: string, updateEmailUserDto: UpdateEmailUserDto) { - const { password, displayName, quota, aliases, title, templateId } = updateEmailUserDto; + const { password, displayName, quota, aliases, title, templateId, forwarders } = updateEmailUserDto; const user = await this.userRepository.findOne( { @@ -283,6 +287,11 @@ export class UsersService { if (quota) updateData.quota = quota; + if (forwarders !== undefined) { + updateData.forward = forwarders; + user.forwarders = forwarders; + } + if (Object.keys(updateData).length > 0) { await firstValueFrom(this.mailServerService.users.updateUser(user.wildduckUserId!, updateData)); } @@ -347,6 +356,7 @@ export class UsersService { title: user.title, emailQuota: user.emailQuota!, emailEnabled: user.emailEnabled, + forwarders: user.forwarders || [], isActive: user.isActive, updatedAt: user.updatedAt, },