chore: add new logic for the quota
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Collection, Entity, EntityRepositoryType, ManyToOne, OneToMany, OneToOne, Property } from "@mikro-orm/core";
|
||||
import { Collection, Entity, EntityRepositoryType, ManyToOne, OneToMany, OneToOne, Opt, Property } from "@mikro-orm/core";
|
||||
|
||||
import { RefreshToken } from "./refresh-token.entity";
|
||||
import { Role } from "./role.entity";
|
||||
@@ -19,30 +19,30 @@ export class User extends BaseEntity {
|
||||
@Property({ type: "varchar", length: 150, nullable: false })
|
||||
password!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255, nullable: true })
|
||||
emailAddress?: string; // Full email address
|
||||
@Property({ type: "varchar", length: 255, nullable: false })
|
||||
emailAddress!: string;
|
||||
|
||||
@Property({ type: "boolean", default: false })
|
||||
emailEnabled: boolean = false; // Whether email is enabled for this user
|
||||
emailEnabled: boolean & Opt;
|
||||
|
||||
@Property({ type: "bigint", nullable: true, default: 1073741824 }) // 1GB default
|
||||
emailQuota?: number; // Email quota in bytes
|
||||
@Property({ type: "bigint", nullable: false, default: 134_217_728 }) // 128MB default
|
||||
emailQuota!: number;
|
||||
|
||||
@Property({ type: "bigint", nullable: true, default: 0 })
|
||||
emailQuotaUsed?: number; // Email quota used in bytes
|
||||
@Property({ type: "bigint", nullable: false, default: 0 })
|
||||
emailQuotaUsed!: number & Opt;
|
||||
|
||||
// Email account integration fields
|
||||
@Property({ type: "varchar", length: 255, nullable: false })
|
||||
wildduckUserId: string; // WildDuck user ID
|
||||
wildduckUserId!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 255, nullable: true })
|
||||
displayName?: string; // Display name for email
|
||||
displayName?: string;
|
||||
|
||||
@Property({ type: "timestamptz", nullable: true })
|
||||
lastQuotaSync?: Date; // Last time quota was synced with WildDuck
|
||||
lastQuotaSync?: Date;
|
||||
|
||||
@Property({ default: true, nullable: false })
|
||||
isActive: boolean = true;
|
||||
isActive: boolean & Opt;
|
||||
|
||||
//=========================
|
||||
|
||||
@@ -61,7 +61,7 @@ export class User extends BaseEntity {
|
||||
business!: Business;
|
||||
|
||||
@ManyToOne(() => Domain, { deleteRule: "restrict" })
|
||||
domain!: Domain; // The domain this email user belongs to
|
||||
domain!: Domain;
|
||||
|
||||
[EntityRepositoryType]?: UserRepository;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
DANAK_SMTPS_SERVER,
|
||||
} from "../../../common/constants";
|
||||
import { BusinessMessage, DomainMessage, MailServerMessage, RoleMessage, UserMessage } from "../../../common/enums/message.enum";
|
||||
import { QUOTA_CONSTANTS } from "../../businesses/constant";
|
||||
import { Business } from "../../businesses/entities/business.entity";
|
||||
import { DomainStatus } from "../../domains/enums/domain-status.enum";
|
||||
import { DomainAutomationService } from "../../domains/services/domain-automation.service";
|
||||
@@ -75,6 +76,12 @@ export class UsersService {
|
||||
const business = await this.em.findOne(Business, { id: businessId });
|
||||
if (!business) throw new BadRequestException(BusinessMessage.NOT_FOUND);
|
||||
|
||||
// Check if business has enough quota
|
||||
const remainingQuota = business.remainingQuota || 0;
|
||||
if (remainingQuota < QUOTA_CONSTANTS.USER_QUOTA_DEDUCTION) {
|
||||
throw new BadRequestException("Insufficient quota to create user. Please upgrade your plan.");
|
||||
}
|
||||
|
||||
const domain = await this.domainsService.getDomainById(domainId, businessId);
|
||||
|
||||
if (domain.business.id !== businessId) throw new BadRequestException(DomainMessage.NOT_BELONG_TO_BUSINESS);
|
||||
@@ -92,14 +99,15 @@ export class UsersService {
|
||||
if (!userRole) throw new BadRequestException(RoleMessage.NOT_FOUND);
|
||||
|
||||
try {
|
||||
const userQuota = quota || QUOTA_CONSTANTS.DEFAULT_EMAIL_QUOTA_BYTES;
|
||||
|
||||
const mailServerUser = await firstValueFrom(
|
||||
this.mailServerService.users.createUser({
|
||||
username: `${username}-${domain.name}`,
|
||||
password,
|
||||
address: emailAddress,
|
||||
name: displayName || username,
|
||||
quota: quota || 1073741824,
|
||||
// language: "fa",
|
||||
quota: userQuota,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -111,7 +119,7 @@ export class UsersService {
|
||||
password: hashedPassword,
|
||||
emailAddress,
|
||||
emailEnabled: true,
|
||||
emailQuota: quota || 1073741824,
|
||||
emailQuota: userQuota,
|
||||
wildduckUserId: mailServerUser.id,
|
||||
displayName: displayName || username,
|
||||
isActive: true,
|
||||
@@ -120,7 +128,11 @@ export class UsersService {
|
||||
role: userRole,
|
||||
});
|
||||
|
||||
await this.em.persistAndFlush(user);
|
||||
// Update business quota after successful user creation
|
||||
business.usedQuota = business.usedQuota + QUOTA_CONSTANTS.USER_QUOTA_DEDUCTION;
|
||||
business.remainingQuota = business.quota - business.usedQuota;
|
||||
|
||||
await this.em.persistAndFlush([user, business]);
|
||||
|
||||
if (aliases && aliases.length > 0) {
|
||||
for (const alias of aliases) {
|
||||
|
||||
Reference in New Issue
Block a user