< Summary

Information
Class: Services.ApiServices.TelegramBotApi.TelegramNotifier
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/TelegramBotApi/TelegramNotifier.cs
Line coverage
73%
Covered lines: 47
Uncovered lines: 17
Coverable lines: 64
Total lines: 109
Line coverage: 73.4%
Branch coverage
45%
Covered branches: 21
Total branches: 46
Branch coverage: 45.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
RoutesFor(...)100%210%
get_IsConfigured()100%11100%
SendAsync()100%88100%
SendToRouteAsync()50%201883.33%
EditAsync()66.66%66100%
PinAsync()0%620%
UnpinAsync()0%620%
GetPinnedAsync()0%110100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/TelegramBotApi/TelegramNotifier.cs

#LineLine coverage
 1using Microsoft.Extensions.Logging;
 2using Services.ApiServices.TelegramBotApi.Models;
 3
 4namespace Services.ApiServices.TelegramBotApi;
 5
 6public sealed class TelegramNotifier : ITelegramNotifier
 7{
 8    private readonly TelegramBotApiClient _client;
 9    private readonly TelegramBotConfig _config;
 10    private readonly ILogger<TelegramNotifier>? _logger;
 11
 1312    public TelegramNotifier(TelegramBotApiClient client, TelegramBotConfig config, ILogger<TelegramNotifier>? logger = n
 13    {
 1314        _client = client;
 1315        _config = config;
 1316        _logger = logger;
 1317    }
 18
 19    public IReadOnlyList<TelegramRoute> RoutesFor(TelegramChannel channel, bool critical = false) =>
 020        _config.RoutesFor(channel, critical);
 21
 222    public bool IsConfigured => _config.IsConfigured;
 23
 24    public async Task<bool> SendAsync(TelegramMessage message, CancellationToken ct = default)
 25    {
 1326        if (!_config.IsConfigured) return false;
 27
 28        // Явный чат — только ему; иначе маршруты категории (+ критичные). Недоступный получатель не мешает остальным.
 1129        IReadOnlyList<TelegramRoute> routes = message.ChatId is { } explicitChat and not 0
 1130            ? [new TelegramRoute { ChatId = explicitChat }]
 1131            : _config.RoutesFor(message.Channel, message.Critical);
 1132        var anySent = false;
 5233        foreach (var route in routes)
 1534            anySent |= await SendToRouteAsync(message, route, ct) != null;
 1135        return anySent;
 1236    }
 37
 38    public async Task<long?> SendToRouteAsync(TelegramMessage message, TelegramRoute route, CancellationToken ct = defau
 39    {
 1540        var chatId = route.ChatId;
 1541        if (!_config.IsConfigured || chatId == 0) return null;
 42        try
 43        {
 1544            if (!string.IsNullOrWhiteSpace(message.ImageUrl))
 45            {
 146                var photo = await _client.SendPhotoAsync(new SendPhotoRequest
 147                {
 148                    ChatId = chatId,
 149                    MessageThreadId = route.ThreadId,
 150                    Photo = message.ImageUrl,
 151                    Caption = message.Html.Length > TelegramMessageBuilder.MaxCaptionLength
 152                        ? message.Html[..TelegramMessageBuilder.MaxCaptionLength]
 153                        : message.Html,
 154                    ParseMode = "HTML",
 155                    DisableNotification = message.Silent
 156                }, ct);
 157                if (photo.Ok) return photo.Value?.MessageId ?? 0;
 58                // Картинка недоступна Telegram — не теряем само сообщение.
 59            }
 60
 1561            var result = await _client.SendMessageAsync(new SendMessageRequest
 1562            {
 1563                ChatId = chatId,
 1564                MessageThreadId = route.ThreadId,
 1565                Text = message.Html,
 1566                ParseMode = "HTML",
 1567                DisableNotification = message.Silent
 1568            }, ct);
 1569            return result.Ok ? result.Value?.MessageId ?? 0 : null;
 70        }
 071        catch (OperationCanceledException) when (ct.IsCancellationRequested)
 72        {
 073            throw;
 74        }
 075        catch (Exception ex)
 76        {
 077            _logger?.LogWarning("Не удалось отправить сообщение в Telegram (чат {ChatId}): {Type}", chatId, ex.GetType()
 078            return null;
 79        }
 1580    }
 81
 82    public async Task<bool> EditAsync(long chatId, long messageId, string html, CancellationToken ct = default)
 83    {
 284        if (!_config.IsConfigured) return false;
 285        var result = await _client.EditMessageTextAsync(new EditMessageTextRequest
 286        {
 287            ChatId = chatId, MessageId = messageId, Text = html, ParseMode = "HTML"
 288        }, ct);
 289        return result.Ok || (result.Error?.Contains("message is not modified", StringComparison.OrdinalIgnoreCase) ?? fa
 290    }
 91
 92    public async Task<bool> PinAsync(long chatId, long messageId, bool silent = true, CancellationToken ct = default) =>
 093        _config.IsConfigured && (await _client.PinChatMessageAsync(
 094            new PinChatMessageRequest { ChatId = chatId, MessageId = messageId, DisableNotification = silent }, ct)).Ok;
 95
 96    public async Task<bool> UnpinAsync(long chatId, long messageId, CancellationToken ct = default) =>
 097        _config.IsConfigured && (await _client.UnpinChatMessageAsync(
 098            new UnpinChatMessageRequest { ChatId = chatId, MessageId = messageId }, ct)).Ok;
 99
 100    public async Task<TelegramPinnedMessage?> GetPinnedAsync(long chatId, CancellationToken ct = default)
 101    {
 0102        if (!_config.IsConfigured) return null;
 0103        var chat = await _client.GetChatAsync(chatId, ct);
 0104        var pinned = chat.Value?.PinnedMessage;
 0105        return chat.Ok && pinned != null
 0106            ? new TelegramPinnedMessage(pinned.MessageId, pinned.Text, pinned.From?.IsBot == true)
 0107            : null;
 0108    }
 109}