Вынести условия-предикаты в extension-методы
HasUser из 13 endpoint-файлов сведён в AuthHelpers.HasUser; 15 приватных предикатов заменены extension-методами с удалением дублирующих приватных методов: IsCommunicationFailure, IsTransportFailure, IsPrivateEndpoint, IsConfigured, IsTrue, IsExpired, IsFailedLogin/IsSuccessfulLogin, HasChanges, HasBudget, HasAnyTerm, IsCurrencyLetter, IsEmojiCodePoint, ContainsFooterHint, IsTypeLabel.
This commit is contained in:
@@ -148,13 +148,13 @@ public static class BudgetNormalizer
|
||||
return direct;
|
||||
}
|
||||
|
||||
string letters = new string(s.Where(IsCurrencyLetter).ToArray());
|
||||
string letters = new string(s.Where(c => c.IsCurrencyLetter()).ToArray());
|
||||
if (CurrencyAliases.TryGetValue(letters, out string? fromLetters))
|
||||
{
|
||||
return fromLetters;
|
||||
}
|
||||
|
||||
if (s.Length == 3 && s.All(IsCurrencyLetter))
|
||||
if (s.Length == 3 && s.All(c => c.IsCurrencyLetter()))
|
||||
{
|
||||
return s;
|
||||
}
|
||||
@@ -162,14 +162,6 @@ public static class BudgetNormalizer
|
||||
return null;
|
||||
}
|
||||
|
||||
// Буква кода валюты: латиница A–Z или кириллица А–Я (regex прототипа [^A-ZА-Я], ai.py L286).
|
||||
// c: Символ (строка уже в верхнем регистре).
|
||||
// Возвращает: True — буква, участвующая в распознавании валюты.
|
||||
private static bool IsCurrencyLetter(char c)
|
||||
{
|
||||
return c is >= 'A' and <= 'Z' or >= 'А' and <= 'Я';
|
||||
}
|
||||
|
||||
// Конвертация суммы через курсы к рублю; null rates → null (курсов нет — граница не конвертируется).
|
||||
// amount: Сумма.
|
||||
// fromCurrency: Исходная валюта (код).
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Deal.Modules.Kanban.Application;
|
||||
|
||||
/// <summary>
|
||||
/// Расширения символов для нормализации бюджетной валюты.
|
||||
/// </summary>
|
||||
internal static class CharExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Буква кода валюты: латиница A–Z или кириллица А–Я (regex прототипа [^A-ZА-Я], ai.py L286).
|
||||
/// </summary>
|
||||
/// <param name="c">Символ (строка уже в верхнем регистре).</param>
|
||||
/// <returns>True — буква, участвующая в распознавании валюты.</returns>
|
||||
public static bool IsCurrencyLetter(this char c) =>
|
||||
c is >= 'A' and <= 'Z' or >= 'А' and <= 'Я';
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Deal.Modules.Kanban.Application.Models;
|
||||
|
||||
namespace Deal.Modules.Kanban.Application.ColumnRules;
|
||||
|
||||
/// <summary>
|
||||
/// Расширения бюджетной группы правил колонки.
|
||||
/// </summary>
|
||||
internal static class BudgetRangeDtoExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Активна ли бюджетная группа: объект есть и не «пустой» (прототип bool(budget) — {} выключен,
|
||||
/// {cur} без границ включён; см. ColumnMatcher.HasActiveRules).
|
||||
/// </summary>
|
||||
/// <param name="budget">Поле budget/prices правил (может быть null).</param>
|
||||
/// <returns>True — группа бюджета участвует в матчинге.</returns>
|
||||
public static bool HasBudget(this BudgetRangeDto? budget)
|
||||
{
|
||||
return budget is not null
|
||||
&& (budget.From is not null || budget.To is not null || !string.IsNullOrWhiteSpace(budget.Cur));
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,8 @@ public static class ColumnMatcher
|
||||
IReadOnlyList<string> locations = NormalizeTerms(rules.Locations);
|
||||
IReadOnlyList<string> types = NormalizeTerms(rules.Types);
|
||||
IReadOnlyList<string> typeTerms = TypeAliases.ExpandTerms(types);
|
||||
bool budgetEnabled = HasBudget(rules.Budget);
|
||||
bool pricesEnabled = HasBudget(rules.Prices);
|
||||
bool budgetEnabled = rules.Budget.HasBudget();
|
||||
bool pricesEnabled = rules.Prices.HasBudget();
|
||||
|
||||
bool anyEnabled = keywords.Count > 0 || stack.Count > 0 || direction.Count > 0 || grade.Count > 0
|
||||
|| levels.Count > 0 || locations.Count > 0 || types.Count > 0 || budgetEnabled || pricesEnabled;
|
||||
@@ -157,38 +157,17 @@ public static class ColumnMatcher
|
||||
return false;
|
||||
}
|
||||
|
||||
return HasAnyTerm(rules.Direction)
|
||||
|| HasAnyTerm(rules.Keywords)
|
||||
|| HasAnyTerm(rules.Stack)
|
||||
|| HasAnyTerm(rules.Grade)
|
||||
|| HasAnyTerm(rules.Levels)
|
||||
|| HasAnyTerm(rules.Locations)
|
||||
|| HasAnyTerm(rules.Types)
|
||||
return rules.Direction.HasAnyTerm()
|
||||
|| rules.Keywords.HasAnyTerm()
|
||||
|| rules.Stack.HasAnyTerm()
|
||||
|| rules.Grade.HasAnyTerm()
|
||||
|| rules.Levels.HasAnyTerm()
|
||||
|| rules.Locations.HasAnyTerm()
|
||||
|| rules.Types.HasAnyTerm()
|
||||
|| (rules.Budget is not null && (rules.Budget.From is not null || rules.Budget.To is not null))
|
||||
|| (rules.Prices is not null && (rules.Prices.From is not null || rules.Prices.To is not null));
|
||||
}
|
||||
|
||||
// Есть ли в списке непустой (после trim) терм.
|
||||
// terms: Список термов группы.
|
||||
// Возвращает: True — хотя бы один терм непустой.
|
||||
private static bool HasAnyTerm(IReadOnlyList<string>? terms)
|
||||
{
|
||||
if (terms is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (string? raw in terms)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(raw))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Совпал ли хотя бы один терм (подстрока в тексте).
|
||||
// lower: Текст в нижнем регистре (очищен от ссылок).
|
||||
// terms: Термы в нижнем регистре.
|
||||
@@ -252,14 +231,4 @@ public static class ColumnMatcher
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Активна ли бюджетная группа: объект есть и не «пустой» (прототип bool(budget) — {} выключен,
|
||||
// {cur} без границ включён, но границ не задаёт — группа совпадает всегда).
|
||||
// budget: Поле budget правил.
|
||||
// Возвращает: True — группа бюджета участвует в матчинге.
|
||||
private static bool HasBudget(BudgetRangeDto? budget)
|
||||
{
|
||||
return budget is not null
|
||||
&& (budget.From is not null || budget.To is not null || !string.IsNullOrWhiteSpace(budget.Cur));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Deal.Modules.Kanban.Application.ColumnRules;
|
||||
|
||||
/// <summary>
|
||||
/// Расширения списков термов правил колонки.
|
||||
/// </summary>
|
||||
internal static class TermListExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Есть ли в списке непустой (после trim) терм.
|
||||
/// </summary>
|
||||
/// <param name="terms">Список термов группы (может быть null).</param>
|
||||
/// <returns>True — хотя бы один терм непустой.</returns>
|
||||
public static bool HasAnyTerm(this IReadOnlyList<string>? terms)
|
||||
{
|
||||
if (terms is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (string? raw in terms)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(raw))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user