Implement billing status notification and enhance user management integration
- Added `NotifyBillingStatusChangedAsync` method to `IRealtimeNotifier` for notifying clients about changes in billing status. - Updated `BillingConfigResumer` to call the new notification method after modifying billing configurations, ensuring users receive real-time updates. - Enhanced `ListUsersQueryHandler` to include a `BillingPendingReview` property in `UserSummaryDto`, indicating if a user has a pending payment request awaiting confirmation. - Refactored various command handlers to utilize `AdvisoryLock` for managing concurrent requests, preventing race conditions in billing operations. - Updated tests to cover new notification behaviors and ensure proper functionality in billing status management.
This commit is contained in:
@@ -75,6 +75,7 @@ public sealed class BillingService(
|
||||
await BillingConfigResumer.ProtectPendingConfigsAsync(
|
||||
dbContext,
|
||||
gateway,
|
||||
notifier,
|
||||
logger,
|
||||
user.UserId,
|
||||
cancellationToken
|
||||
|
||||
@@ -118,6 +118,17 @@ internal sealed class RoleService(
|
||||
if (usersInRole.Count > 0)
|
||||
return Result.Failure(RoleErrors.RoleInUse);
|
||||
|
||||
// Живых пользователей с этой ролью нет, но инбаунды могли всё ещё указывать её в
|
||||
// AllowedRoleIds (plain uuid[], без FK) — без подчистки роль пропадёт из RoleManager, а
|
||||
// "мёртвая" ссылка так и останется висеть в массиве, молча не пуская никого нового.
|
||||
var affectedInbounds = await dbContext
|
||||
.Inbounds.Where(i => i.AllowedRoleIds.Contains(roleId))
|
||||
.ToListAsync(cancellationToken);
|
||||
foreach (var inbound in affectedInbounds)
|
||||
inbound.RemoveAllowedRole(roleId);
|
||||
if (affectedInbounds.Count > 0)
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
await roleManager.DeleteAsync(role);
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
@@ -157,6 +157,23 @@ internal sealed class XuiPanelGateway(
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
// ThreeXui.Net трактует обновление shadowsocks-клиента как rotate password/cipher, вне
|
||||
// области UpdateClient — молча ничего не меняет и возвращает false внутри себя, а наш уровень
|
||||
// выше это никак не видит (XuiClient.UpdateClientAsync это глотает и просто логирует debug).
|
||||
// Раньше это означало Result.Success() без единого реального изменения на панели: блокировка/
|
||||
// приостановка/возврат по оплате были no-op для SS-конфигов, хотя мы считали их применёнными.
|
||||
// Явно отказываем, а не молчим — вызывающий код (Block/UnblockUserCommandHandler,
|
||||
// BillingConfigResumer) увидит ошибку и залогирует предупреждение вместо ложной уверенности.
|
||||
if (protocol == VpnProtocol.Shadowsocks)
|
||||
{
|
||||
return Result.Failure(
|
||||
Error.Failure(
|
||||
"Xui.ShadowsocksUpdateNotSupported",
|
||||
"3x-ui/ThreeXui.Net не поддерживает изменение shadowsocks-клиента (enable/expiresAt/имя) после создания."
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var client = GetClient(node);
|
||||
|
||||
Reference in New Issue
Block a user