import { RoleData } from "./role.entity"; import { PermissionData } from "./permission.entity"; import crypto from 'crypto'; export class UserData { private constructor( public readonly id: string, public authentikId: string | null, public username: string, public email: string, public roles: RoleData[], public permissions: PermissionData[], public isActive: boolean, public deletedAt: Date | null, public lastSeenAt: Date | null, public storageQuota: number, public storageUsed: number, ) {} //#region Create static create(data: { username: string; email: string; authentikId?: string | null; storageQuota?: number; storageUsed?: number; }): UserData { const quota = data.storageQuota !== undefined ? data.storageQuota : 10737418240; // 10 GB const used = data.storageUsed !== undefined ? data.storageUsed : 0; return new UserData( crypto.randomUUID(), data.authentikId || null, data.username, data.email, [], [], true, null, null, quota, used, ); } //#endregion //#region Read hasRole(roleId: string) : boolean { return this.roles.some(x => x.id.toLowerCase() === roleId.toLowerCase()) } assignRole(roleData : RoleData) : void { if (this.hasRole(roleData.id)) throw new Error("Role Sudah dimiliki."); this.roles.push(roleData); } hasPermissions(permissionId : string) : boolean { return this.permissions.some(x => x.id.toLowerCase() === permissionId.toLowerCase()) } hasPermission(permission: string) : boolean { const byPerm = this.permissions.some(x => x.id.toLowerCase() === permission.toLowerCase() || x.name.toLowerCase() === permission.toLowerCase()); if (byPerm) return true; // check roles return this.roles.some(r => r.permissions.some(p => p.id.toLowerCase() === permission.toLowerCase() || p.name.toLowerCase() === permission.toLowerCase())); } assignPermission(permissionData : PermissionData) : void { if (this.hasPermissions(permissionData.id)) throw new Error("Permission sudah dimiliki.") this.permissions.push(permissionData); } //#endregion //#region Update changeEmail(email: string) { this.email = email; } changeUsername(username: string) { this.username = username; } touchLastSeen() { this.lastSeenAt = new Date(); } enable() { this.isActive = true; } disable() { this.isActive = false; } //#endregion //#region Delete softDelete() { this.deletedAt = new Date(); this.isActive = false; } restoreInstance() { this.deletedAt = null; } //#endregion public static restore(props: { id: string; authentikId?: string | null; username: string; email: string; roles?: RoleData[]; permissions?: PermissionData[]; isActive?: boolean; deletedAt?: Date | null; lastSeenAt?: Date | null; storageQuota?: number | null; storageUsed?: number | null; }): UserData { return new UserData( props.id, props.authentikId || null, props.username, props.email, props.roles || [], props.permissions || [], props.isActive !== undefined ? props.isActive : true, props.deletedAt || null, props.lastSeenAt || null, props.storageQuota !== undefined && props.storageQuota !== null ? props.storageQuota : 10737418240, props.storageUsed !== undefined && props.storageUsed !== null ? props.storageUsed : 0, ); } removeRole(roleId: string) { const idx = this.roles.findIndex(r => r.id.toLowerCase() === roleId.toLowerCase()); if (idx === -1) throw new Error('Role tidak ditemukan pada user.'); this.roles.splice(idx, 1); } removePermission(permissionId: string) { const idx = this.permissions.findIndex(p => p.id.toLowerCase() === permissionId.toLowerCase()); if (idx === -1) throw new Error('Permission tidak ditemukan pada user.'); this.permissions.splice(idx, 1); } // Storage helpers setStorageQuota(bytes: number) { if (bytes < 0) throw new Error('storageQuota must be >= 0'); if (this.storageUsed > bytes) throw new Error('storageQuota cannot be less than storageUsed'); this.storageQuota = bytes; } setStorageUsed(bytes: number) { if (bytes < 0) throw new Error('storageUsed must be >= 0'); if (bytes > this.storageQuota) throw new Error('storageUsed cannot exceed storageQuota'); this.storageUsed = bytes; } // Response helper for API toResponse() { const remaining = this.storageQuota - this.storageUsed; const usagePercentage = this.storageQuota > 0 ? Math.round((this.storageUsed / this.storageQuota) * 100) : 0; return { id: this.id, authentikId: this.authentikId, username: this.username, email: this.email, roles: this.roles, permissions: this.permissions, isActive: this.isActive, deletedAt: this.deletedAt, lastSeenAt: this.lastSeenAt, storage: { quota: this.storageQuota, used: this.storageUsed, remaining, usagePercentage, }, }; } }