feat(settings): silent-drop options + counter with rolling today→yesterday
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,11 @@ final class Settings
|
||||
public const OPT_SITE_TITLE = 'cf7stg_site_title';
|
||||
public const OPT_LAST_TEST = 'cf7stg_last_test';
|
||||
|
||||
public const OPT_DRY_RUN_DROP = 'cf7stg_dry_run_drop';
|
||||
public const OPT_DROP_THRESHOLD = 'cf7stg_drop_score_threshold';
|
||||
public const OPT_HARD_DROP_ENABLED = 'cf7stg_hard_drop_enabled';
|
||||
public const OPT_DROP_COUNTERS = 'cf7stg_drop_counters';
|
||||
|
||||
public static function get_bot_token(): string
|
||||
{
|
||||
if (defined('SPAM2TG_BOT_TOKEN') && SPAM2TG_BOT_TOKEN !== '') {
|
||||
@@ -76,4 +81,91 @@ final class Settings
|
||||
{
|
||||
return self::get_bot_token() !== '' && self::get_chat_id() !== '';
|
||||
}
|
||||
|
||||
public static function is_dry_run_drop(): bool
|
||||
{
|
||||
return (bool)get_option(self::OPT_DRY_RUN_DROP, true);
|
||||
}
|
||||
|
||||
public static function set_dry_run_drop(bool $on): void
|
||||
{
|
||||
update_option(self::OPT_DRY_RUN_DROP, $on);
|
||||
}
|
||||
|
||||
public static function get_drop_score_threshold(): int
|
||||
{
|
||||
return (int)get_option(self::OPT_DROP_THRESHOLD, -5);
|
||||
}
|
||||
|
||||
public static function set_drop_score_threshold(int $v): void
|
||||
{
|
||||
update_option(self::OPT_DROP_THRESHOLD, $v);
|
||||
}
|
||||
|
||||
public static function is_hard_drop_enabled(): bool
|
||||
{
|
||||
return (bool)get_option(self::OPT_HARD_DROP_ENABLED, true);
|
||||
}
|
||||
|
||||
public static function set_hard_drop_enabled(bool $on): void
|
||||
{
|
||||
update_option(self::OPT_HARD_DROP_ENABLED, $on);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{total:int,real_today:int,real_yesterday:int,dry_today:int,dry_yesterday:int,today_date:string,reset_at:string}
|
||||
*/
|
||||
public static function get_drop_counters(): array
|
||||
{
|
||||
$raw = get_option(self::OPT_DROP_COUNTERS, null);
|
||||
if (!is_array($raw) || !isset($raw['total'])) {
|
||||
return self::default_drop_counters();
|
||||
}
|
||||
return array_merge(self::default_drop_counters(), $raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically increments the drop counter. `$mode` must be 'real' or 'dry_run';
|
||||
* any other value is a no-op (defensive — guards against typos in callers).
|
||||
* Performs rolling today→yesterday on date change.
|
||||
*/
|
||||
public static function increment_drop_counter(string $mode): void
|
||||
{
|
||||
if (!in_array($mode, ['real', 'dry_run'], true)) return;
|
||||
$c = self::get_drop_counters();
|
||||
$today = date('Y-m-d');
|
||||
if ($c['today_date'] !== $today) {
|
||||
$c['real_yesterday'] = $c['real_today'];
|
||||
$c['dry_yesterday'] = $c['dry_today'];
|
||||
$c['real_today'] = 0;
|
||||
$c['dry_today'] = 0;
|
||||
$c['today_date'] = $today;
|
||||
}
|
||||
$c['total']++;
|
||||
if ($mode === 'real') {
|
||||
$c['real_today']++;
|
||||
} else {
|
||||
$c['dry_today']++;
|
||||
}
|
||||
update_option(self::OPT_DROP_COUNTERS, $c);
|
||||
}
|
||||
|
||||
public static function reset_drop_counters(): void
|
||||
{
|
||||
update_option(self::OPT_DROP_COUNTERS, self::default_drop_counters());
|
||||
}
|
||||
|
||||
private static function default_drop_counters(): array
|
||||
{
|
||||
$today = date('Y-m-d');
|
||||
return [
|
||||
'total' => 0,
|
||||
'real_today' => 0,
|
||||
'real_yesterday' => 0,
|
||||
'dry_today' => 0,
|
||||
'dry_yesterday' => 0,
|
||||
'today_date' => $today,
|
||||
'reset_at' => $today,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Cf7stg\Tests;
|
||||
|
||||
use Cf7stg\Settings;
|
||||
|
||||
final class SettingsCounterTest extends Cf7stgTestCase
|
||||
{
|
||||
public function test_default_counters_are_zero(): void
|
||||
{
|
||||
$c = Settings::get_drop_counters();
|
||||
self::assertSame(0, $c['total']);
|
||||
self::assertSame(0, $c['real_today']);
|
||||
self::assertSame(0, $c['dry_today']);
|
||||
}
|
||||
|
||||
public function test_increment_real_counter(): void
|
||||
{
|
||||
Settings::increment_drop_counter('real');
|
||||
$c = Settings::get_drop_counters();
|
||||
self::assertSame(1, $c['total']);
|
||||
self::assertSame(1, $c['real_today']);
|
||||
self::assertSame(0, $c['dry_today']);
|
||||
}
|
||||
|
||||
public function test_increment_dry_run_counter(): void
|
||||
{
|
||||
Settings::increment_drop_counter('dry_run');
|
||||
Settings::increment_drop_counter('dry_run');
|
||||
$c = Settings::get_drop_counters();
|
||||
self::assertSame(2, $c['total']);
|
||||
self::assertSame(0, $c['real_today']);
|
||||
self::assertSame(2, $c['dry_today']);
|
||||
}
|
||||
|
||||
public function test_rolling_today_to_yesterday_on_date_change(): void
|
||||
{
|
||||
$yesterday = date('Y-m-d', strtotime('-1 day'));
|
||||
update_option(Settings::OPT_DROP_COUNTERS, [
|
||||
'total' => 5,
|
||||
'real_today' => 5,
|
||||
'real_yesterday' => 0,
|
||||
'dry_today' => 0,
|
||||
'dry_yesterday' => 0,
|
||||
'today_date' => $yesterday,
|
||||
'reset_at' => $yesterday,
|
||||
]);
|
||||
|
||||
Settings::increment_drop_counter('real');
|
||||
$c = Settings::get_drop_counters();
|
||||
self::assertSame(date('Y-m-d'), $c['today_date']);
|
||||
self::assertSame(5, $c['real_yesterday']);
|
||||
self::assertSame(1, $c['real_today']);
|
||||
self::assertSame(6, $c['total']);
|
||||
}
|
||||
|
||||
public function test_reset_counters_zeroes_and_updates_reset_at(): void
|
||||
{
|
||||
Settings::increment_drop_counter('real');
|
||||
Settings::increment_drop_counter('dry_run');
|
||||
Settings::reset_drop_counters();
|
||||
$c = Settings::get_drop_counters();
|
||||
self::assertSame(0, $c['total']);
|
||||
self::assertSame(0, $c['real_today']);
|
||||
self::assertSame(0, $c['dry_today']);
|
||||
self::assertSame(date('Y-m-d'), $c['reset_at']);
|
||||
}
|
||||
|
||||
public function test_get_dry_run_drop_default_true_when_unset(): void
|
||||
{
|
||||
self::assertTrue(Settings::is_dry_run_drop());
|
||||
}
|
||||
|
||||
public function test_get_dry_run_drop_false_when_disabled(): void
|
||||
{
|
||||
update_option(Settings::OPT_DRY_RUN_DROP, false);
|
||||
self::assertFalse(Settings::is_dry_run_drop());
|
||||
}
|
||||
|
||||
public function test_get_drop_score_threshold_default_minus_5(): void
|
||||
{
|
||||
self::assertSame(-5, Settings::get_drop_score_threshold());
|
||||
}
|
||||
|
||||
public function test_get_hard_drop_enabled_default_true(): void
|
||||
{
|
||||
self::assertTrue(Settings::is_hard_drop_enabled());
|
||||
}
|
||||
|
||||
public function test_invalid_counters_option_resets_to_defaults(): void
|
||||
{
|
||||
update_option(Settings::OPT_DROP_COUNTERS, 'broken-string');
|
||||
$c = Settings::get_drop_counters();
|
||||
self::assertSame(0, $c['total']);
|
||||
self::assertArrayHasKey('today_date', $c);
|
||||
}
|
||||
|
||||
public function test_increment_with_invalid_mode_is_noop(): void
|
||||
{
|
||||
Settings::increment_drop_counter('garbage');
|
||||
$c = Settings::get_drop_counters();
|
||||
self::assertSame(0, $c['total']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user