fix: match directadmin vacation controls
This commit is contained in:
@@ -6,7 +6,7 @@ function render_rule_form(AppContext $ctx, string $mode, ?array $rule): string
|
|||||||
$isUpdate = $mode === 'update';
|
$isUpdate = $mode === 'update';
|
||||||
$id = $isUpdate ? (string)$rule['id'] : '';
|
$id = $isUpdate ? (string)$rule['id'] : '';
|
||||||
$subjectPrefix = $rule['subject_prefix'] ?? $rule['subject'] ?? '';
|
$subjectPrefix = $rule['subject_prefix'] ?? $rule['subject'] ?? '';
|
||||||
$replyFrequency = selected_reply_frequency($rule);
|
$replyFrequency = selected_reply_frequency($ctx, $rule);
|
||||||
$body = $rule['body'] ?? '';
|
$body = $rule['body'] ?? '';
|
||||||
$enabled = $rule === null || !empty($rule['enabled']);
|
$enabled = $rule === null || !empty($rule['enabled']);
|
||||||
$startValue = (string)($rule['start_value'] ?? default_schedule_value($ctx, true));
|
$startValue = (string)($rule['start_value'] ?? default_schedule_value($ctx, true));
|
||||||
@@ -30,29 +30,43 @@ function render_rule_form(AppContext $ctx, string $mode, ?array $rule): string
|
|||||||
function default_schedule_value(AppContext $ctx, bool $start): string
|
function default_schedule_value(AppContext $ctx, bool $start): string
|
||||||
{
|
{
|
||||||
$today = new DateTimeImmutable('today', new DateTimeZone($ctx->settings->timezone()));
|
$today = new DateTimeImmutable('today', new DateTimeZone($ctx->settings->timezone()));
|
||||||
if ($ctx->settings->scheduleMode() === 'directadmin_period') {
|
return $today->format('Y-m-d') . 'T' . ($start ? '00:00' : '23:59');
|
||||||
return $today->format('Y-m-d') . '|' . ($start ? 'morning' : 'evening');
|
|
||||||
}
|
|
||||||
return $today->format('Y-m-d') . 'T' . ($start ? '09:00' : '17:00');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param array<string,mixed>|null $rule */
|
/** @param array<string,mixed>|null $rule */
|
||||||
function selected_reply_frequency(?array $rule): string
|
function selected_reply_frequency(AppContext $ctx, ?array $rule): string
|
||||||
{
|
{
|
||||||
if ($rule === null) {
|
if ($rule === null) {
|
||||||
return '1440';
|
return '1440';
|
||||||
}
|
}
|
||||||
if (!empty($rule['reply_every_message'])) {
|
if (!empty($rule['reply_every_message'])) {
|
||||||
return 'every';
|
return $ctx->settings->backendMode() === 'da' ? '1' : 'every';
|
||||||
}
|
}
|
||||||
$minutes = (string)(int)($rule['repeat_minutes'] ?? 1440);
|
$minutes = (string)(int)($rule['repeat_minutes'] ?? 1440);
|
||||||
return in_array($minutes, ['30', '60', '120', '360', '720', '1440', '2880', '10080'], true) ? $minutes : '1440';
|
return array_key_exists($minutes, reply_frequency_options($ctx)) ? $minutes : '1440';
|
||||||
}
|
}
|
||||||
|
|
||||||
function render_reply_frequency_select(AppContext $ctx, string $selected): string
|
function render_reply_frequency_select(AppContext $ctx, string $selected): string
|
||||||
{
|
{
|
||||||
$options = [
|
$options = reply_frequency_options($ctx);
|
||||||
'every' => 'Send automatic reply for every message',
|
$html = '<select name="reply_frequency">';
|
||||||
|
foreach ($options as $value => $label) {
|
||||||
|
$value = (string)$value;
|
||||||
|
$html .= '<option value="' . AppContext::e($value) . '"' . ($selected === $value ? ' selected' : '') . '>' . AppContext::e($ctx->t($label)) . '</option>';
|
||||||
|
}
|
||||||
|
return $html . '</select>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array<string,string> */
|
||||||
|
function reply_frequency_options(AppContext $ctx): array
|
||||||
|
{
|
||||||
|
$options = [];
|
||||||
|
if ($ctx->settings->backendMode() !== 'da') {
|
||||||
|
$options['every'] = 'Send automatic reply for every message';
|
||||||
|
}
|
||||||
|
return $options + [
|
||||||
|
'1' => '1 minute',
|
||||||
|
'10' => '10 minutes',
|
||||||
'30' => '30 minutes',
|
'30' => '30 minutes',
|
||||||
'60' => '1 hour',
|
'60' => '1 hour',
|
||||||
'120' => '2 hours',
|
'120' => '2 hours',
|
||||||
@@ -60,14 +74,19 @@ function render_reply_frequency_select(AppContext $ctx, string $selected): strin
|
|||||||
'720' => '12 hours',
|
'720' => '12 hours',
|
||||||
'1440' => '1 day',
|
'1440' => '1 day',
|
||||||
'2880' => '2 days',
|
'2880' => '2 days',
|
||||||
|
'4320' => '3 days',
|
||||||
|
'5760' => '4 days',
|
||||||
|
'7200' => '5 days',
|
||||||
|
'8640' => '6 days',
|
||||||
'10080' => '7 days',
|
'10080' => '7 days',
|
||||||
|
'11520' => '8 days',
|
||||||
|
'12960' => '9 days',
|
||||||
|
'14400' => '10 days',
|
||||||
|
'15840' => '11 days',
|
||||||
|
'17280' => '12 days',
|
||||||
|
'18720' => '13 days',
|
||||||
|
'20160' => '14 days',
|
||||||
];
|
];
|
||||||
$html = '<select name="reply_frequency">';
|
|
||||||
foreach ($options as $value => $label) {
|
|
||||||
$value = (string)$value;
|
|
||||||
$html .= '<option value="' . AppContext::e($value) . '"' . ($selected === $value ? ' selected' : '') . '>' . AppContext::e($ctx->t($label)) . '</option>';
|
|
||||||
}
|
|
||||||
return $html . '</select>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param array<string,mixed> $post @return array<string,mixed> */
|
/** @param array<string,mixed> $post @return array<string,mixed> */
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ return static function (AppContext $ctx): void {
|
|||||||
$rows .= '<tr><td><span class="badge ' . ($enabled ? 'ok' : 'off') . '">' . AppContext::e($ctx->t($enabled ? 'Enabled' : 'Disabled')) . '</span></td>';
|
$rows .= '<tr><td><span class="badge ' . ($enabled ? 'ok' : 'off') . '">' . AppContext::e($ctx->t($enabled ? 'Enabled' : 'Disabled')) . '</span></td>';
|
||||||
$rows .= '<td>' . AppContext::e($subjectPrefix) . '<br><span class="muted">' . date('Y-m-d H:i', (int)($rule['updated_at'] ?? time())) . '</span></td>';
|
$rows .= '<td>' . AppContext::e($subjectPrefix) . '<br><span class="muted">' . date('Y-m-d H:i', (int)($rule['updated_at'] ?? time())) . '</span></td>';
|
||||||
$rows .= '<td>' . AppContext::e(date('Y-m-d H:i', (int)$rule['start_ts'])) . '<br><span class="muted">' . AppContext::e($ctx->t('To')) . ' ' . AppContext::e(date('Y-m-d H:i', (int)$rule['end_ts'])) . '</span></td>';
|
$rows .= '<td>' . AppContext::e(date('Y-m-d H:i', (int)$rule['start_ts'])) . '<br><span class="muted">' . AppContext::e($ctx->t('To')) . ' ' . AppContext::e(date('Y-m-d H:i', (int)$rule['end_ts'])) . '</span></td>';
|
||||||
$rows .= '<td>' . AppContext::e($ctx->t($rule['dynamic_scope'] ? 'Dynamic' : 'Snapshot')) . '</td><td><span class="table-actions">';
|
$rows .= '<td><span class="table-actions">';
|
||||||
$rows .= '<a class="btn" href="' . AppContext::e($ctx->url('update.html', ['id' => $id])) . '">' . AppContext::e($ctx->t('Edit')) . '</a>';
|
$rows .= '<a class="btn" href="' . AppContext::e($ctx->url('update.html', ['id' => $id])) . '">' . AppContext::e($ctx->t('Edit')) . '</a>';
|
||||||
$rows .= '<a class="btn" href="' . AppContext::e($ctx->url('preview.html', ['id' => $id])) . '">' . AppContext::e($ctx->t('Preview')) . '</a>';
|
$rows .= '<a class="btn" href="' . AppContext::e($ctx->url('preview.html', ['id' => $id])) . '">' . AppContext::e($ctx->t('Preview')) . '</a>';
|
||||||
$rows .= '<form method="post" action="' . AppContext::e($ctx->url('toggle.html')) . '">' . $ctx->csrfField('toggle:' . $id) . '<input type="hidden" name="id" value="' . AppContext::e($id) . '"><button>' . AppContext::e($ctx->t($enabled ? 'Disable' : 'Enable')) . '</button></form>';
|
$rows .= '<form method="post" action="' . AppContext::e($ctx->url('toggle.html')) . '">' . $ctx->csrfField('toggle:' . $id) . '<input type="hidden" name="id" value="' . AppContext::e($id) . '"><button>' . AppContext::e($ctx->t($enabled ? 'Disable' : 'Enable')) . '</button></form>';
|
||||||
@@ -36,6 +36,6 @@ return static function (AppContext $ctx): void {
|
|||||||
|
|
||||||
$body = '<div class="panel"><div class="panel-head"><div><h3>' . AppContext::e($ctx->t('Global autoresponders')) . '</h3><p class="muted">' . AppContext::e($ctx->t('All valid POP/IMAP mailboxes in this account')) . '</p></div>' .
|
$body = '<div class="panel"><div class="panel-head"><div><h3>' . AppContext::e($ctx->t('Global autoresponders')) . '</h3><p class="muted">' . AppContext::e($ctx->t('All valid POP/IMAP mailboxes in this account')) . '</p></div>' .
|
||||||
'<a class="btn amber" href="' . AppContext::e($ctx->url('create.html')) . '">' . AppContext::e($ctx->t('Add autoresponder')) . '</a></div>' .
|
'<a class="btn amber" href="' . AppContext::e($ctx->url('create.html')) . '">' . AppContext::e($ctx->t('Add autoresponder')) . '</a></div>' .
|
||||||
'<table><thead><tr><th>' . AppContext::e($ctx->t('Status')) . '</th><th>' . AppContext::e($ctx->t('Subject prefix')) . '</th><th>' . AppContext::e($ctx->t('Sending period')) . '</th><th>' . AppContext::e($ctx->t('Scope')) . '</th><th>' . AppContext::e($ctx->t('Actions')) . '</th></tr></thead><tbody>' . $rows . '</tbody></table></div>';
|
'<table><thead><tr><th>' . AppContext::e($ctx->t('Status')) . '</th><th>' . AppContext::e($ctx->t('Subject prefix')) . '</th><th>' . AppContext::e($ctx->t('Sending period')) . '</th><th>' . AppContext::e($ctx->t('Actions')) . '</th></tr></thead><tbody>' . $rows . '</tbody></table></div>';
|
||||||
$ctx->render('Global autoresponders', $body, $ok);
|
$ctx->render('Global autoresponders', $body, $ok);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ class DirectAdminVacationApi
|
|||||||
throw new InvalidArgumentException('Invalid mailbox email');
|
throw new InvalidArgumentException('Invalid mailbox email');
|
||||||
}
|
}
|
||||||
[$local, $domain] = explode('@', strtolower($email), 2);
|
[$local, $domain] = explode('@', strtolower($email), 2);
|
||||||
[$startDate, $startTime] = $this->splitPeriod((string)($rule['start_value'] ?? ''));
|
[$startDate, $startTime] = $this->splitScheduleValue((string)($rule['start_value'] ?? ''), true);
|
||||||
[$endDate, $endTime] = $this->splitPeriod((string)($rule['end_value'] ?? ''));
|
[$endDate, $endTime] = $this->splitScheduleValue((string)($rule['end_value'] ?? ''), false);
|
||||||
[$startYear, $startMonth, $startDay] = explode('-', $startDate);
|
[$startYear, $startMonth, $startDay] = explode('-', $startDate);
|
||||||
[$endYear, $endMonth, $endDay] = explode('-', $endDate);
|
[$endYear, $endMonth, $endDay] = explode('-', $endDate);
|
||||||
$subjectPrefix = (string)($rule['subject_prefix'] ?? $rule['subject'] ?? '');
|
$subjectPrefix = (string)($rule['subject_prefix'] ?? $rule['subject'] ?? '');
|
||||||
@@ -108,12 +108,16 @@ class DirectAdminVacationApi
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{0:string,1:string} */
|
/** @return array{0:string,1:string} */
|
||||||
private function splitPeriod(string $value): array
|
private function splitScheduleValue(string $value, bool $start): array
|
||||||
{
|
{
|
||||||
if (!preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2})\|(morning|afternoon|evening)$/', $value, $m)) {
|
if (preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2})T([0-9]{2}:[0-9]{2})$/', $value, $m)) {
|
||||||
throw new InvalidArgumentException('DirectAdmin API backend requires directadmin_period values');
|
return [$m[1], $m[2]];
|
||||||
}
|
}
|
||||||
return [$m[1], $m[2]];
|
if (!preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2})\|(morning|afternoon|evening)$/', $value, $m)) {
|
||||||
|
throw new InvalidArgumentException('DirectAdmin API backend requires exact date-time values');
|
||||||
|
}
|
||||||
|
$time = ['morning' => '08:00', 'afternoon' => '13:00', 'evening' => $start ? '18:00' : '23:59'][$m[2]];
|
||||||
|
return [$m[1], $time];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param array<string,string> $payload */
|
/** @param array<string,string> $payload */
|
||||||
@@ -144,9 +148,11 @@ class DirectAdminVacationApi
|
|||||||
private function replyOnceTime(array $rule): string
|
private function replyOnceTime(array $rule): string
|
||||||
{
|
{
|
||||||
if (!empty($rule['reply_every_message'])) {
|
if (!empty($rule['reply_every_message'])) {
|
||||||
return '0';
|
return '1m';
|
||||||
}
|
}
|
||||||
return match ((int)($rule['repeat_minutes'] ?? 1440)) {
|
return match ((int)($rule['repeat_minutes'] ?? 1440)) {
|
||||||
|
1 => '1m',
|
||||||
|
10 => '10m',
|
||||||
30 => '30m',
|
30 => '30m',
|
||||||
60 => '1h',
|
60 => '1h',
|
||||||
120 => '2h',
|
120 => '2h',
|
||||||
@@ -154,7 +160,18 @@ class DirectAdminVacationApi
|
|||||||
720 => '12h',
|
720 => '12h',
|
||||||
1440 => '1d',
|
1440 => '1d',
|
||||||
2880 => '2d',
|
2880 => '2d',
|
||||||
|
4320 => '3d',
|
||||||
|
5760 => '4d',
|
||||||
|
7200 => '5d',
|
||||||
|
8640 => '6d',
|
||||||
10080 => '1w',
|
10080 => '1w',
|
||||||
|
11520 => '8d',
|
||||||
|
12960 => '9d',
|
||||||
|
14400 => '10d',
|
||||||
|
15840 => '11d',
|
||||||
|
17280 => '12d',
|
||||||
|
18720 => '13d',
|
||||||
|
20160 => '14d',
|
||||||
default => '1d',
|
default => '1d',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ final class RuleValidator
|
|||||||
{
|
{
|
||||||
/** @var array<string,int> */
|
/** @var array<string,int> */
|
||||||
private const REPLY_FREQUENCIES = [
|
private const REPLY_FREQUENCIES = [
|
||||||
|
'1' => 1,
|
||||||
|
'10' => 10,
|
||||||
'30' => 30,
|
'30' => 30,
|
||||||
'60' => 60,
|
'60' => 60,
|
||||||
'120' => 120,
|
'120' => 120,
|
||||||
@@ -12,7 +14,18 @@ final class RuleValidator
|
|||||||
'720' => 720,
|
'720' => 720,
|
||||||
'1440' => 1440,
|
'1440' => 1440,
|
||||||
'2880' => 2880,
|
'2880' => 2880,
|
||||||
|
'4320' => 4320,
|
||||||
|
'5760' => 5760,
|
||||||
|
'7200' => 7200,
|
||||||
|
'8640' => 8640,
|
||||||
'10080' => 10080,
|
'10080' => 10080,
|
||||||
|
'11520' => 11520,
|
||||||
|
'12960' => 12960,
|
||||||
|
'14400' => 14400,
|
||||||
|
'15840' => 15840,
|
||||||
|
'17280' => 17280,
|
||||||
|
'18720' => 18720,
|
||||||
|
'20160' => 20160,
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @param array<string,mixed> $input @return array<string,mixed> */
|
/** @param array<string,mixed> $input @return array<string,mixed> */
|
||||||
@@ -45,7 +58,7 @@ final class RuleValidator
|
|||||||
if ($endTs <= $startTs) {
|
if ($endTs <= $startTs) {
|
||||||
throw new InvalidArgumentException('Data zakończenia musi być późniejsza niż data rozpoczęcia.');
|
throw new InvalidArgumentException('Data zakończenia musi być późniejsza niż data rozpoczęcia.');
|
||||||
}
|
}
|
||||||
[$replyEveryMessage, $repeatMinutes] = self::parseReplyFrequency((string)($input['reply_frequency'] ?? '1440'));
|
[$replyEveryMessage, $repeatMinutes] = self::parseReplyFrequency((string)($input['reply_frequency'] ?? '1440'), $settings);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'subject_prefix' => $subjectPrefix,
|
'subject_prefix' => $subjectPrefix,
|
||||||
@@ -64,10 +77,13 @@ final class RuleValidator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{0:bool,1:int} */
|
/** @return array{0:bool,1:int} */
|
||||||
private static function parseReplyFrequency(string $value): array
|
private static function parseReplyFrequency(string $value, Settings $settings): array
|
||||||
{
|
{
|
||||||
$value = trim(strtolower($value));
|
$value = trim(strtolower($value));
|
||||||
if ($value === 'every') {
|
if ($value === 'every') {
|
||||||
|
if ($settings->backendMode() === 'da') {
|
||||||
|
throw new InvalidArgumentException('Częstość odpowiedzi jest nieprawidłowa.');
|
||||||
|
}
|
||||||
return [true, 0];
|
return [true, 0];
|
||||||
}
|
}
|
||||||
if (isset(self::REPLY_FREQUENCIES[$value])) {
|
if (isset(self::REPLY_FREQUENCIES[$value])) {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ final class Settings
|
|||||||
|
|
||||||
public function scheduleMode(): string
|
public function scheduleMode(): string
|
||||||
{
|
{
|
||||||
return $this->backendMode() === 'da' ? 'directadmin_period' : 'exact_hour';
|
return 'exact_hour';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dynamicMailboxScope(): bool
|
public function dynamicMailboxScope(): bool
|
||||||
|
|||||||
+13
@@ -17,6 +17,8 @@ return [
|
|||||||
'Response content' => 'Response content',
|
'Response content' => 'Response content',
|
||||||
'Response frequency' => 'Response frequency',
|
'Response frequency' => 'Response frequency',
|
||||||
'Send automatic reply for every message' => 'Send automatic reply for every message',
|
'Send automatic reply for every message' => 'Send automatic reply for every message',
|
||||||
|
'1 minute' => '1 minute',
|
||||||
|
'10 minutes' => '10 minutes',
|
||||||
'30 minutes' => '30 minutes',
|
'30 minutes' => '30 minutes',
|
||||||
'1 hour' => '1 hour',
|
'1 hour' => '1 hour',
|
||||||
'2 hours' => '2 hours',
|
'2 hours' => '2 hours',
|
||||||
@@ -24,7 +26,18 @@ return [
|
|||||||
'12 hours' => '12 hours',
|
'12 hours' => '12 hours',
|
||||||
'1 day' => '1 day',
|
'1 day' => '1 day',
|
||||||
'2 days' => '2 days',
|
'2 days' => '2 days',
|
||||||
|
'3 days' => '3 days',
|
||||||
|
'4 days' => '4 days',
|
||||||
|
'5 days' => '5 days',
|
||||||
|
'6 days' => '6 days',
|
||||||
'7 days' => '7 days',
|
'7 days' => '7 days',
|
||||||
|
'8 days' => '8 days',
|
||||||
|
'9 days' => '9 days',
|
||||||
|
'10 days' => '10 days',
|
||||||
|
'11 days' => '11 days',
|
||||||
|
'12 days' => '12 days',
|
||||||
|
'13 days' => '13 days',
|
||||||
|
'14 days' => '14 days',
|
||||||
'Status' => 'Status',
|
'Status' => 'Status',
|
||||||
'Enabled' => 'Enabled',
|
'Enabled' => 'Enabled',
|
||||||
'Disabled' => 'Disabled',
|
'Disabled' => 'Disabled',
|
||||||
|
|||||||
+13
@@ -17,6 +17,8 @@ return [
|
|||||||
'Response content' => 'Treść odpowiedzi',
|
'Response content' => 'Treść odpowiedzi',
|
||||||
'Response frequency' => 'Częstość odpowiedzi',
|
'Response frequency' => 'Częstość odpowiedzi',
|
||||||
'Send automatic reply for every message' => 'Wysyłaj automatyczną odpowiedź dla każdej wiadomości',
|
'Send automatic reply for every message' => 'Wysyłaj automatyczną odpowiedź dla każdej wiadomości',
|
||||||
|
'1 minute' => '1 minuta',
|
||||||
|
'10 minutes' => '10 minut',
|
||||||
'30 minutes' => '30 minut',
|
'30 minutes' => '30 minut',
|
||||||
'1 hour' => '1 godzina',
|
'1 hour' => '1 godzina',
|
||||||
'2 hours' => '2 godziny',
|
'2 hours' => '2 godziny',
|
||||||
@@ -24,7 +26,18 @@ return [
|
|||||||
'12 hours' => '12 godzin',
|
'12 hours' => '12 godzin',
|
||||||
'1 day' => '1 dzień',
|
'1 day' => '1 dzień',
|
||||||
'2 days' => '2 dni',
|
'2 days' => '2 dni',
|
||||||
|
'3 days' => '3 dni',
|
||||||
|
'4 days' => '4 dni',
|
||||||
|
'5 days' => '5 dni',
|
||||||
|
'6 days' => '6 dni',
|
||||||
'7 days' => '7 dni',
|
'7 days' => '7 dni',
|
||||||
|
'8 days' => '8 dni',
|
||||||
|
'9 days' => '9 dni',
|
||||||
|
'10 days' => '10 dni',
|
||||||
|
'11 days' => '11 dni',
|
||||||
|
'12 days' => '12 dni',
|
||||||
|
'13 days' => '13 dni',
|
||||||
|
'14 days' => '14 dni',
|
||||||
'Status' => 'Status',
|
'Status' => 'Status',
|
||||||
'Enabled' => 'Włączony',
|
'Enabled' => 'Włączony',
|
||||||
'Disabled' => 'Wyłączony',
|
'Disabled' => 'Wyłączony',
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ name=global-autoresponder
|
|||||||
id=global-autoresponder
|
id=global-autoresponder
|
||||||
type=user
|
type=user
|
||||||
author=HITME.PL
|
author=HITME.PL
|
||||||
version=1.1.4
|
version=1.1.5
|
||||||
active=no
|
active=no
|
||||||
installed=no
|
installed=no
|
||||||
user_run_as=root
|
user_run_as=root
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ test('backend mode derives schedule mode', function (): void {
|
|||||||
test_write($path, "GLOBAL_AUTORESPONDER_BACKEND=da\n");
|
test_write($path, "GLOBAL_AUTORESPONDER_BACKEND=da\n");
|
||||||
$settings = Settings::load($path);
|
$settings = Settings::load($path);
|
||||||
assert_same('da', $settings->backendMode());
|
assert_same('da', $settings->backendMode());
|
||||||
assert_same('directadmin_period', $settings->scheduleMode());
|
assert_same('exact_hour', $settings->scheduleMode());
|
||||||
|
|
||||||
test_write($path, "GLOBAL_AUTORESPONDER_BACKEND=exim\n");
|
test_write($path, "GLOBAL_AUTORESPONDER_BACKEND=exim\n");
|
||||||
$settings = Settings::load($path);
|
$settings = Settings::load($path);
|
||||||
|
|||||||
@@ -13,22 +13,36 @@ test('directadmin vacation api builds scoped payload for one mailbox', function
|
|||||||
$payload = $api->buildSavePayload('info@example.com', [
|
$payload = $api->buildSavePayload('info@example.com', [
|
||||||
'subject_prefix' => 'Urlop',
|
'subject_prefix' => 'Urlop',
|
||||||
'reply_every_message' => false,
|
'reply_every_message' => false,
|
||||||
'repeat_minutes' => 1440,
|
'repeat_minutes' => 1,
|
||||||
'body' => 'Body',
|
'body' => 'Body',
|
||||||
'start_value' => '2026-06-10|morning',
|
'start_value' => '2026-06-10T00:00',
|
||||||
'end_value' => '2026-06-24|evening',
|
'end_value' => '2026-06-24T23:59',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_same('info', $payload['user']);
|
assert_same('info', $payload['user']);
|
||||||
assert_same('example.com', $payload['domain']);
|
assert_same('example.com', $payload['domain']);
|
||||||
assert_same('Body', $payload['text']);
|
assert_same('Body', $payload['text']);
|
||||||
assert_same('Urlop', $payload['subject']);
|
assert_same('Urlop', $payload['subject']);
|
||||||
assert_same('1d', $payload['reply_once_time']);
|
assert_same('1m', $payload['reply_once_time']);
|
||||||
assert_false(isset($payload['email']));
|
assert_false(isset($payload['email']));
|
||||||
assert_false(isset($payload['subject_prefix']));
|
assert_false(isset($payload['subject_prefix']));
|
||||||
assert_false(isset($payload['reply_frequency']));
|
assert_false(isset($payload['reply_frequency']));
|
||||||
assert_same('morning', $payload['starttime']);
|
assert_same('00:00', $payload['starttime']);
|
||||||
assert_same('evening', $payload['endtime']);
|
assert_same('23:59', $payload['endtime']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('directadmin vacation api maps every-message legacy rules to one minute minimum', function (): void {
|
||||||
|
$api = new DirectAdminVacationApi('/usr/local/directadmin/directadmin');
|
||||||
|
$payload = $api->buildSavePayload('info@example.com', [
|
||||||
|
'subject_prefix' => 'Urlop',
|
||||||
|
'reply_every_message' => true,
|
||||||
|
'repeat_minutes' => 0,
|
||||||
|
'body' => 'Body',
|
||||||
|
'start_value' => '2026-06-10T00:00',
|
||||||
|
'end_value' => '2026-06-24T23:59',
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_same('1m', $payload['reply_once_time']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('directadmin vacation api reports http error response bodies', function (): void {
|
test('directadmin vacation api reports http error response bodies', function (): void {
|
||||||
|
|||||||
+18
-8
@@ -59,11 +59,12 @@ test('rule form uses minute time input and no summary box in exim mode', functio
|
|||||||
assert_contains(': pierwotny temat', $html);
|
assert_contains(': pierwotny temat', $html);
|
||||||
assert_contains('Częstość odpowiedzi', $html);
|
assert_contains('Częstość odpowiedzi', $html);
|
||||||
assert_contains('Wysyłaj automatyczną odpowiedź dla każdej wiadomości', $html);
|
assert_contains('Wysyłaj automatyczną odpowiedź dla każdej wiadomości', $html);
|
||||||
|
assert_contains('14 dni', $html);
|
||||||
assert_contains('1 dzień', $html);
|
assert_contains('1 dzień', $html);
|
||||||
assert_contains('Treść wiadomości', $html);
|
assert_contains('Treść wiadomości', $html);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rule form uses native period selector in da mode', function (): void {
|
test('rule form uses exact hour selector and directadmin frequency range in da mode', function (): void {
|
||||||
$settingsPath = TEST_TMP . '/form-da.conf';
|
$settingsPath = TEST_TMP . '/form-da.conf';
|
||||||
test_write($settingsPath, "DEFAULT_PLUGIN_LANGUAGE=pl\nGLOBAL_AUTORESPONDER_BACKEND=da\n");
|
test_write($settingsPath, "DEFAULT_PLUGIN_LANGUAGE=pl\nGLOBAL_AUTORESPONDER_BACKEND=da\n");
|
||||||
$settings = Settings::load($settingsPath);
|
$settings = Settings::load($settingsPath);
|
||||||
@@ -76,9 +77,18 @@ test('rule form uses native period selector in da mode', function (): void {
|
|||||||
new AuditLog(TEST_TMP . '/audit.log')
|
new AuditLog(TEST_TMP . '/audit.log')
|
||||||
);
|
);
|
||||||
$html = render_rule_form($ctx, 'create', null);
|
$html = render_rule_form($ctx, 'create', null);
|
||||||
assert_contains('name="start_value_period"', $html);
|
assert_contains('type="time"', $html);
|
||||||
assert_contains('Rano', $html);
|
assert_contains('step="60"', $html);
|
||||||
assert_false(strpos($html, 'type="time"') !== false);
|
assert_contains('1 minuta', $html);
|
||||||
|
assert_contains('14 dni', $html);
|
||||||
|
assert_false(strpos($html, 'Wysyłaj automatyczną odpowiedź dla każdej wiadomości') !== false);
|
||||||
|
assert_false(strpos($html, 'name="start_value_period"') !== false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('autoresponder table does not expose mailbox scope column', function (): void {
|
||||||
|
$source = file_get_contents(PLUGIN_ROOT . '/exec/handlers/index.php') ?: '';
|
||||||
|
assert_false(strpos($source, "ctx->t('Scope')") !== false);
|
||||||
|
assert_false(strpos($source, "ctx->t(\$rule['dynamic_scope']") !== false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('mutating handlers synchronize active backend after storage changes', function (): void {
|
test('mutating handlers synchronize active backend after storage changes', function (): void {
|
||||||
@@ -155,8 +165,8 @@ test('new rule form selects current date for start and end calendars by default'
|
|||||||
|
|
||||||
assert_contains('id="start_value_date" name="start_value_date" value="' . $today . '"', $html);
|
assert_contains('id="start_value_date" name="start_value_date" value="' . $today . '"', $html);
|
||||||
assert_contains('id="end_value_date" name="end_value_date" value="' . $today . '"', $html);
|
assert_contains('id="end_value_date" name="end_value_date" value="' . $today . '"', $html);
|
||||||
assert_contains('id="start_value" name="start_value" value="' . $today . 'T09:00"', $html);
|
assert_contains('id="start_value" name="start_value" value="' . $today . 'T00:00"', $html);
|
||||||
assert_contains('id="end_value" name="end_value" value="' . $today . 'T17:00"', $html);
|
assert_contains('id="end_value" name="end_value" value="' . $today . 'T23:59"', $html);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rule form localizes calendar and preview labels without translating user content globally', function (): void {
|
test('rule form localizes calendar and preview labels without translating user content globally', function (): void {
|
||||||
@@ -194,8 +204,8 @@ test('directadmin backend allows only one enabled global rule per account', func
|
|||||||
'repeat_minutes' => 1440,
|
'repeat_minutes' => 1440,
|
||||||
'body' => 'Body',
|
'body' => 'Body',
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
'start_value' => '2026-06-10|morning',
|
'start_value' => '2026-06-10T00:00',
|
||||||
'end_value' => '2026-06-24|evening',
|
'end_value' => '2026-06-24T23:59',
|
||||||
]);
|
]);
|
||||||
$ctx = new AppContext(
|
$ctx = new AppContext(
|
||||||
new DirectAdminUser('alice', 'enhanced', 'pl', TEST_TMP . '/config'),
|
new DirectAdminUser('alice', 'enhanced', 'pl', TEST_TMP . '/config'),
|
||||||
|
|||||||
@@ -26,21 +26,42 @@ test('rule validator normalizes exact hour schedule', function (): void {
|
|||||||
assert_true($rule['start_ts'] < $rule['end_ts']);
|
assert_true($rule['start_ts'] < $rule['end_ts']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rule validator accepts da period schedule when backend is da', function (): void {
|
test('rule validator accepts da exact hour schedule when backend is da', function (): void {
|
||||||
$settingsPath = TEST_TMP . '/validator-da.conf';
|
$settingsPath = TEST_TMP . '/validator-da.conf';
|
||||||
test_write($settingsPath, "GLOBAL_AUTORESPONDER_BACKEND=da\n");
|
test_write($settingsPath, "GLOBAL_AUTORESPONDER_BACKEND=da\n");
|
||||||
$settings = Settings::load($settingsPath);
|
$settings = Settings::load($settingsPath);
|
||||||
$rule = RuleValidator::validate([
|
$rule = RuleValidator::validate([
|
||||||
'subject_prefix' => 'Urlop',
|
'subject_prefix' => 'Urlop',
|
||||||
'reply_frequency' => 'every',
|
'reply_frequency' => '1',
|
||||||
'body' => 'Body',
|
'body' => 'Body',
|
||||||
'start_value' => '2026-06-10|morning',
|
'start_value' => '2026-06-10T00:00',
|
||||||
'end_value' => '2026-06-24|evening',
|
'end_value' => '2026-06-24T23:59',
|
||||||
'enabled' => '1',
|
'enabled' => '1',
|
||||||
], $settings);
|
], $settings);
|
||||||
assert_same('directadmin_period', $rule['schedule_mode']);
|
assert_same('exact_hour', $rule['schedule_mode']);
|
||||||
assert_true($rule['reply_every_message']);
|
assert_false($rule['reply_every_message']);
|
||||||
assert_same(0, $rule['repeat_minutes']);
|
assert_same(1, $rule['repeat_minutes']);
|
||||||
|
assert_same('2026-06-10T00:00', $rule['start_value']);
|
||||||
|
assert_same('2026-06-24T23:59', $rule['end_value']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rule validator rejects every message frequency for da backend', function (): void {
|
||||||
|
$settingsPath = TEST_TMP . '/validator-da-every.conf';
|
||||||
|
test_write($settingsPath, "GLOBAL_AUTORESPONDER_BACKEND=da\n");
|
||||||
|
$settings = Settings::load($settingsPath);
|
||||||
|
try {
|
||||||
|
RuleValidator::validate([
|
||||||
|
'subject_prefix' => 'Urlop',
|
||||||
|
'reply_frequency' => 'every',
|
||||||
|
'body' => 'Body',
|
||||||
|
'start_value' => '2026-06-10T00:00',
|
||||||
|
'end_value' => '2026-06-24T23:59',
|
||||||
|
], $settings);
|
||||||
|
} catch (InvalidArgumentException $e) {
|
||||||
|
assert_contains('Częstość odpowiedzi', $e->getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new RuntimeException('Expected every-message frequency to fail for da backend');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rule validator rejects header injection and reversed dates', function (): void {
|
test('rule validator rejects header injection and reversed dates', function (): void {
|
||||||
@@ -66,8 +87,8 @@ test('rule validator rejects unsupported response frequency', function (): void
|
|||||||
'subject_prefix' => 'Urlop',
|
'subject_prefix' => 'Urlop',
|
||||||
'reply_frequency' => '45',
|
'reply_frequency' => '45',
|
||||||
'body' => 'Body',
|
'body' => 'Body',
|
||||||
'start_value' => '2026-06-10|morning',
|
'start_value' => '2026-06-10T00:00',
|
||||||
'end_value' => '2026-06-24|evening',
|
'end_value' => '2026-06-24T23:59',
|
||||||
], $settings);
|
], $settings);
|
||||||
} catch (InvalidArgumentException $e) {
|
} catch (InvalidArgumentException $e) {
|
||||||
assert_contains('Częstość odpowiedzi', $e->getMessage());
|
assert_contains('Częstość odpowiedzi', $e->getMessage());
|
||||||
|
|||||||
Reference in New Issue
Block a user