Skip to content

Commit 02d4c77

Browse files
committed
warnings
1 parent d1ce295 commit 02d4c77

15 files changed

+98
-58
lines changed

.editorconfig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
# SYSLIB1040: The non-generic 'JsonStringEnumConverter' requires dynamic code.
44
dotnet_diagnostic.SYSLIB1040.severity = none
5+
dotnet_diagnostic.CA1848.severity = none
6+
dotnet_diagnostic.CA1873.severity = none
57
csharp_indent_labels = one_less_than_current
68
csharp_using_directive_placement = outside_namespace:silent
79
csharp_prefer_simple_using_statement = true:suggestion
@@ -80,4 +82,4 @@ dotnet_naming_style.pascal_case.word_separator =
8082
dotnet_naming_style.pascal_case.capitalization = pascal_case
8183

8284
# csharpier
83-
max_line_length = 140
85+
max_line_length = 140

ClubDoorman.Test/AiChecksImageQualityTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ public void CreateSpamImageMessage_UsesHighDetail()
110110

111111
var part = message.Content.Value2.Single();
112112
Assert.That(part.IsImageUrl, Is.True, "Expected image content part.");
113-
return part.ImageUrl.ImageUrl.Detail;
113+
Assert.That(part.ImageUrl, Is.Not.Null, "Expected image URL payload.");
114+
Assert.That(part.ImageUrl!.ImageUrl, Is.Not.Null, "Expected nested image URL.");
115+
return part.ImageUrl.ImageUrl!.Detail;
114116
}
115117
}

