- Implemented 3 Commands with handlers and validators:
* JoinNetworkCommand: Add user to binary network tree
- Validates parent exists and is in network
- Validates leg position is empty
- Records history with NetworkMembershipAction.Join
* MoveInNetworkCommand: Move user to different position
- Validates new parent and leg availability
- Prevents circular dependencies (IsDescendant check)
- Records old/new parent and leg in history
* RemoveFromNetworkCommand: Remove user from network
- Validates no children exist (must move/remove first)
- Soft delete (sets NetworkParentId to null)
- Idempotent design
- Implemented 3 Queries with handlers, validators, and DTOs:
* GetNetworkTreeQuery: Binary tree visualization
- Recursive tree building with MaxDepth limit (1-10)
- Returns nested structure with Left/Right children
* GetUserNetworkPositionQuery: User position details
- Parent info, leg position, children counts
- Left/Right child counts for balance view
* GetNetworkMembershipHistoryQuery: Complete audit trail
- Filter by UserId, pagination support
- Shows Join/Move/Remove actions with full details
- All operations include complete history tracking
- Binary tree validation (parent-child relationships)
- Circular dependency prevention in MoveInNetwork
- 21 new files, ~850 lines of code
- Build successful with 0 errors
70 lines
2.4 KiB
C#
70 lines
2.4 KiB
C#
namespace CMSMicroservice.Application.NetworkMembershipCQ.Commands.RemoveFromNetwork;
|
|
|
|
public class RemoveFromNetworkCommandHandler : IRequestHandler<RemoveFromNetworkCommand, Unit>
|
|
{
|
|
private readonly IApplicationDbContext _context;
|
|
|
|
public RemoveFromNetworkCommandHandler(IApplicationDbContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
public async Task<Unit> Handle(RemoveFromNetworkCommand request, CancellationToken cancellationToken)
|
|
{
|
|
// بررسی وجود کاربر
|
|
var user = await _context.Users
|
|
.FirstOrDefaultAsync(x => x.Id == request.UserId, cancellationToken);
|
|
|
|
if (user == null)
|
|
{
|
|
throw new NotFoundException(nameof(User), request.UserId);
|
|
}
|
|
|
|
// بررسی اینکه کاربر در شبکه باشد
|
|
if (!user.NetworkParentId.HasValue)
|
|
{
|
|
// اگر قبلاً حذف شده، هیچ کاری نکن (Idempotent)
|
|
return Unit.Value;
|
|
}
|
|
|
|
// بررسی وجود فرزندان
|
|
var hasChildren = await _context.Users
|
|
.AnyAsync(x => x.NetworkParentId == request.UserId, cancellationToken);
|
|
|
|
if (hasChildren)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"کاربر با شناسه {request.UserId} دارای فرزند در شبکه است. ابتدا باید فرزندان جابجا یا حذف شوند");
|
|
}
|
|
|
|
// ذخیره مقادیر قبلی برای History
|
|
var oldParentId = user.NetworkParentId;
|
|
var oldLegPosition = user.LegPosition;
|
|
|
|
// حذف از شبکه (Soft Delete)
|
|
user.NetworkParentId = null;
|
|
user.LegPosition = null;
|
|
|
|
_context.Users.Update(user);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
// ثبت تاریخچه
|
|
var history = new NetworkMembershipHistory
|
|
{
|
|
UserId = request.UserId,
|
|
OldParentId = oldParentId,
|
|
NewParentId = null,
|
|
OldLegPosition = oldLegPosition,
|
|
NewLegPosition = null,
|
|
Action = NetworkMembershipAction.Remove,
|
|
Reason = request.Reason ?? "حذف از شبکه",
|
|
PerformedBy = "System" // TODO: باید از Current User گرفته شود
|
|
};
|
|
|
|
await _context.NetworkMembershipHistories.AddAsync(history, cancellationToken);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
return Unit.Value;
|
|
}
|
|
}
|