0034531a3a
- Replace date('Y-m-d') with wp_date('Y-m-d') in increment_drop_counter and
default_drop_counters to respect WordPress timezone settings.
- Update corresponding test assertions to use wp_date() for consistency.
- Clarify in docblock that increment_drop_counter is not atomic under concurrent
submissions; read-modify-write pattern via update_option is acceptable for
low-volume dashboard counters.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
175 lines
5.3 KiB
PHP
175 lines
5.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Cf7stg;
|
|
|
|
final class Settings
|
|
{
|
|
public const OPT_BOT_TOKEN = 'cf7stg_bot_token_enc';
|
|
public const OPT_CHAT_ID = 'cf7stg_chat_id';
|
|
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 !== '') {
|
|
return (string)SPAM2TG_BOT_TOKEN;
|
|
}
|
|
$enc = (string)get_option(self::OPT_BOT_TOKEN, '');
|
|
$dec = Crypto::decrypt($enc);
|
|
return $dec ?? '';
|
|
}
|
|
|
|
public static function is_bot_token_constant(): bool
|
|
{
|
|
return defined('SPAM2TG_BOT_TOKEN') && SPAM2TG_BOT_TOKEN !== '';
|
|
}
|
|
|
|
public static function set_bot_token(string $plaintext): void
|
|
{
|
|
update_option(self::OPT_BOT_TOKEN, Crypto::encrypt($plaintext));
|
|
}
|
|
|
|
public static function get_chat_id(): string
|
|
{
|
|
if (defined('SPAM2TG_CHAT_ID') && SPAM2TG_CHAT_ID !== '') {
|
|
return (string)SPAM2TG_CHAT_ID;
|
|
}
|
|
return (string)get_option(self::OPT_CHAT_ID, '');
|
|
}
|
|
|
|
public static function is_chat_id_constant(): bool
|
|
{
|
|
return defined('SPAM2TG_CHAT_ID') && SPAM2TG_CHAT_ID !== '';
|
|
}
|
|
|
|
public static function set_chat_id(string $chat_id): void
|
|
{
|
|
update_option(self::OPT_CHAT_ID, $chat_id);
|
|
}
|
|
|
|
public static function get_site_title(): string
|
|
{
|
|
$override = trim((string)get_option(self::OPT_SITE_TITLE, ''));
|
|
if ($override !== '') return $override;
|
|
$host = parse_url(home_url(), PHP_URL_HOST) ?: '';
|
|
return DomainFormatter::humanize((string)$host);
|
|
}
|
|
|
|
public static function set_site_title(string $title): void
|
|
{
|
|
update_option(self::OPT_SITE_TITLE, trim($title));
|
|
}
|
|
|
|
public static function get_last_test(): array
|
|
{
|
|
$v = get_option(self::OPT_LAST_TEST, []);
|
|
return is_array($v) ? $v : [];
|
|
}
|
|
|
|
public static function set_last_test(array $v): void
|
|
{
|
|
update_option(self::OPT_LAST_TEST, $v);
|
|
}
|
|
|
|
public static function is_configured(): bool
|
|
{
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* Note: not atomic under concurrent CF7 submissions — `update_option` is a
|
|
* read-modify-write. Acceptable for low-volume dashboard counters.
|
|
*/
|
|
public static function increment_drop_counter(string $mode): void
|
|
{
|
|
if (!in_array($mode, ['real', 'dry_run'], true)) return;
|
|
$c = self::get_drop_counters();
|
|
$today = wp_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 = wp_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,
|
|
];
|
|
}
|
|
}
|