chore: update user fix
This commit is contained in:
@@ -2,14 +2,6 @@ import { EntityManager } from "@mikro-orm/postgresql";
|
||||
import { BadRequestException, Injectable, Logger, NotFoundException } from "@nestjs/common";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import {
|
||||
DANAK_IMAPS_ENCRYPTION,
|
||||
DANAK_IMAPS_PORT,
|
||||
DANAK_IMAPS_SERVER,
|
||||
DANAK_SMTPS_ENCRYPTION,
|
||||
DANAK_SMTPS_PORT,
|
||||
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";
|
||||
@@ -106,6 +98,7 @@ export class UsersService {
|
||||
if (domain.status !== DomainStatus.VERIFIED) throw new BadRequestException(DomainMessage.NOT_VERIFIED);
|
||||
|
||||
const emailAddress = `${username}@${domain.name}`;
|
||||
const finalUserName = `${username}-${domain.name}`;
|
||||
|
||||
const existingUser = await this.userRepository.findOne({ emailAddress });
|
||||
if (existingUser) throw new BadRequestException(UserMessage.EMAIL_ADDRESS_ALREADY_EXISTS);
|
||||
@@ -120,7 +113,7 @@ export class UsersService {
|
||||
|
||||
const mailServerUser = await firstValueFrom(
|
||||
this.mailServerService.users.createUser({
|
||||
username: `${username}-${domain.name}`,
|
||||
username: finalUserName,
|
||||
password,
|
||||
address: emailAddress,
|
||||
name: displayName || username,
|
||||
@@ -132,7 +125,7 @@ export class UsersService {
|
||||
|
||||
const user = this.userRepository.create({
|
||||
title: title || displayName || username,
|
||||
userName: username,
|
||||
userName: finalUserName,
|
||||
password: hashedPassword,
|
||||
emailAddress,
|
||||
emailEnabled: true,
|
||||
@@ -182,19 +175,6 @@ export class UsersService {
|
||||
createdAt: user.createdAt,
|
||||
isActive: user.isActive,
|
||||
},
|
||||
setupInfo: {
|
||||
emailAddress: user.emailAddress!,
|
||||
imapSettings: {
|
||||
server: DANAK_IMAPS_SERVER,
|
||||
port: DANAK_IMAPS_PORT,
|
||||
encryption: DANAK_IMAPS_ENCRYPTION,
|
||||
},
|
||||
smtpSettings: {
|
||||
server: DANAK_SMTPS_SERVER,
|
||||
port: DANAK_SMTPS_PORT,
|
||||
encryption: DANAK_SMTPS_ENCRYPTION,
|
||||
},
|
||||
},
|
||||
message: UserMessage.EMAIL_USER_CREATED_SUCCESSFULLY,
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -245,14 +225,23 @@ export class UsersService {
|
||||
async updateEmailUser(userId: string, businessId: string, updateEmailUserDto: UpdateEmailUserDto) {
|
||||
const { password, displayName, quota, aliases, title } = updateEmailUserDto;
|
||||
|
||||
const user = await this.userRepository.findOne({
|
||||
id: userId,
|
||||
business: { id: businessId },
|
||||
emailEnabled: true,
|
||||
});
|
||||
const user = await this.userRepository.findOne(
|
||||
{
|
||||
id: userId,
|
||||
business: { id: businessId },
|
||||
emailEnabled: true,
|
||||
},
|
||||
{ populate: ["business"] },
|
||||
);
|
||||
|
||||
if (!user) throw new NotFoundException(UserMessage.EMAIL_USER_NOT_FOUND);
|
||||
|
||||
// Validate business quota if quota is being updated
|
||||
if (quota) {
|
||||
const currentQuota = user.emailQuota || 0;
|
||||
this.validateBusinessQuotaAvailability(user.business, currentQuota, quota);
|
||||
}
|
||||
|
||||
try {
|
||||
const updateData: UpdateUserDto = {};
|
||||
|
||||
@@ -299,7 +288,13 @@ export class UsersService {
|
||||
|
||||
if (displayName) user.displayName = displayName;
|
||||
|
||||
if (quota) user.emailQuota = quota;
|
||||
if (quota) {
|
||||
const currentQuota = user.emailQuota || 0;
|
||||
user.emailQuota = quota;
|
||||
|
||||
// Update business quota tracking
|
||||
this.updateBusinessQuotaTracking(user.business, currentQuota, quota);
|
||||
}
|
||||
|
||||
if (title) user.title = title;
|
||||
|
||||
@@ -330,14 +325,21 @@ export class UsersService {
|
||||
* Update email user quota
|
||||
*/
|
||||
async updateEmailUserQuota(userId: string, businessId: string, newQuota: number) {
|
||||
const user = await this.userRepository.findOne({
|
||||
id: userId,
|
||||
business: { id: businessId },
|
||||
emailEnabled: true,
|
||||
});
|
||||
const user = await this.userRepository.findOne(
|
||||
{
|
||||
id: userId,
|
||||
business: { id: businessId },
|
||||
emailEnabled: true,
|
||||
},
|
||||
{ populate: ["business"] },
|
||||
);
|
||||
|
||||
if (!user) throw new NotFoundException(UserMessage.EMAIL_USER_NOT_FOUND);
|
||||
|
||||
// Validate business quota before updating
|
||||
const currentQuota = user.emailQuota || 0;
|
||||
this.validateBusinessQuotaAvailability(user.business, currentQuota, newQuota);
|
||||
|
||||
try {
|
||||
if (user.wildduckUserId) {
|
||||
await firstValueFrom(
|
||||
@@ -348,7 +350,11 @@ export class UsersService {
|
||||
}
|
||||
|
||||
user.emailQuota = newQuota;
|
||||
await this.em.persistAndFlush(user);
|
||||
|
||||
// Update business quota tracking
|
||||
this.updateBusinessQuotaTracking(user.business, currentQuota, newQuota);
|
||||
|
||||
await this.em.persistAndFlush([user, user.business]);
|
||||
|
||||
this.logger.log(`Email user quota updated: ${user.emailAddress} to ${newQuota} bytes`);
|
||||
|
||||
@@ -373,4 +379,33 @@ export class UsersService {
|
||||
status: user.isActive,
|
||||
};
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
private validateBusinessQuotaAvailability(business: Business, currentUserQuota: number, newUserQuota: number): void {
|
||||
// Prevent quota downgrade - users can only upgrade their quota
|
||||
if (newUserQuota < currentUserQuota) {
|
||||
throw new BadRequestException(BusinessMessage.QUOTA_DOWNGRADE_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
const quotaDifference = newUserQuota - currentUserQuota;
|
||||
|
||||
if (quotaDifference > 0) {
|
||||
const remainingQuota = Number(business.remainingQuota) || 0;
|
||||
|
||||
if (quotaDifference > remainingQuota) {
|
||||
throw new BadRequestException(BusinessMessage.INSUFFICIENT_QUOTA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================
|
||||
|
||||
private updateBusinessQuotaTracking(business: Business, currentUserQuota: number, newUserQuota: number): void {
|
||||
const quotaDifference = newUserQuota - currentUserQuota;
|
||||
|
||||
business.usedQuota = Number(business.usedQuota) + quotaDifference;
|
||||
business.remainingQuota = Number(business.quota) - Number(business.usedQuota);
|
||||
|
||||
this.logger.log(`Updated business quota for ${business.name}: used=${business.usedQuota}, remaining=${business.remainingQuota}`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user