diff --git a/src/core/Deal.Infrastructure/Data/TenantContext.cs b/src/core/Deal.Infrastructure/Data/TenantContext.cs index 65eed6f..ab3520b 100644 --- a/src/core/Deal.Infrastructure/Data/TenantContext.cs +++ b/src/core/Deal.Infrastructure/Data/TenantContext.cs @@ -3,22 +3,17 @@ using Deal.SharedKernel.Tenants.Models; namespace Deal.Infrastructure.Data; -/// -/// Контекст тенанта на AsyncLocal -/// public sealed class TenantContext : ITenantContext { private static readonly AsyncLocal Current = new(); - public TenantId? TenantId => Current.Value; + TenantId? ITenantContext.TenantId => Current.Value; - public bool HasTenant => Current.Value is not null; + bool ITenantContext.HasTenant => Current.Value is not null; - public string? SchemaName => Current.Value?.SchemaName; + string? ITenantContext.SchemaName => Current.Value?.SchemaName; - /// void ITenantContext.SetTenant(TenantId tenantId) => Current.Value = tenantId; - /// void ITenantContext.Reset() => Current.Value = null; } diff --git a/src/core/Deal.Infrastructure/Integrations/Services/LocalTelegramGateway.cs b/src/core/Deal.Infrastructure/Integrations/Services/LocalTelegramGateway.cs index 1af1518..6dee6a7 100644 --- a/src/core/Deal.Infrastructure/Integrations/Services/LocalTelegramGateway.cs +++ b/src/core/Deal.Infrastructure/Integrations/Services/LocalTelegramGateway.cs @@ -3,21 +3,16 @@ using Deal.Contracts.Integrations.Models; namespace Deal.Infrastructure.Integrations.Services; -/// -/// Локальная заглушка без telegram-service. -/// public sealed class LocalTelegramGateway : ITelegramGateway { // Фаза idle-формы (аккаунт не подключён — сервиса нет). private const string IdlePhase = "idle"; - /// Task ITelegramGateway.StatusAsync(CancellationToken ct) { return Task.FromResult(new TelegramAccountStatusDto(IdlePhase, false, false, string.Empty, null, null)); } - /// Task ITelegramGateway.StartPhoneAsync( string phone, int apiId, @@ -25,76 +20,61 @@ public sealed class LocalTelegramGateway : ITelegramGateway CancellationToken ct) => Task.FromResult(new TelegramAuthResultDto(IdlePhase, null)); - /// Task ITelegramGateway.StartQrAsync( int apiId, string apiHash, CancellationToken ct) => Task.FromResult(new TelegramAuthResultDto(IdlePhase, null)); - /// - public Task SendCodeAsync(string code, CancellationToken ct) => Task.FromResult(IdlePhase); + Task ITelegramGateway.SendCodeAsync(string code, CancellationToken ct) => Task.FromResult(IdlePhase); - /// - public Task SendPasswordAsync(string password, CancellationToken ct) => Task.FromResult(IdlePhase); + Task ITelegramGateway.SendPasswordAsync(string password, CancellationToken ct) => Task.FromResult(IdlePhase); - /// Task ITelegramGateway.LogoutAsync(CancellationToken ct) => Task.CompletedTask; - /// Task> ITelegramGateway.RefreshDialogsAsync(CancellationToken ct) => Task.FromResult>([]); - /// Task ITelegramGateway.SetMonitorAsync( string dialogId, bool enabled, CancellationToken ct) => Task.CompletedTask; - /// Task ITelegramGateway.SetMonitorAllAsync(bool enabled, CancellationToken ct) => Task.CompletedTask; - /// - public Task BackfillAsync( + Task ITelegramGateway.BackfillAsync( string dialogId, bool force, CancellationToken ct) => Task.FromResult(0); - /// Task> ITelegramGateway.ReadRecentAsync( string dialogId, int limit, CancellationToken ct) => Task.FromResult>([]); - /// Task ITelegramGateway.ReadSourceAsync( string dialogId, long msgId, CancellationToken ct) => Task.FromResult(new TelegramSourceContentDto(false, null, null)); - /// Task> ITelegramGateway.SearchAsync( string query, int limit, CancellationToken ct) => Task.FromResult>([]); - /// Task ITelegramGateway.InfoAsync(string dialogId, CancellationToken ct) => Task.FromResult(new TelegramChannelInfoDto(dialogId, string.Empty, string.Empty, string.Empty, SourceDefaults.DefaultHue, null, false)); - /// Task ITelegramGateway.ReadForEvalAsync( string dialogId, int limit, CancellationToken ct) => Task.FromResult(new TelegramEvalReadDto(false, "no_history", [])); - /// Task ITelegramGateway.JoinAsync(string username, CancellationToken ct) => Task.CompletedTask; - /// Task ITelegramGateway.LeaveAsync(string dialogId, CancellationToken ct) => Task.CompletedTask; } diff --git a/src/core/Deal.Modules.Tenants/Application/Services/DefaultPasswordHasher.cs b/src/core/Deal.Modules.Tenants/Application/Services/DefaultPasswordHasher.cs index ba7e7c3..1876f4c 100644 --- a/src/core/Deal.Modules.Tenants/Application/Services/DefaultPasswordHasher.cs +++ b/src/core/Deal.Modules.Tenants/Application/Services/DefaultPasswordHasher.cs @@ -3,14 +3,9 @@ using Isopoh.Cryptography.Argon2; namespace Deal.Modules.Tenants.Application.Services; -/// -/// Реализация на Argon2id. -/// public sealed class DefaultPasswordHasher : IPasswordHasher { - /// - public string Hash(string password) => Argon2.Hash(password); + string IPasswordHasher.Hash(string password) => Argon2.Hash(password); - /// - public bool Verify(string password, string encodedHash) => Argon2.Verify(encodedHash, password); + bool IPasswordHasher.Verify(string password, string encodedHash) => Argon2.Verify(encodedHash, password); } diff --git a/src/core/tests/Deal.Tests.Unit/Api/DiscoveryWorkerSchedulerTests.cs b/src/core/tests/Deal.Tests.Unit/Api/DiscoveryWorkerSchedulerTests.cs index 8e12fd4..8d8ade1 100644 --- a/src/core/tests/Deal.Tests.Unit/Api/DiscoveryWorkerSchedulerTests.cs +++ b/src/core/tests/Deal.Tests.Unit/Api/DiscoveryWorkerSchedulerTests.cs @@ -39,7 +39,7 @@ public sealed class DiscoveryWorkerSchedulerTests TestDiscoveryStore StoreB, TestDiscoveryGateway GatewayA, TestDiscoveryGateway GatewayB, - TenantContext TenantContext, + ITenantContext TenantContext, ListLogger Logs); [Fact] @@ -91,7 +91,7 @@ public sealed class DiscoveryWorkerSchedulerTests private static Context CreateContext() { var tenants = new TestTenantRepository(Tenant(TenantA), Tenant(TenantB)); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); var storeA = new TestDiscoveryStore(); var storeB = new TestDiscoveryStore(); var settingsA = new TestSettingsStore(); diff --git a/src/core/tests/Deal.Tests.Unit/Api/MlOutboxFlushSchedulerTests.cs b/src/core/tests/Deal.Tests.Unit/Api/MlOutboxFlushSchedulerTests.cs index ef50d41..fb26843 100644 --- a/src/core/tests/Deal.Tests.Unit/Api/MlOutboxFlushSchedulerTests.cs +++ b/src/core/tests/Deal.Tests.Unit/Api/MlOutboxFlushSchedulerTests.cs @@ -41,7 +41,7 @@ public sealed class MlOutboxFlushSchedulerTests { var store = new TestMlLearningStore(); SeedRows(store, count: 25, prefix: "a"); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( port, new TestTenantRepository(Tenant(TenantA)), @@ -67,7 +67,7 @@ public sealed class MlOutboxFlushSchedulerTests service.TrainUnavailable = true; var store = new TestMlLearningStore(); SeedRows(store, count: 5, prefix: "a"); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( port, new TestTenantRepository(Tenant(TenantA)), @@ -95,7 +95,7 @@ public sealed class MlOutboxFlushSchedulerTests SeedRows(storeA, count: 12, prefix: "a"); var storeB = new TestMlLearningStore(); SeedRows(storeB, count: 3, prefix: "b"); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( port, new TestTenantRepository(Tenant(TenantA), Tenant(TenantB)), @@ -121,7 +121,7 @@ public sealed class MlOutboxFlushSchedulerTests { var store = new TestMlLearningStore(); SeedRows(store, count: 105, prefix: "a"); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( port, new TestTenantRepository(Tenant(TenantA)), @@ -148,7 +148,7 @@ public sealed class MlOutboxFlushSchedulerTests private static ServiceProvider BuildProvider( int port, TestTenantRepository tenants, - TenantContext tenantContext, + ITenantContext tenantContext, Dictionary storesByTenant) { var services = new ServiceCollection(); diff --git a/src/core/tests/Deal.Tests.Unit/Support/PipelineWorkerSchedulerTests.cs b/src/core/tests/Deal.Tests.Unit/Support/PipelineWorkerSchedulerTests.cs index 9bd8504..79a645d 100644 --- a/src/core/tests/Deal.Tests.Unit/Support/PipelineWorkerSchedulerTests.cs +++ b/src/core/tests/Deal.Tests.Unit/Support/PipelineWorkerSchedulerTests.cs @@ -47,7 +47,7 @@ public sealed class PipelineWorkerSchedulerTests TestKanjStore KanjB, SseSubscription SubscriptionB, PipelinePumpGate PumpGate, - TenantContext TenantContext, + ITenantContext TenantContext, ListLogger Logs); // ─── Цикл: pump каждого тенанта в собственном scope + new_card ───────── @@ -149,7 +149,7 @@ public sealed class PipelineWorkerSchedulerTests private static Context CreateContext(bool withThrowingQueueReadA = false) { var tenants = new TestTenantRepository(Tenant(TenantA), Tenant(TenantB)); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); var pipelineA = new TestPipelineStore(throwOnList: withThrowingQueueReadA); var pipelineB = new TestPipelineStore(); var kanjA = new TestKanjStore(); diff --git a/src/core/tests/Deal.Tests.Unit/Support/StorageTickSchedulerTests.cs b/src/core/tests/Deal.Tests.Unit/Support/StorageTickSchedulerTests.cs index e694a76..95198d0 100644 --- a/src/core/tests/Deal.Tests.Unit/Support/StorageTickSchedulerTests.cs +++ b/src/core/tests/Deal.Tests.Unit/Support/StorageTickSchedulerTests.cs @@ -46,7 +46,7 @@ public sealed class StorageTickSchedulerTests TestKanjStore storeB = StoreWithExpiredInboxCard("l_b_old"); var settings = new TestSettingsStore(); var tenants = new TestTenantRepository(Tenant(TenantA), Tenant(TenantB)); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider(tenants, tenantContext, storeA, storeB, settings); SseBroker broker = provider.GetRequiredService(); @@ -74,7 +74,7 @@ public sealed class StorageTickSchedulerTests var storeB = new TestKanjStore(); storeB.SeedCard(Card("l_b_fresh", KanbanColumns.Inbox, ReceivedAtMsAgo(TimeSpan.FromHours(1)))); var settings = new TestSettingsStore(); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( new TestTenantRepository(Tenant(TenantA), Tenant(TenantB)), tenantContext, @@ -100,7 +100,7 @@ public sealed class StorageTickSchedulerTests { // У тенанта A настройки падают (имитация сбоя схемы/БД) — тик A логирует ошибку, B обрабатывается. TestKanjStore storeB = StoreWithExpiredInboxCard("l_b_old"); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); var settingsByTenant = new Dictionary { [TenantA] = new ThrowingSettingsStore(), @@ -133,7 +133,7 @@ public sealed class StorageTickSchedulerTests [Fact] public async Task RunCycle_TenantListFailure_DoesNotThrow() { - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( new ThrowingTenantRepository(), tenantContext, @@ -152,7 +152,7 @@ public sealed class StorageTickSchedulerTests { var kanjStore = new TestKanjStore(); var settings = new TestSettingsStore(); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); var pipelineStoreA = new TestPipelineStore(); long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); pipelineStoreA.SeedRejected(Rejected("r_old_a", (long)(nowMs - TimeSpan.FromDays(4).TotalMilliseconds))); @@ -186,7 +186,7 @@ public sealed class StorageTickSchedulerTests cardStoreA.SeedCard(HoldCard("c_a_future", title: "Будущий", reminderAtMs: NowMs() + 60_000)); cardStoreA.SeedCard(HoldCard("c_a_work", stage: "work", title: "В работе", reminderAtMs: NowMs() - 60_000)); var cardStoreB = new TestKanjStore(); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( new TestTenantRepository(Tenant(TenantA), Tenant(TenantB)).Repository, tenantContext, @@ -221,7 +221,7 @@ public sealed class StorageTickSchedulerTests cardStoreA.SeedCard(HoldCard("c_past", title: "Старое", reminderAtMs: NowMs() - 60_000)); var settingsA = new TestSettingsStore(); settingsA.Preload(SettingsKeys.RemindersEnabled, "false"); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( new TestTenantRepository(Tenant(TenantA)).Repository, tenantContext, @@ -247,7 +247,7 @@ public sealed class StorageTickSchedulerTests // и тик A завершается, тенант B обрабатывается (автоархив + тост) — проход жив. var cardStoreA = new TestKanjStore(throwOnDueReminders: true); TestKanjStore storeB = StoreWithExpiredInboxCard("l_b_old"); - var tenantContext = new TenantContext(); + ITenantContext tenantContext = new TenantContext(); await using ServiceProvider provider = BuildProvider( new TestTenantRepository(Tenant(TenantA), Tenant(TenantB)).Repository, tenantContext, @@ -280,7 +280,7 @@ public sealed class StorageTickSchedulerTests // Возвращает: Провайдер с зарегистрированными сервисами теста. private static ServiceProvider BuildProvider( TestTenantRepository tenants, - TenantContext tenantContext, + ITenantContext tenantContext, TestKanjStore storeA, TestKanjStore storeB, TestSettingsStore settings) @@ -301,7 +301,7 @@ public sealed class StorageTickSchedulerTests // Возвращает: Провайдер с зарегистрированными сервисами теста. private static ServiceProvider BuildProvider( ITenantRepository tenants, - TenantContext tenantContext, + ITenantContext tenantContext, Dictionary storesByTenant, Dictionary settingsByTenant, Dictionary? pipelineStoresByTenant = null) diff --git a/src/telegram-service/Deal.Telegram/Telegram/WTelegramSessionClient.cs b/src/telegram-service/Deal.Telegram/Telegram/WTelegramSessionClient.cs index 31da04c..211670e 100644 --- a/src/telegram-service/Deal.Telegram/Telegram/WTelegramSessionClient.cs +++ b/src/telegram-service/Deal.Telegram/Telegram/WTelegramSessionClient.cs @@ -11,9 +11,6 @@ namespace Deal.Telegram.Telegram; #pragma warning disable CS0618 // Auth_SendCode/Auth_SignIn используются осознанно: ручной веб-вход 1:1 с прототипом -/// -/// Реальная реализация поверх WTelegramClient. -/// public sealed class WTelegramSessionClient : ISessionClient { private readonly Client _client; @@ -67,25 +64,19 @@ public sealed class WTelegramSessionClient : ISessionClient _updateManager = new UpdateManager(_client, OnSingleUpdateAsync); } - /// - public bool IsAuthorized => _client.UserId != 0; + bool ISessionClient.IsAuthorized => _client.UserId != 0; - /// - public bool IsConnected => _connected && !_client.Disconnected; + bool ISessionClient.IsConnected => _connected && !_client.Disconnected; - /// - public int ApiId => _apiId; + int ISessionClient.ApiId => _apiId; - /// - public string ApiHash => _apiHash; + string ISessionClient.ApiHash => _apiHash; - /// - public byte[]? SessionBytes => Volatile.Read(ref _latestSessionBytes); + byte[]? ISessionClient.SessionBytes => Volatile.Read(ref _latestSessionBytes); - /// async Task ISessionClient.ConnectAsync(CancellationToken cancellationToken) { - if (IsConnected) + if (((ISessionClient)this).IsConnected) { return; } @@ -94,7 +85,6 @@ public sealed class WTelegramSessionClient : ISessionClient _connected = true; } - /// async Task ISessionClient.RequestCodeAsync(string phone, CancellationToken cancellationToken) { _phone = phone; @@ -118,7 +108,6 @@ public sealed class WTelegramSessionClient : ISessionClient } } - /// async Task ISessionClient.SubmitCodeAsync(string code, CancellationToken cancellationToken) { if (_phoneAlreadyAuthorized) @@ -158,7 +147,6 @@ public sealed class WTelegramSessionClient : ISessionClient return null; } - /// async Task ISessionClient.SubmitPasswordAsync(string password, CancellationToken cancellationToken) { try @@ -178,7 +166,6 @@ public sealed class WTelegramSessionClient : ISessionClient } } - /// async Task ISessionClient.StartQrAsync(Action onQrUrl, CancellationToken cancellationToken) { try @@ -196,13 +183,11 @@ public sealed class WTelegramSessionClient : ISessionClient } } - /// async Task ISessionClient.LogOutAsync(CancellationToken cancellationToken) { await _client.Auth_LogOut().WaitAsync(cancellationToken).ConfigureAwait(false); } - /// async Task ISessionClient.GetAccountAsync(CancellationToken cancellationToken) { UserBase[] users = await _client.Users_GetUsers(InputUser.Self).WaitAsync(cancellationToken).ConfigureAwait(false); @@ -221,7 +206,6 @@ public sealed class WTelegramSessionClient : ISessionClient /// public event Func? MessageReceived; - /// async Task> ISessionClient.GetDialogsAsync(int limit, CancellationToken cancellationToken) { Messages_DialogsBase result = await RunTlCallAsync(() => _client.Messages_GetDialogs(limit: limit), cancellationToken).ConfigureAwait(false); @@ -241,7 +225,6 @@ public sealed class WTelegramSessionClient : ISessionClient return items; } - /// async Task> ISessionClient.GetMessagesAsync( string dialogId, int limit, @@ -265,7 +248,6 @@ public sealed class WTelegramSessionClient : ISessionClient return items; } - /// async Task ISessionClient.GetMessageAsync( string dialogId, long msgId, @@ -295,7 +277,6 @@ public sealed class WTelegramSessionClient : ISessionClient return null; } - /// async Task ISessionClient.MarkReadAsync(string dialogId, CancellationToken cancellationToken) { InputPeer peer = await ResolvePeerAsync(dialogId, cancellationToken).ConfigureAwait(false); @@ -303,7 +284,6 @@ public sealed class WTelegramSessionClient : ISessionClient } - /// async Task> ISessionClient.SearchAsync( string query, int limit, @@ -327,7 +307,6 @@ public sealed class WTelegramSessionClient : ISessionClient return items; } - /// async Task ISessionClient.GetInfoAsync(string dialogId, CancellationToken cancellationToken) { TelegramSourceInfo unknown = DefaultSourceInfo(dialogId); @@ -361,7 +340,6 @@ public sealed class WTelegramSessionClient : ISessionClient return unknown; } - /// async Task ISessionClient.ReadForEvalAsync( string dialogId, int limit, @@ -410,7 +388,6 @@ public sealed class WTelegramSessionClient : ISessionClient } } - /// async Task ISessionClient.JoinAsync(string username, CancellationToken cancellationToken) { Contacts_ResolvedPeer resolved = await RunTlCallAsync(() => _client.Contacts_ResolveUsername(username), cancellationToken).ConfigureAwait(false); @@ -425,7 +402,6 @@ public sealed class WTelegramSessionClient : ISessionClient await RunTlCallAsync(() => _client.Channels_JoinChannel(new InputChannel(channel.id, channel.access_hash)), cancellationToken).ConfigureAwait(false); } - /// async Task ISessionClient.LeaveAsync(string dialogId, CancellationToken cancellationToken) { if (!TryParseSignedId(dialogId, out bool isChannel, out _, out _, out long rawId) || !isChannel)