feat: implement global autoresponder plugin
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
final class Settings
|
||||
{
|
||||
public const BASE_DIR = '/usr/local/hitme_plugins/global-autoresponders';
|
||||
public const CONFIG_DIR = self::BASE_DIR . '/config';
|
||||
public const DATA_DIR = self::BASE_DIR . '/data';
|
||||
public const STATE_DIR = self::BASE_DIR . '/state';
|
||||
public const LOG_DIR = self::BASE_DIR . '/logs';
|
||||
public const AUDIT_LOG = self::LOG_DIR . '/audit.log';
|
||||
public const EXTERNAL_SETTINGS = self::CONFIG_DIR . '/plugin-settings.conf';
|
||||
|
||||
/** @var array<string,string> */
|
||||
private array $values;
|
||||
|
||||
/**
|
||||
* @param array<string,string> $values
|
||||
*/
|
||||
private function __construct(array $values)
|
||||
{
|
||||
$this->values = $values;
|
||||
$this->validate();
|
||||
}
|
||||
|
||||
public static function load(string $path): self
|
||||
{
|
||||
$values = self::defaults();
|
||||
if (is_file($path)) {
|
||||
$lines = file($path, FILE_IGNORE_NEW_LINES);
|
||||
if ($lines !== false) {
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
if ($line === '' || str_starts_with($line, '#') || !str_contains($line, '=')) {
|
||||
continue;
|
||||
}
|
||||
[$key, $value] = explode('=', $line, 2);
|
||||
$values[trim($key)] = trim($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new self($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public static function defaults(): array
|
||||
{
|
||||
return [
|
||||
'DEFAULT_PLUGIN_LANGUAGE' => 'en',
|
||||
'DEFAULT_ENABLE' => 'true',
|
||||
'GLOBAL_AUTORESPONDER_TIMEZONE' => 'Europe/Warsaw',
|
||||
'GLOBAL_AUTORESPONDER_SCHEDULE_MODE' => 'exact_hour',
|
||||
'GLOBAL_AUTORESPONDER_REPLY_EVERY_MESSAGE' => 'false',
|
||||
'GLOBAL_AUTORESPONDER_REPEAT_MINUTES' => '1440',
|
||||
'GLOBAL_AUTORESPONDER_DYNAMIC_MAILBOX_SCOPE' => 'true',
|
||||
'GLOBAL_AUTORESPONDER_MAX_SUBJECT_BYTES' => '255',
|
||||
'GLOBAL_AUTORESPONDER_MAX_BODY_BYTES' => '20000',
|
||||
];
|
||||
}
|
||||
|
||||
public function getString(string $key, string $default = ''): string
|
||||
{
|
||||
return $this->values[$key] ?? $default;
|
||||
}
|
||||
|
||||
public function getBool(string $key, bool $default = false): bool
|
||||
{
|
||||
$raw = strtolower($this->getString($key, $default ? 'true' : 'false'));
|
||||
return in_array($raw, ['1', 'true', 'yes', 'on'], true);
|
||||
}
|
||||
|
||||
public function getInt(string $key, int $default): int
|
||||
{
|
||||
$raw = $this->getString($key, (string)$default);
|
||||
return preg_match('/^-?[0-9]+$/', $raw) ? (int)$raw : $default;
|
||||
}
|
||||
|
||||
public function defaultLanguage(): string
|
||||
{
|
||||
$lang = strtolower($this->getString('DEFAULT_PLUGIN_LANGUAGE', 'en'));
|
||||
return preg_match('/^[a-z]{2}$/', $lang) ? $lang : 'en';
|
||||
}
|
||||
|
||||
public function defaultEnable(): bool
|
||||
{
|
||||
return $this->getBool('DEFAULT_ENABLE', true);
|
||||
}
|
||||
|
||||
public function timezone(): string
|
||||
{
|
||||
return $this->getString('GLOBAL_AUTORESPONDER_TIMEZONE', 'Europe/Warsaw');
|
||||
}
|
||||
|
||||
public function scheduleMode(): string
|
||||
{
|
||||
return $this->getString('GLOBAL_AUTORESPONDER_SCHEDULE_MODE', 'exact_hour');
|
||||
}
|
||||
|
||||
public function replyEveryMessage(): bool
|
||||
{
|
||||
return $this->getBool('GLOBAL_AUTORESPONDER_REPLY_EVERY_MESSAGE', false);
|
||||
}
|
||||
|
||||
public function repeatMinutes(): int
|
||||
{
|
||||
return $this->getInt('GLOBAL_AUTORESPONDER_REPEAT_MINUTES', 1440);
|
||||
}
|
||||
|
||||
public function dynamicMailboxScope(): bool
|
||||
{
|
||||
return $this->getBool('GLOBAL_AUTORESPONDER_DYNAMIC_MAILBOX_SCOPE', true);
|
||||
}
|
||||
|
||||
public function maxSubjectBytes(): int
|
||||
{
|
||||
return $this->getInt('GLOBAL_AUTORESPONDER_MAX_SUBJECT_BYTES', 255);
|
||||
}
|
||||
|
||||
public function maxBodyBytes(): int
|
||||
{
|
||||
return $this->getInt('GLOBAL_AUTORESPONDER_MAX_BODY_BYTES', 20000);
|
||||
}
|
||||
|
||||
public function loadOrCreateSecret(string $path = self::CONFIG_DIR . '/secret.key'): string
|
||||
{
|
||||
if (is_file($path)) {
|
||||
$secret = trim((string)file_get_contents($path));
|
||||
if ($secret !== '') {
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
$dir = dirname($path);
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0700, true);
|
||||
}
|
||||
$secret = bin2hex(random_bytes(32));
|
||||
file_put_contents($path, $secret . "\n", LOCK_EX);
|
||||
@chmod($path, 0600);
|
||||
return $secret;
|
||||
}
|
||||
|
||||
private function validate(): void
|
||||
{
|
||||
try {
|
||||
new DateTimeZone($this->timezone());
|
||||
} catch (Throwable) {
|
||||
throw new InvalidArgumentException('Invalid timezone: ' . $this->timezone());
|
||||
}
|
||||
if (!in_array($this->scheduleMode(), ['exact_hour', 'directadmin_period'], true)) {
|
||||
throw new InvalidArgumentException('Invalid schedule mode: ' . $this->scheduleMode());
|
||||
}
|
||||
if ($this->repeatMinutes() < 0) {
|
||||
throw new InvalidArgumentException('Invalid repeat minutes');
|
||||
}
|
||||
if ($this->maxSubjectBytes() < 1 || $this->maxBodyBytes() < 1) {
|
||||
throw new InvalidArgumentException('Invalid size limits');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user