feat(formatter): [БЫЛО БЫ DROPPED] header + triggered-rule line in dry-run mode
This commit is contained in:
@@ -43,9 +43,15 @@ final class MessageFormatter
|
|||||||
|
|
||||||
$lines = [];
|
$lines = [];
|
||||||
|
|
||||||
|
$is_dry_run_drop = !empty($ctx['dry_run_drop']);
|
||||||
|
|
||||||
|
if ($is_dry_run_drop) {
|
||||||
|
$header = '[БЫЛО БЫ DROPPED]';
|
||||||
|
} else {
|
||||||
$label_info = self::LABEL_MAP[$class['label']] ?? self::LABEL_MAP['unclear'];
|
$label_info = self::LABEL_MAP[$class['label']] ?? self::LABEL_MAP['unclear'];
|
||||||
$header = ($ctx['is_retro'] ? '📂 Ретроспектива · ' : '')
|
$header = ($ctx['is_retro'] ? '📂 Ретроспектива · ' : '')
|
||||||
. $label_info['emoji'] . ' ' . $label_info['text'];
|
. $label_info['emoji'] . ' ' . $label_info['text'];
|
||||||
|
}
|
||||||
|
|
||||||
$lines[] = $header;
|
$lines[] = $header;
|
||||||
$lines[] = '🌐 ' . esc_html($ctx['site_title']) . ' · форма «' . esc_html($ctx['form_title']) . '»';
|
$lines[] = '🌐 ' . esc_html($ctx['site_title']) . ' · форма «' . esc_html($ctx['form_title']) . '»';
|
||||||
@@ -60,6 +66,18 @@ final class MessageFormatter
|
|||||||
$lines[] = '⚙️ Попало в спам: ' . esc_html($ctx['reason']);
|
$lines[] = '⚙️ Попало в спам: ' . esc_html($ctx['reason']);
|
||||||
$lines[] = '📊 Классификация: ' . self::format_reasons($class['reasons']);
|
$lines[] = '📊 Классификация: ' . self::format_reasons($class['reasons']);
|
||||||
|
|
||||||
|
if ($is_dry_run_drop) {
|
||||||
|
$rule = '';
|
||||||
|
foreach ($class['reasons'] as $r) {
|
||||||
|
$text = (string)($r['text'] ?? '');
|
||||||
|
if (strpos($text, 'hard-rule:') === 0 || strpos($text, 'score ≤') === 0) {
|
||||||
|
$rule = $text;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($rule !== '') $lines[] = '🚫 Сработавшее правило: ' . esc_html($rule);
|
||||||
|
}
|
||||||
|
|
||||||
$meta_bits = [];
|
$meta_bits = [];
|
||||||
if ($ctx['ip'] !== '') $meta_bits[] = 'IP ' . esc_html($ctx['ip']);
|
if ($ctx['ip'] !== '') $meta_bits[] = 'IP ' . esc_html($ctx['ip']);
|
||||||
if ($ctx['user_agent'] !== '') $meta_bits[] = 'UA ' . esc_html(self::shorten_ua($ctx['user_agent']));
|
if ($ctx['user_agent'] !== '') $meta_bits[] = 'UA ' . esc_html(self::shorten_ua($ctx['user_agent']));
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Cf7stg\Tests;
|
||||||
|
|
||||||
|
use Cf7stg\MessageFormatter;
|
||||||
|
|
||||||
|
final class MessageFormatterDryRunTest extends Cf7stgTestCase
|
||||||
|
{
|
||||||
|
private function ctx(array $overrides = []): array
|
||||||
|
{
|
||||||
|
return array_merge([
|
||||||
|
'fields' => ['your-name' => 'OB', 'tel' => '+79991234567'],
|
||||||
|
'classification' => [
|
||||||
|
'score' => 2,
|
||||||
|
'label' => 'drop',
|
||||||
|
'reasons' => [
|
||||||
|
['sign' => '+', 'weight' => 3, 'text' => 'телефон RU'],
|
||||||
|
['sign' => '×', 'weight' => 0, 'text' => 'hard-rule: короткое латинское имя'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'site_title' => 'домработница.рус',
|
||||||
|
'form_title' => 'Test',
|
||||||
|
'submitted_at' => '21.04.2026 11:52',
|
||||||
|
'reason' => 'Akismet',
|
||||||
|
'ip' => '91.188.244.33',
|
||||||
|
'user_agent' => 'Mozilla/5.0',
|
||||||
|
'is_retro' => false,
|
||||||
|
'dry_run_drop' => false,
|
||||||
|
], $overrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_dry_run_drop_prefix_in_first_line(): void
|
||||||
|
{
|
||||||
|
$r = MessageFormatter::build($this->ctx(['dry_run_drop' => true]));
|
||||||
|
$first_line = strtok($r['text'], "\n");
|
||||||
|
self::assertStringContainsString('[БЫЛО БЫ DROPPED]', $first_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_dry_run_drop_includes_triggered_rule_line(): void
|
||||||
|
{
|
||||||
|
$r = MessageFormatter::build($this->ctx(['dry_run_drop' => true]));
|
||||||
|
self::assertStringContainsString('Сработавшее правило: hard-rule: короткое латинское имя', $r['text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_dry_run_drop_includes_score_based_rule_line(): void
|
||||||
|
{
|
||||||
|
$ctx = $this->ctx([
|
||||||
|
'dry_run_drop' => true,
|
||||||
|
'classification' => [
|
||||||
|
'score' => -7,
|
||||||
|
'label' => 'drop',
|
||||||
|
'reasons' => [
|
||||||
|
['sign' => '×', 'weight' => 0, 'text' => 'score ≤ -5'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$r = MessageFormatter::build($ctx);
|
||||||
|
self::assertStringContainsString('Сработавшее правило: score ≤ -5', $r['text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_non_drop_payload_no_marker(): void
|
||||||
|
{
|
||||||
|
$r = MessageFormatter::build($this->ctx(['dry_run_drop' => false]));
|
||||||
|
self::assertStringNotContainsString('[БЫЛО БЫ DROPPED]', $r['text']);
|
||||||
|
self::assertStringNotContainsString('Сработавшее правило', $r['text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_dry_run_drop_header_replaces_label_emoji(): void
|
||||||
|
{
|
||||||
|
// When dry_run_drop is true, the regular ⛔ авто-дроп header must be REPLACED,
|
||||||
|
// not duplicated.
|
||||||
|
$r = MessageFormatter::build($this->ctx(['dry_run_drop' => true]));
|
||||||
|
$first_line = strtok($r['text'], "\n");
|
||||||
|
self::assertStringNotContainsString('авто-дроп', $first_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user