ClubDoorman/AdminCommandHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ public async Task AdminChatMessage(Message message)
270270
{
271271
// TODO: this is not ideal, share getter with MessageProcessor
272272
_me ??= await _bot.GetMe();
273-
if (message.Text != null && message.Text.StartsWith("/unban"))
273+
if (message.Text != null && message.Text.StartsWith("/unban", StringComparison.Ordinal))
274274
{
275275
var split = message.Text.Split(' ');
276276
if (split.Length > 1 && long.TryParse(split[1], out var userId))

ClubDoorman/AiChecks.cs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Globalization;
12
using System.Text;
23
using System.Text.Json;
34
using System.Text.Json.Serialization;
@@ -173,13 +174,13 @@ public async ValueTask<SpamPhotoBio> GetAttentionBaitProbability(
173174
}
174175

175176
var sb = new StringBuilder();
176-
sb.Append($"Имя: {Utils.FullName(user)}");
177+
sb.Append(CultureInfo.InvariantCulture, $"Имя: {Utils.FullName(user)}");
177178
if (user.Username != null)
178-
sb.Append($"\nЮзернейм: @{user.Username}");
179+
sb.Append(CultureInfo.InvariantCulture, $"\nЮзернейм: @{user.Username}");
179180
if (userChat.Bio != null)
180-
sb.Append($"\nОписание: {userChat.Bio}");
181+
sb.Append(CultureInfo.InvariantCulture, $"\nОписание: {userChat.Bio}");
181182
if (photoBytes != null)
182-
sb.Append($"\nФото: ");
183+
sb.Append("\nФото: ");
183184

184185
nameBioUser = sb.ToString();
185186
var promptDebugString = nameBioUser;
@@ -205,14 +206,14 @@ public async ValueTask<SpamPhotoBio> GetAttentionBaitProbability(
205206
byte[]? channelPhoto = null;
206207
var linkedChat = await _bot.GetChat(linked, cancellationToken: ct);
207208
var info = new StringBuilder();
208-
info.Append($"Информация о привязанном канале:\nНазвание: {linkedChat.Title}");
209+
info.Append(CultureInfo.InvariantCulture, $"Информация о привязанном канале:\nНазвание: {linkedChat.Title}");
209210
if (linkedChat.Username != null)
210-
sb.Append($"\nЮзернейм: @{linkedChat.Username}");
211+
info.Append(CultureInfo.InvariantCulture, $"\nЮзернейм: @{linkedChat.Username}");
211212
if (linkedChat.Description != null)
212-
info.Append($"\nОписание: {linkedChat.Description}");
213+
info.Append(CultureInfo.InvariantCulture, $"\nОписание: {linkedChat.Description}");
213214
if (linkedChat.Photo != null)
214215
{
215-
info.Append($"\nФото:");
216+
info.Append("\nФото:");
216217
using var ms = new MemoryStream();
217218
await _bot.GetInfoAndDownloadFile(linkedChat.Photo.BigFileId, ms, cancellationToken: ct);
218219
channelPhoto = ms.ToArray();
@@ -249,14 +250,17 @@ public async ValueTask<SpamPhotoBio> GetAttentionBaitProbability(
249250
byte[]? channelPhoto = null;
250251
var mentionedChat = await _bot.GetChat(username, cancellationToken: ct);
251252
var info = new StringBuilder();
252-
info.Append($"Информация об упомянутом канале:\nНазвание: {mentionedChat.Title}");
253+
info.Append(
254+
CultureInfo.InvariantCulture,
255+
$"Информация об упомянутом канале:\nНазвание: {mentionedChat.Title}"
256+
);
253257
if (mentionedChat.Username != null)
254-
info.Append($"\nЮзернейм: @{mentionedChat.Username}");
258+
info.Append(CultureInfo.InvariantCulture, $"\nЮзернейм: @{mentionedChat.Username}");
255259
if (mentionedChat.Description != null)
256-
info.Append($"\nОписание: {mentionedChat.Description}");
260+
info.Append(CultureInfo.InvariantCulture, $"\nОписание: {mentionedChat.Description}");
257261
if (mentionedChat.Photo != null)
258262
{
259-
info.Append($"\nФото:");
263+
info.Append("\nФото:");
260264
using var ms = new MemoryStream();
261265
await _bot.GetInfoAndDownloadFile(mentionedChat.Photo.BigFileId, ms, cancellationToken: ct);
262266
channelPhoto = ms.ToArray();
@@ -327,9 +331,9 @@ internal record ChatDescription(string Description, long? ChannelId);
327331
{
328332
var chat = await _bot.GetChat(chatId, cancellationToken: ct);
329333
var info = new StringBuilder();
330-
info.AppendLine($"Чат: {chat.Title}");
334+
info.AppendLine(CultureInfo.InvariantCulture, $"Чат: {chat.Title}");
331335
if (chat.Description != null)
332-
info.AppendLine($"Описание чата: {chat.Description}");
336+
info.AppendLine(CultureInfo.InvariantCulture, $"Описание чата: {chat.Description}");
333337

334338
return new(info.ToString(), chat.LinkedChatId);
335339
}
@@ -354,9 +358,9 @@ private async ValueTask<string> GetLinkedChannelInfoAsync(long channelId, Cancel
354358
{
355359
var linkedChat = await _bot.GetChat(channelId, cancellationToken: ct);
356360
var info = new StringBuilder();
357-
info.AppendLine($"Этот чат - чат обсуждения для канала: {linkedChat.Title}");
361+
info.AppendLine(CultureInfo.InvariantCulture, $"Этот чат - чат обсуждения для канала: {linkedChat.Title}");
358362
if (linkedChat.Description != null)
359-
info.AppendLine($"Описание канала: {linkedChat.Description}");
363+
info.AppendLine(CultureInfo.InvariantCulture, $"Описание канала: {linkedChat.Description}");
360364

361365
return info.ToString();
362366
}
@@ -445,7 +449,7 @@ public async ValueTask<SpamProbability> GetSpamProbability(Message message, bool
445449
}
446450

447451
var modelToUse = free ? "openrouter/free" : Model;
448-
var selectedPhoto = message.Photo?.Any() == true ? SelectHighestQualityPhoto(message.Photo) : null;
452+
var selectedPhoto = message.Photo is { Length: > 0 } ? SelectHighestQualityPhoto(message.Photo) : null;
449453
var cacheKey = $"llm_spam_prob:{modelToUse}:{ShaHelper.ComputeSha256Hex(text)}";
450454
if (string.IsNullOrWhiteSpace(text) && selectedPhoto != null)
451455
cacheKey = $"llm_spam_prob:{modelToUse}:{selectedPhoto.FileUniqueId}";
@@ -513,7 +517,7 @@ public async ValueTask<SpamProbability> GetSpamProbability(Message message, bool
513517
fullPrompt.AppendLine(contextBuilder.ToString());
514518
fullPrompt.AppendLine("###");
515519
if (!string.IsNullOrWhiteSpace(text))
516-
fullPrompt.AppendLine($"Само сообщение, которое нужно проанализировать:\n{text}");
520+
fullPrompt.AppendLine(CultureInfo.InvariantCulture, $"Само сообщение, которое нужно проанализировать:\n{text}");
517521
else
518522
fullPrompt.AppendLine("Само сообщение не содержит текста, только изображение.");
519523

ClubDoorman/CaptchaManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public async ValueTask IntroFlow(User user, Chat chat)
172172

173173
var fullName = Utils.FullName(user);
174174
var fullNameLower = fullName.ToLowerInvariant();
175-
var usernameLower = user.Username?.ToLower();
175+
var usernameLower = user.Username?.ToLowerInvariant();
176176
if (
177177
_namesBlacklist.Any(fullNameLower.Contains)
178178
|| (usernameLower != null && _namesBlacklist.Any(usernameLower.Contains))

ClubDoorman/Config.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Frozen;
2+
using System.Globalization;
23
using Microsoft.Extensions.Caching.Hybrid;
34
using Telegram.Bot;
45

@@ -31,12 +32,16 @@ public Config(HybridCache hybridCache, ILogger<Config> logger)
3132
public bool HighConfidenceAutoBan { get; } = !GetEnvironmentBool("DOORMAN_HIGH_CONFIDENCE_AUTOBAN_DISABLE");
3233
public bool ApprovedUsersMlSpamCheck { get; } = !GetEnvironmentBool("DOORMAN_APPROVED_ML_SPAM_CHECK_DISABLE");
3334
public string BotApi { get; } =
34-
Environment.GetEnvironmentVariable("DOORMAN_BOT_API") ?? throw new Exception("DOORMAN_BOT_API variable not set");
35+
Environment.GetEnvironmentVariable("DOORMAN_BOT_API") ?? throw new InvalidOperationException("DOORMAN_BOT_API variable not set");
3536

3637
public string? OpenRouterApi { get; } = Environment.GetEnvironmentVariable("DOORMAN_OPENROUTER_API");
3738

3839
public long AdminChatId { get; } =
39-
long.Parse(Environment.GetEnvironmentVariable("DOORMAN_ADMIN_CHAT") ?? throw new Exception("DOORMAN_ADMIN_CHAT variable not set"));
40+
long.Parse(
41+
Environment.GetEnvironmentVariable("DOORMAN_ADMIN_CHAT")
42+
?? throw new InvalidOperationException("DOORMAN_ADMIN_CHAT variable not set"),
43+
CultureInfo.InvariantCulture
44+
);
4045

4146
public FrozenDictionary<long, long> MultiAdminChatMap { get; private set; }
4247
public FrozenSet<long> ChannelsCheckExclusionChats { get; }
@@ -143,7 +148,7 @@ private static string GetClubUrlOrDefault()
143148
if (!url.EndsWith('/'))
144149
url += '/';
145150
if (!Uri.IsWellFormedUriString(url, UriKind.Absolute))
146-
throw new Exception("DOORMAN_CLUB_URL variable is set to invalid URL");
151+
throw new InvalidOperationException("DOORMAN_CLUB_URL variable is set to invalid URL");
147152
return url;
148153
}
149154

ClubDoorman/MessageProcessor.cs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -987,22 +987,22 @@ private async Task HandleChatMemberUpdated(Update update, CancellationToken stop
987987
switch (newChatMember.Status)
988988
{
989989
case ChatMemberStatus.Member:
990+
{
991+
if (chatMember.OldChatMember.Status == ChatMemberStatus.Left)
990992
{
991-
if (chatMember.OldChatMember.Status == ChatMemberStatus.Left)
992-
{
993-
_logger.LogDebug(
994-
"New chat member in chat {Chat}: {First} {Last} @{Username}; Id = {Id}",
995-
chatMember.Chat.Title,
996-
newChatMember.User.FirstName,
997-
newChatMember.User.LastName,
998-
newChatMember.User.Username,
999-
newChatMember.User.Id
1000-
);
1001-
await _captchaManager.IntroFlow(newChatMember.User, chatMember.Chat);
1002-
WatchNewcomer(chatMember.Chat, newChatMember.User, stoppingToken);
1003-
}
1004-
break;
993+
_logger.LogDebug(
994+
"New chat member in chat {Chat}: {First} {Last} @{Username}; Id = {Id}",
995+
chatMember.Chat.Title,
996+
newChatMember.User.FirstName,
997+
newChatMember.User.LastName,
998+
newChatMember.User.Username,
999+
newChatMember.User.Id
1000+
);
1001+
await _captchaManager.IntroFlow(newChatMember.User, chatMember.Chat);
1002+
WatchNewcomer(chatMember.Chat, newChatMember.User, stoppingToken);
10051003
}
1004+
break;
1005+
}
10061006
case ChatMemberStatus.Kicked or ChatMemberStatus.Restricted:
10071007
StopWatchingNewcomer(key);
10081008
if (!_config.NonFreeChat(chatMember.Chat.Id))
@@ -1011,15 +1011,16 @@ private async Task HandleChatMemberUpdated(Update update, CancellationToken stop
10111011
var action = newChatMember.Status == ChatMemberStatus.Kicked ? "забанил(а)" : "дал(а) ридонли";
10121012
var user = newChatMember.User;
10131013
var messages = _recentMessagesStorage.Get(user.Id, chatMember.Chat.Id);
1014-
var lastMessage = messages.LastOrDefault();
1014+
var lastMessage = messages.Count > 0 ? messages[^1] : null;
10151015
var lastMessageText = lastMessage?.Text ?? lastMessage?.Caption;
10161016
var tailMessage = string.IsNullOrWhiteSpace(lastMessageText)
10171017
? "Если его забанили за спам, а ML не распознал спам - киньте его сообщение сюда."
10181018
: $"Его/её последним сообщением было:{Environment.NewLine}{lastMessageText}";
10191019
var mentionAt = user.Username != null ? $" @{user.Username}" : "";
10201020
await _bot.SendMessage(
10211021
_config.GetAdminChat(chatMember.Chat.Id),
1022-
$"В чате {chatMember.Chat.Title} юзеру {Utils.FullName(user)}{mentionAt} {action} {Utils.FullName(chatMember.From)}. {tailMessage}"
1022+
$"В чате {chatMember.Chat.Title} юзеру {Utils.FullName(user)}{mentionAt} {action} {Utils.FullName(chatMember.From)}. {tailMessage}",
1023+
cancellationToken: stoppingToken
10231024
);
10241025
break;
10251026
case ChatMemberStatus.Left:

ClubDoorman/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ private static void SeedData(AppDbContext db)
106106
using var reader = new StreamReader(dataFile);
107107
using var csv = new CsvReader(
108108
reader,
109-
new CsvConfiguration(CultureInfo.InvariantCulture) { PrepareHeaderForMatch = args => args.Header.ToLower() }
109+
new CsvConfiguration(CultureInfo.InvariantCulture) { PrepareHeaderForMatch = args => args.Header.ToLowerInvariant() }
110110
);
111111

112112
var records = csv.GetRecords<CsvRow>().Select(r => new SpamHamRecord { Text = r.Text, IsSpam = r.Label });
@@ -125,7 +125,7 @@ private static void SeedData(AppDbContext db)
125125
Log.Information("No approved users detected in the database, starting initial seeding from text file");
126126
var userIds = File.ReadAllLines(dataFile)
127127
.Where(line => !string.IsNullOrWhiteSpace(line))
128-
.Select(line => new ApprovedUser { Id = long.Parse(line) });
128+
.Select(line => new ApprovedUser { Id = long.Parse(line, CultureInfo.InvariantCulture) });
129129

130130
db.ApprovedUsers.AddRange(userIds);
131131
db.SaveChanges();

ClubDoorman/ShaHelper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Security.Cryptography;
1+
using System.Globalization;
2+
using System.Security.Cryptography;
23
using System.Text;
34

45
namespace ClubDoorman;
@@ -13,7 +14,7 @@ public static string ComputeSha256Hex(string? input)
1314
var hash = SHA256.HashData(bytes);
1415
var sb = new StringBuilder(hash.Length * 2);
1516
foreach (byte b in hash)
16-
sb.Append(b.ToString("x2"));
17+
sb.Append(b.ToString("x2", CultureInfo.InvariantCulture));
1718
return sb.ToString();
1819
}
1920
}

ClubDoorman/SpamHamClassifier.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ internal class MessagePrediction : MessageData
2121
public bool PredictedLabel { get; set; }
2222
}
2323

24-
public class SpamHamClassifier
24+
public class SpamHamClassifier : IDisposable
2525
{
2626
public SpamHamClassifier(ILogger<SpamHamClassifier> logger, IServiceScopeFactory serviceScopeFactory)
2727
{
@@ -42,16 +42,14 @@ public SpamHamClassifier(ILogger<SpamHamClassifier> logger, IServiceScopeFactory
4242

4343
private async Task RetrainLoop()
4444
{
45-
while (true)
45+
while (await _retrainTimer.WaitForNextTickAsync())
4646
{
47-
await _retrainTimer.WaitForNextTickAsync();
4847
if (_needsRetraining)
4948
{
5049
await Train();
5150
_needsRetraining = false;
5251
}
5352
}
54-
// ReSharper disable once FunctionNeverReturns
5553
}
5654

5755
public async Task<(bool Spam, float Score)> IsSpam(string message)
@@ -125,4 +123,11 @@ private async Task Train()
125123
_logger.LogError(e, "Exception during training");
126124
}
127125
}
126+
127+
public void Dispose()
128+
{
129+
_retrainTimer.Dispose();
130+
_datasetLock.Dispose();
131+
GC.SuppressFinalize(this);
132+
}
128133
}

0 commit comments

Comments
 (0)