修改User模块
This commit is contained in:
1 parent
d6471f97d3
commit
bb7162aaf6
21 files changed
+278
-336
No files matched your search
@@ -14,14 +14,6 @@ public sealed class UserFundsService(IFreeSql orm, ICurrentUser currentUser) : I
|
||||
public async Task<UserFundsResponse> Change(UserFundsRequest request, bool points, CancellationToken ct)
|
||||
{
|
||||
RequestValidator.Validate(request);
|
||||
// DTO 只检查非空,其余长度、金额和操作组合在服务中手动判断。
|
||||
UserInputChecks.Length(request.UserName, 20, "目标账户");
|
||||
UserInputChecks.Length(request.RequestId, 64, "请求号");
|
||||
UserInputChecks.Length(request.Remark, 255, "备注");
|
||||
if (request.Amount is < 0.01m or > 1000000m)
|
||||
throw new ValidationException("金额必须为0.01-1000000");
|
||||
if (decimal.Round(request.Amount, 2) != request.Amount)
|
||||
throw new ValidationException("金额最多保留两位小数");
|
||||
if (points ? request.Operation is not ("充值" or "转移") : request.Operation is not ("充值" or "消费"))
|
||||
throw new ValidationException("不支持的资金操作类型");
|
||||
ct.ThrowIfCancellationRequested();
|
||||
@@ -32,15 +24,12 @@ public sealed class UserFundsService(IFreeSql orm, ICurrentUser currentUser) : I
|
||||
var actor = await db.Select<UserEntity>().Where(u => u.UserName == currentUser.UserName).FirstAsync(ct)
|
||||
?? throw new UnauthorizedAccessException();
|
||||
bool transfer = points && request.Operation == "转移";
|
||||
if (!transfer && actor.SaLevel != 1) throw new AppException("充值和余额调整仅允许管理员操作", 403);
|
||||
var name = request.UserName.Trim();
|
||||
var target = await db.Select<UserEntity>().Where(u => u.UserName == name).FirstAsync(ct)
|
||||
?? throw new AppException("目标账户不存在");
|
||||
if (transfer && actor.Id == target.Id) throw new AppException("不能向自己转移积分");
|
||||
if (transfer && !UserAccessPolicy.CanManage(actor, target))
|
||||
throw new AppException("只能向管理范围内的账户转移积分", 403);
|
||||
// 双账户转移按相同主键顺序加锁,避免双方同时转账时产生反向锁顺序。
|
||||
var ids = transfer ? new[] { actor.Id, target.Id }.Order().ToArray() : new[] { target.Id };
|
||||
// 操作者和目标按主键顺序加锁,再按最新账户状态授权,避免权限变更与资金写入交错。
|
||||
var ids = new[] { actor.Id, target.Id }.Distinct().Order().ToArray();
|
||||
foreach (var id in ids)
|
||||
{
|
||||
var locked = await db.Select<UserEntity>().Where(u => u.Id == id).ForUpdate().FirstAsync(ct)
|
||||
@@ -48,6 +37,10 @@ public sealed class UserFundsService(IFreeSql orm, ICurrentUser currentUser) : I
|
||||
if (id == target.Id) target = locked;
|
||||
if (id == actor.Id) actor = locked;
|
||||
}
|
||||
if (transfer && !UserAccessPolicy.CanManage(actor, target))
|
||||
throw new AppException("只能向管理范围内的账户转移积分", 403);
|
||||
if (!transfer && !UserAccessPolicy.IsAdmin(actor))
|
||||
throw new AppException("充值和余额调整仅允许管理员操作", 403);
|
||||
var key = "user:" + request.RequestId.Trim();
|
||||
// 持有目标行锁后检查请求号,相同账户的并发重试只能执行一次。
|
||||
bool duplicate = points
|
||||
@@ -101,7 +94,7 @@ public sealed class UserFundsService(IFreeSql orm, ICurrentUser currentUser) : I
|
||||
if (await db.Insert(new UserPointsRecordEntity
|
||||
{
|
||||
UserName = user.UserName, UserNick = user.NickName, DeltaPoints = amount, NewPoints = value,
|
||||
OptionType = operation, OperatorType = actor.SaLevel == 1 ? "管理员" : "用户", OperatorName = actor.UserName,
|
||||
OptionType = operation, OperatorType = UserAccessPolicy.IsAdmin(actor) ? "管理员" : "用户", OperatorName = actor.UserName,
|
||||
CounterpartyAccountName = counterparty, OutTradeNo = key, Remark = remark, AddTime = DateTime.Now
|
||||
}).ExecuteAffrowsAsync(ct) != 1) throw new AppException("写入积分流水失败");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user