重构
This commit is contained in:
@@ -2,7 +2,6 @@ import { Injectable, BadRequestException } from '@nestjs/common';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { PrismaService } from '../../shared/prisma/prisma.service';
|
||||
import { WalletService } from '../ledger/wallet.service';
|
||||
import { AuthService } from '../identity/auth.service';
|
||||
import { SystemConfigService } from '../../shared/config/system-config.service';
|
||||
import { Decimal } from '@prisma/client/runtime/library';
|
||||
@@ -10,6 +9,8 @@ import { generateBatchNo } from '../../shared/common/decorators';
|
||||
import { assertPlayerUsername, validateInitialDepositRemark } from '@thebet365/shared';
|
||||
import { appBadRequest, appForbidden, appNotFound } from '../../shared/common/app-error';
|
||||
import { assignInviteCodeWithHistory } from '../../shared/common/invite-code.util';
|
||||
import { AgentNetworkService, type AgentScope } from './agent-network.service';
|
||||
import { AgentCreditService } from './agent-credit.service';
|
||||
|
||||
function dec(v: Decimal | null | undefined) {
|
||||
return v?.toString() ?? '0';
|
||||
@@ -23,9 +24,10 @@ function sub(a: Decimal | null | undefined, b: Decimal | null | undefined) {
|
||||
export class AgentsService {
|
||||
constructor(
|
||||
private prisma: PrismaService,
|
||||
private wallet: WalletService,
|
||||
private auth: AuthService,
|
||||
private systemConfig: SystemConfigService,
|
||||
private network: AgentNetworkService,
|
||||
private credit: AgentCreditService,
|
||||
) {}
|
||||
|
||||
async getMaxAgentLevel(): Promise<number> {
|
||||
@@ -39,52 +41,7 @@ export class AgentsService {
|
||||
}
|
||||
|
||||
private async buildAgentAncestorChainMap(parentAgentIds: (bigint | null | undefined)[]) {
|
||||
const cache = new Map<string, { username: string; parentAgentId: bigint | null }>();
|
||||
const pending = new Set<bigint>();
|
||||
|
||||
for (const id of parentAgentIds) {
|
||||
if (id) pending.add(id);
|
||||
}
|
||||
|
||||
while (pending.size > 0) {
|
||||
const batch = [...pending];
|
||||
pending.clear();
|
||||
const profiles = await this.prisma.agentProfile.findMany({
|
||||
where: { userId: { in: batch } },
|
||||
select: {
|
||||
userId: true,
|
||||
parentAgentId: true,
|
||||
user: { select: { username: true } },
|
||||
},
|
||||
});
|
||||
for (const profile of profiles) {
|
||||
cache.set(profile.userId.toString(), {
|
||||
username: profile.user.username,
|
||||
parentAgentId: profile.parentAgentId,
|
||||
});
|
||||
if (profile.parentAgentId && !cache.has(profile.parentAgentId.toString())) {
|
||||
pending.add(profile.parentAgentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const build = (startId: bigint | null | undefined): string[] => {
|
||||
const chain: string[] = [];
|
||||
let cur = startId ?? null;
|
||||
while (cur) {
|
||||
const hit = cache.get(cur.toString());
|
||||
if (!hit) break;
|
||||
chain.unshift(hit.username);
|
||||
cur = hit.parentAgentId;
|
||||
}
|
||||
return chain;
|
||||
};
|
||||
|
||||
const map = new Map<string, string[]>();
|
||||
for (const id of parentAgentIds) {
|
||||
if (id) map.set(id.toString(), build(id));
|
||||
}
|
||||
return map;
|
||||
return this.network.buildAgentAncestorChainMap(parentAgentIds);
|
||||
}
|
||||
|
||||
private async agentCashbackRateMap(agentUserIds: bigint[]): Promise<Map<string, string>> {
|
||||
@@ -142,100 +99,23 @@ export class AgentsService {
|
||||
parentAgentIds: (bigint | null | undefined)[],
|
||||
rootAgentId: bigint,
|
||||
) {
|
||||
const cache = new Map<string, { username: string; parentAgentId: bigint | null }>();
|
||||
const pending = new Set<bigint>();
|
||||
const rootKey = rootAgentId.toString();
|
||||
|
||||
for (const id of parentAgentIds) {
|
||||
if (id) pending.add(id);
|
||||
}
|
||||
pending.add(rootAgentId);
|
||||
|
||||
while (pending.size > 0) {
|
||||
const batch = [...pending];
|
||||
pending.clear();
|
||||
const profiles = await this.prisma.agentProfile.findMany({
|
||||
where: { userId: { in: batch } },
|
||||
select: {
|
||||
userId: true,
|
||||
parentAgentId: true,
|
||||
user: { select: { username: true } },
|
||||
},
|
||||
});
|
||||
for (const profile of profiles) {
|
||||
cache.set(profile.userId.toString(), {
|
||||
username: profile.user.username,
|
||||
parentAgentId: profile.parentAgentId,
|
||||
});
|
||||
if (
|
||||
profile.parentAgentId &&
|
||||
profile.parentAgentId.toString() !== rootKey &&
|
||||
!cache.has(profile.parentAgentId.toString())
|
||||
) {
|
||||
pending.add(profile.parentAgentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const build = (startId: bigint | null | undefined): string[] => {
|
||||
if (!startId) return [];
|
||||
const chain: string[] = [];
|
||||
let cur: bigint | null = startId;
|
||||
let reachedRoot = false;
|
||||
while (cur) {
|
||||
const hit = cache.get(cur.toString());
|
||||
if (!hit) return [];
|
||||
chain.unshift(hit.username);
|
||||
if (cur.toString() === rootKey) {
|
||||
reachedRoot = true;
|
||||
break;
|
||||
}
|
||||
cur = hit.parentAgentId;
|
||||
}
|
||||
return reachedRoot ? chain : [];
|
||||
};
|
||||
|
||||
const map = new Map<string, string[]>();
|
||||
for (const id of parentAgentIds) {
|
||||
if (id) map.set(id.toString(), build(id));
|
||||
}
|
||||
return map;
|
||||
return this.network.buildScopedAncestorChainMap(parentAgentIds, rootAgentId);
|
||||
}
|
||||
|
||||
private async getAgentPortalScope(rootAgentId: bigint) {
|
||||
const profile = await this.getProfile(rootAgentId);
|
||||
const subtreeIds = await this.getSubtreeAgentIds(rootAgentId);
|
||||
const descendantIds = subtreeIds.filter((id) => id !== rootAgentId);
|
||||
const subtreeIdSet = new Set(subtreeIds.map((id) => id.toString()));
|
||||
return {
|
||||
rootAgentId,
|
||||
rootLevel: profile.level,
|
||||
subtreeIds,
|
||||
descendantIds,
|
||||
subtreeIdSet,
|
||||
};
|
||||
private async getAgentPortalScope(rootAgentId: bigint): Promise<AgentScope> {
|
||||
return this.network.resolveScope(rootAgentId);
|
||||
}
|
||||
|
||||
private assertAgentInPortalSubtree(
|
||||
scope: { subtreeIdSet: Set<string> },
|
||||
scope: AgentScope,
|
||||
agentId: bigint,
|
||||
) {
|
||||
if (!scope.subtreeIdSet.has(agentId.toString())) {
|
||||
throw appForbidden('NOT_SUB_AGENT');
|
||||
}
|
||||
this.network.assertAgentInScope(scope, agentId);
|
||||
}
|
||||
|
||||
/** 代理端:玩家必须挂在当前代理子树内某代理下(自己或下级) */
|
||||
async requirePlayerInPortalSubtree(rootAgentId: bigint, playerId: bigint) {
|
||||
const scope = await this.getAgentPortalScope(rootAgentId);
|
||||
const player = await this.prisma.user.findFirst({
|
||||
where: { id: playerId, userType: 'PLAYER', deletedAt: null },
|
||||
include: { wallet: true, preferences: true, auth: true },
|
||||
});
|
||||
if (!player?.parentId || !scope.subtreeIdSet.has(player.parentId.toString())) {
|
||||
throw appForbidden('MANAGE_DIRECT_PLAYERS_ONLY');
|
||||
}
|
||||
return { player, scope, isDirect: player.parentId.toString() === rootAgentId.toString() };
|
||||
return this.network.requirePlayerInPortalSubtree(rootAgentId, playerId);
|
||||
}
|
||||
|
||||
private async validateAgentLevel(level: number, parentAgentId?: bigint) {
|
||||
@@ -270,51 +150,11 @@ export class AgentsService {
|
||||
}
|
||||
|
||||
async getProfile(agentId: bigint) {
|
||||
const profile = await this.prisma.agentProfile.findUnique({
|
||||
where: { userId: agentId },
|
||||
});
|
||||
if (!profile) throw appBadRequest('AGENT_PROFILE_NOT_FOUND');
|
||||
const available = new Decimal(profile.creditLimit).sub(profile.usedCredit);
|
||||
return { ...profile, availableCredit: available };
|
||||
return this.credit.getProfile(agentId);
|
||||
}
|
||||
|
||||
async recalculateUsedCredit(agentId: bigint) {
|
||||
const directPlayers = await this.prisma.user.findMany({
|
||||
where: { parentId: agentId, userType: 'PLAYER' },
|
||||
include: { wallet: true },
|
||||
});
|
||||
|
||||
let directLiability = new Decimal(0);
|
||||
for (const p of directPlayers) {
|
||||
if (p.wallet) {
|
||||
directLiability = directLiability
|
||||
.add(p.wallet.availableBalance)
|
||||
.add(p.wallet.frozenBalance);
|
||||
}
|
||||
}
|
||||
|
||||
const childAgents = await this.prisma.agentProfile.findMany({
|
||||
where: { parentAgentId: agentId },
|
||||
});
|
||||
|
||||
let childExposure = new Decimal(0);
|
||||
for (const child of childAgents) {
|
||||
const exposure = Decimal.max(child.creditLimit, child.usedCredit);
|
||||
childExposure = childExposure.add(exposure);
|
||||
}
|
||||
|
||||
const usedCredit = directLiability.add(childExposure);
|
||||
|
||||
await this.prisma.agentProfile.update({
|
||||
where: { userId: agentId },
|
||||
data: {
|
||||
usedCredit,
|
||||
directPlayerLiability: directLiability,
|
||||
childAgentExposure: childExposure,
|
||||
},
|
||||
});
|
||||
|
||||
return usedCredit;
|
||||
return this.credit.recalculateUsedCredit(agentId);
|
||||
}
|
||||
|
||||
async adjustCredit(
|
||||
@@ -324,45 +164,7 @@ export class AgentsService {
|
||||
requestId: string,
|
||||
remark?: string,
|
||||
) {
|
||||
const amt = new Decimal(amount);
|
||||
const profile = await this.prisma.agentProfile.findUnique({
|
||||
where: { userId: agentId },
|
||||
});
|
||||
if (!profile) throw appBadRequest('AGENT_NOT_FOUND');
|
||||
|
||||
const creditBefore = profile.creditLimit;
|
||||
const creditAfter = creditBefore.add(amt);
|
||||
if (creditAfter.lt(0)) throw appBadRequest('CREDIT_LIMIT_NEGATIVE');
|
||||
|
||||
if (profile.parentAgentId) {
|
||||
await this.assertChildCreditWithinParent(profile.parentAgentId, profile, creditAfter);
|
||||
}
|
||||
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
await tx.agentProfile.update({
|
||||
where: { userId: agentId },
|
||||
data: { creditLimit: creditAfter },
|
||||
});
|
||||
|
||||
await tx.agentCreditTransaction.create({
|
||||
data: {
|
||||
agentId,
|
||||
transactionType: amt.gte(0) ? 'CREDIT_INCREASE' : 'CREDIT_DECREASE',
|
||||
amount: amt,
|
||||
creditBefore,
|
||||
creditAfter,
|
||||
operatorId,
|
||||
requestId,
|
||||
remark,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
if (profile.parentAgentId) {
|
||||
await this.recalculateUsedCredit(profile.parentAgentId);
|
||||
}
|
||||
|
||||
return { creditAfter };
|
||||
return this.credit.adjustCredit(agentId, amount, operatorId, requestId, remark);
|
||||
}
|
||||
|
||||
/** 代理只能操作直属玩家(parentId === 当前代理) */
|
||||
@@ -462,19 +264,7 @@ export class AgentsService {
|
||||
|
||||
/** 玩家有所属代理时,上分金额不得超过该代理当前可用授信(会先重算 usedCredit) */
|
||||
async assertPlayerParentCreditForDeposit(playerId: bigint, amount: Decimal | number) {
|
||||
const user = await this.prisma.user.findFirst({
|
||||
where: { id: playerId, userType: 'PLAYER', deletedAt: null },
|
||||
select: { parentId: true },
|
||||
});
|
||||
if (!user?.parentId) return;
|
||||
|
||||
await this.recalculateUsedCredit(user.parentId);
|
||||
const profile = await this.getProfile(user.parentId);
|
||||
const available = new Decimal(profile.creditLimit).sub(profile.usedCredit);
|
||||
const amt = new Decimal(amount);
|
||||
if (available.lt(amt)) {
|
||||
throw appBadRequest('CREDIT_TOPUP_EXCEEDED');
|
||||
}
|
||||
return this.credit.assertPlayerParentCreditForDeposit(playerId, amount);
|
||||
}
|
||||
|
||||
/** 管理员给玩家上分:校验上级授信后入账,并刷新代理占用额度 */
|
||||
@@ -485,23 +275,7 @@ export class AgentsService {
|
||||
remark?: string,
|
||||
requestId?: string,
|
||||
) {
|
||||
await this.assertPlayerParentCreditForDeposit(playerId, amount);
|
||||
const result = await this.wallet.deposit(
|
||||
playerId,
|
||||
amount,
|
||||
operatorId,
|
||||
remark ?? '管理员上分',
|
||||
requestId,
|
||||
'ADMIN_DEPOSIT',
|
||||
);
|
||||
const player = await this.prisma.user.findUnique({
|
||||
where: { id: playerId },
|
||||
select: { parentId: true },
|
||||
});
|
||||
if (player?.parentId) {
|
||||
await this.recalculateUsedCredit(player.parentId);
|
||||
}
|
||||
return result;
|
||||
return this.credit.adminDepositToPlayer(playerId, amount, operatorId, remark, requestId);
|
||||
}
|
||||
|
||||
/** 管理员给玩家下分:扣款后刷新上级代理占用额度 */
|
||||
@@ -512,22 +286,7 @@ export class AgentsService {
|
||||
remark?: string,
|
||||
requestId?: string,
|
||||
) {
|
||||
const result = await this.wallet.withdraw(
|
||||
playerId,
|
||||
amount,
|
||||
operatorId,
|
||||
remark ?? '管理员下分',
|
||||
requestId,
|
||||
'ADMIN_WITHDRAW',
|
||||
);
|
||||
const player = await this.prisma.user.findUnique({
|
||||
where: { id: playerId },
|
||||
select: { parentId: true },
|
||||
});
|
||||
if (player?.parentId) {
|
||||
await this.recalculateUsedCredit(player.parentId);
|
||||
}
|
||||
return result;
|
||||
return this.credit.adminWithdrawFromPlayer(playerId, amount, operatorId, remark, requestId);
|
||||
}
|
||||
|
||||
/** 上下分弹窗:玩家余额 + 授信代理可用额度/限额上下文 */
|
||||
@@ -535,70 +294,7 @@ export class AgentsService {
|
||||
playerId: bigint,
|
||||
options: { forAdmin?: boolean; actingAgentId?: bigint } = {},
|
||||
) {
|
||||
const player = await this.prisma.user.findFirst({
|
||||
where: { id: playerId, userType: 'PLAYER', deletedAt: null },
|
||||
include: { wallet: true },
|
||||
});
|
||||
if (!player) throw appNotFound('PLAYER_NOT_FOUND');
|
||||
|
||||
if (options.actingAgentId) {
|
||||
await this.requireDirectPlayer(options.actingAgentId, playerId);
|
||||
}
|
||||
|
||||
const creditAgentId = options.forAdmin ? player.parentId : (options.actingAgentId ?? null);
|
||||
|
||||
let credit: Record<string, unknown> | null = null;
|
||||
if (creditAgentId) {
|
||||
await this.recalculateUsedCredit(creditAgentId);
|
||||
const profile = await this.getProfile(creditAgentId);
|
||||
const parent = profile.parentAgentId
|
||||
? await this.prisma.agentProfile.findUnique({ where: { userId: profile.parentAgentId } })
|
||||
: null;
|
||||
const { maxSingleDeposit, maxDailyDeposit } = this.resolveEffectiveDepositLimits(profile, parent);
|
||||
|
||||
let dailyDepositUsed: string | null = null;
|
||||
if (!options.forAdmin) {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const dailyAgg = await this.prisma.walletTransaction.aggregate({
|
||||
where: {
|
||||
operatorId: creditAgentId,
|
||||
transactionType: 'MANUAL_DEPOSIT',
|
||||
createdAt: { gte: today },
|
||||
},
|
||||
_sum: { amount: true },
|
||||
});
|
||||
dailyDepositUsed = dec(dailyAgg._sum.amount);
|
||||
}
|
||||
|
||||
const agentUser = await this.prisma.user.findUnique({
|
||||
where: { id: creditAgentId },
|
||||
select: { username: true },
|
||||
});
|
||||
|
||||
credit = {
|
||||
agentId: creditAgentId.toString(),
|
||||
agentUsername: agentUser?.username ?? '',
|
||||
agentLevel: profile.level,
|
||||
creditLimit: dec(profile.creditLimit),
|
||||
usedCredit: dec(profile.usedCredit),
|
||||
availableCredit: dec(profile.availableCredit),
|
||||
maxSingleDeposit: maxSingleDeposit?.toString() ?? null,
|
||||
maxDailyDeposit: maxDailyDeposit?.toString() ?? null,
|
||||
dailyDepositUsed,
|
||||
appliesDepositLimits: !options.forAdmin,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
player: {
|
||||
id: player.id.toString(),
|
||||
username: player.username,
|
||||
availableBalance: dec(player.wallet?.availableBalance),
|
||||
frozenBalance: dec(player.wallet?.frozenBalance),
|
||||
},
|
||||
credit,
|
||||
};
|
||||
return this.credit.getPlayerTransferContext(playerId, options);
|
||||
}
|
||||
|
||||
private async assertAgentDepositLimits(creditAgentId: bigint, amount: Decimal) {
|
||||
@@ -624,9 +320,9 @@ export class AgentsService {
|
||||
const dailyAgg = await this.prisma.walletTransaction.aggregate({
|
||||
where: {
|
||||
operatorId: creditAgentId,
|
||||
transactionType: 'MANUAL_DEPOSIT',
|
||||
createdAt: { gte: today },
|
||||
},
|
||||
transactionType: { in: ['AGENT_DEPOSIT', 'MANUAL_DEPOSIT'] },
|
||||
createdAt: { gte: today },
|
||||
},
|
||||
_sum: { amount: true },
|
||||
});
|
||||
const dailyTotal = new Decimal(dailyAgg._sum.amount ?? 0).add(amount);
|
||||
@@ -660,22 +356,7 @@ export class AgentsService {
|
||||
requestId: string,
|
||||
remark?: string,
|
||||
) {
|
||||
await this.requireDirectPlayer(agentId, playerId);
|
||||
|
||||
const profile = await this.getProfile(agentId);
|
||||
const available = new Decimal(profile.creditLimit).sub(profile.usedCredit);
|
||||
const amt = new Decimal(amount);
|
||||
|
||||
if (available.lt(amt)) {
|
||||
throw appBadRequest('INSUFFICIENT_AGENT_CREDIT');
|
||||
}
|
||||
|
||||
await this.assertAgentDepositLimits(agentId, amt);
|
||||
|
||||
await this.wallet.deposit(playerId, amt, agentId, remark ?? '代理上分', requestId, 'AGENT_DEPOSIT');
|
||||
await this.recalculateUsedCredit(agentId);
|
||||
|
||||
return { success: true };
|
||||
return this.credit.depositToPlayer(agentId, playerId, amount, requestId, remark);
|
||||
}
|
||||
|
||||
async withdrawFromPlayer(
|
||||
@@ -685,19 +366,7 @@ export class AgentsService {
|
||||
requestId: string,
|
||||
remark?: string,
|
||||
) {
|
||||
await this.requireDirectPlayer(agentId, playerId);
|
||||
|
||||
await this.wallet.withdraw(
|
||||
playerId,
|
||||
amount,
|
||||
agentId,
|
||||
remark ?? '代理下分',
|
||||
requestId,
|
||||
'AGENT_WITHDRAW',
|
||||
);
|
||||
await this.recalculateUsedCredit(agentId);
|
||||
|
||||
return { success: true };
|
||||
return this.credit.withdrawFromPlayer(agentId, playerId, amount, requestId, remark);
|
||||
}
|
||||
|
||||
async getDirectPlayerDetail(agentId: bigint, playerId: bigint) {
|
||||
@@ -1508,7 +1177,7 @@ export class AgentsService {
|
||||
|
||||
const hash = await this.auth.hashPassword(data.password);
|
||||
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
const user = await this.prisma.$transaction(async (tx) => {
|
||||
const locale = data.locale ?? 'zh-CN';
|
||||
const user = await tx.user.create({
|
||||
data: {
|
||||
@@ -1564,13 +1233,16 @@ export class AgentsService {
|
||||
},
|
||||
});
|
||||
}
|
||||
if (data.parentAgentId) {
|
||||
await this.recalculateUsedCredit(data.parentAgentId);
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
});
|
||||
|
||||
if (data.parentAgentId) {
|
||||
await this.recalculateUsedCredit(data.parentAgentId);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
async createPlayer(
|
||||
@@ -1707,18 +1379,7 @@ export class AgentsService {
|
||||
if (!remarkResult.ok) throw appBadRequest(remarkResult.code);
|
||||
const requestId =
|
||||
data.depositRequestId ?? `admin-create-${user.id}-${Date.now()}`;
|
||||
await this.assertPlayerParentCreditForDeposit(user.id, initial);
|
||||
await this.wallet.deposit(
|
||||
user.id,
|
||||
initial,
|
||||
operatorId,
|
||||
remarkResult.remark,
|
||||
requestId,
|
||||
'ADMIN_DEPOSIT',
|
||||
);
|
||||
if (parentId) {
|
||||
await this.recalculateUsedCredit(parentId);
|
||||
}
|
||||
await this.credit.adminDepositToPlayer(user.id, initial, operatorId, remarkResult.remark, requestId);
|
||||
}
|
||||
|
||||
return user;
|
||||
@@ -1799,10 +1460,7 @@ export class AgentsService {
|
||||
}
|
||||
|
||||
async getChildAgents(agentId: bigint) {
|
||||
return this.prisma.agentProfile.findMany({
|
||||
where: { parentAgentId: agentId },
|
||||
include: { user: true },
|
||||
});
|
||||
return this.network.getChildAgents(agentId);
|
||||
}
|
||||
|
||||
async listChildAgentsSummary(parentAgentId: bigint) {
|
||||
@@ -1980,15 +1638,7 @@ export class AgentsService {
|
||||
}
|
||||
|
||||
async assertDescendantAgent(rootAgentId: bigint, targetAgentId: bigint) {
|
||||
const subtreeIds = await this.getSubtreeAgentIds(rootAgentId);
|
||||
if (!subtreeIds.some((id) => id === targetAgentId)) {
|
||||
throw appForbidden('NOT_SUB_AGENT');
|
||||
}
|
||||
const profile = await this.prisma.agentProfile.findUnique({
|
||||
where: { userId: targetAgentId },
|
||||
});
|
||||
if (!profile) throw appNotFound('AGENT_NOT_FOUND');
|
||||
return profile;
|
||||
return this.network.assertDescendantAgent(rootAgentId, targetAgentId);
|
||||
}
|
||||
|
||||
async countSubtreeAgentsByLevel(rootAgentId: bigint) {
|
||||
@@ -2242,13 +1892,7 @@ export class AgentsService {
|
||||
}
|
||||
|
||||
async assertDirectChildAgent(parentAgentId: bigint, subAgentId: bigint) {
|
||||
const profile = await this.prisma.agentProfile.findUnique({
|
||||
where: { userId: subAgentId },
|
||||
});
|
||||
if (!profile || profile.parentAgentId !== parentAgentId) {
|
||||
throw appForbidden('NOT_SUB_AGENT');
|
||||
}
|
||||
return profile;
|
||||
return this.network.assertDirectChildAgent(parentAgentId, subAgentId);
|
||||
}
|
||||
|
||||
async getSubAgentForParent(parentAgentId: bigint, subAgentId: bigint) {
|
||||
@@ -2275,27 +1919,7 @@ export class AgentsService {
|
||||
}
|
||||
|
||||
async getSubtreeAgentIds(agentId: bigint) {
|
||||
const ids: bigint[] = [];
|
||||
const queue: bigint[] = [agentId];
|
||||
const seen = new Set<string>();
|
||||
|
||||
while (queue.length > 0) {
|
||||
const current = queue.shift()!;
|
||||
const key = current.toString();
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
ids.push(current);
|
||||
|
||||
const children = await this.prisma.agentProfile.findMany({
|
||||
where: { parentAgentId: current },
|
||||
select: { userId: true },
|
||||
});
|
||||
for (const child of children) {
|
||||
queue.push(child.userId);
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
return this.network.getSubtreeAgentIds(agentId);
|
||||
}
|
||||
|
||||
async getReportSummary(agentId: bigint) {
|
||||
|
||||
Reference in New Issue
Block a user