Upload via GUI (30 Dateien)

This commit is contained in:
2026-11-08 20:09:19 +00:00
parent 4ad8fe8349
commit fe3c8fa7c5
24 changed files with 1137 additions and 650 deletions
+1 -1
View File
@@ -62,7 +62,7 @@ Unter *Einstellungen → DeskHub Tickets* gibt es **„Speichern und Verbindung
## Grenzen ## Grenzen
- **Keine Dateianhänge:** Die öffentliche API von DeskHub nimmt nur Text. Der Anhang-Upload des Kundenformulars fehlt deshalb im WordPress-Formular. - **Dateianhänge (ab Plugin 1.3.0 und DeskHub 1.0.67):** Besucher können bis zu 5 Dateien anhängen (zusammen höchstens 10 MB). Erlaubte Typen und die Größe je Datei bestimmt DeskHub (Einstellungen → Uploads); im Plugin lässt sich die Funktion ausschalten, ein eigenes Formular in DeskHub kann Anhänge ebenfalls abschalten. Mit älterem DeskHub bleibt das Feld unsichtbar.
- **Ältere DeskHub-Version:** Ohne die Formular-Schnittstelle (vor 1.0.64) zeigt das Plugin das einfache Formular ohne eigene Felder; Administratoren sehen einen Hinweis. - **Ältere DeskHub-Version:** Ohne die Formular-Schnittstelle (vor 1.0.64) zeigt das Plugin das einfache Formular ohne eigene Felder; Administratoren sehen einen Hinweis.
- **IP-Adresse im Ticket:** DeskHub sieht die IP-Adresse Ihres WordPress-Servers, nicht die des Besuchers. - **IP-Adresse im Ticket:** DeskHub sieht die IP-Adresse Ihres WordPress-Servers, nicht die des Besuchers.
- **Mengenbegrenzung der API:** DeskHub nimmt über die API höchstens 60 Tickets pro Minute an (für alle Aufrufer zusammen). - **Mengenbegrenzung der API:** DeskHub nimmt über die API höchstens 60 Tickets pro Minute an (für alle Aufrufer zusammen).
@@ -107,6 +107,8 @@
.dht-wrap .dht-group { font-size: 1.1em !important; line-height: 1.3 !important; font-weight: 600 !important; letter-spacing: normal !important; text-transform: none !important; } .dht-wrap .dht-group { font-size: 1.1em !important; line-height: 1.3 !important; font-weight: 600 !important; letter-spacing: normal !important; text-transform: none !important; }
.dht-radios.dht-inline { display: flex; flex-wrap: wrap; gap: 0 1.4em; } .dht-radios.dht-inline { display: flex; flex-wrap: wrap; gap: 0 1.4em; }
.dht-radios.dht-inline legend { flex: 1 1 100%; } .dht-radios.dht-inline legend { flex: 1 1 100%; }
.dht-attach input[type="file"] { width: 100%; padding: .5em 0; font: inherit; color: inherit; }
.dht-attach .dht-help { display: block; }
.dht-help { margin: .3em 0 0; font-size: .88em; color: var(--dht-muted); } .dht-help { margin: .3em 0 0; font-size: .88em; color: var(--dht-muted); }
.dht-req { color: #b91c1c; } .dht-req { color: #b91c1c; }
.dht-group { margin: 1.2em 0 .6em; } .dht-group { margin: 1.2em 0 .6em; }
@@ -43,6 +43,12 @@
var mi = message.querySelector('textarea'); var mi = message.querySelector('textarea');
if (mi) { mi.disabled = !f.messageShow; mi.required = !!f.messageShow; mi.placeholder = f.messageHint || ''; } if (mi) { mi.disabled = !f.messageShow; mi.required = !!f.messageShow; mi.placeholder = f.messageHint || ''; }
} }
var attach = form.querySelector('.dht-attach');
if (attach) {
attach.hidden = !f.attachments;
var fi = attach.querySelector('input[type=file]');
if (fi) { fi.disabled = !f.attachments; if (!f.attachments) { fi.value = ''; } }
}
var submit = form.querySelector('.dht-submit'); var submit = form.querySelector('.dht-submit');
if (submit && f.submitLabel) { submit.textContent = f.submitLabel; } if (submit && f.submitLabel) { submit.textContent = f.submitLabel; }
} }
@@ -3,7 +3,7 @@
* Plugin Name: DeskHub Tickets * Plugin Name: DeskHub Tickets
* Plugin URI: https://git.viper.ipv64.net/M_Viper/deskhub * Plugin URI: https://git.viper.ipv64.net/M_Viper/deskhub
* Description: Support-Tickets aus WordPress heraus in DeskHub anlegen und den Status abfragen. Formular und Statusabfrage per Shortcode, Spamschutz, Einwilligung und optional Cloudflare Turnstile. * Description: Support-Tickets aus WordPress heraus in DeskHub anlegen und den Status abfragen. Formular und Statusabfrage per Shortcode, Spamschutz, Einwilligung und optional Cloudflare Turnstile.
* Version: 1.2.2 * Version: 1.3.0
* Requires at least: 5.8 * Requires at least: 5.8
* Requires PHP: 7.4 * Requires PHP: 7.4
* Author: DeskHub * Author: DeskHub
@@ -17,7 +17,7 @@ if (!defined('ABSPATH')) {
exit; exit;
} }
define('DESKHUB_TICKETS_VERSION', '1.2.2'); define('DESKHUB_TICKETS_VERSION', '1.3.0');
define('DESKHUB_TICKETS_FILE', __FILE__); define('DESKHUB_TICKETS_FILE', __FILE__);
define('DESKHUB_TICKETS_DIR', plugin_dir_path(__FILE__)); define('DESKHUB_TICKETS_DIR', plugin_dir_path(__FILE__));
define('DESKHUB_TICKETS_ASSETS', plugin_dir_url(__FILE__)); define('DESKHUB_TICKETS_ASSETS', plugin_dir_url(__FILE__));
@@ -71,13 +71,17 @@ class Deskhub_Tickets_Client
public function create_ticket(array $data) public function create_ticket(array $data)
{ {
$fields = $data['fields'] ?? null; $fields = $data['fields'] ?? null;
unset($data['fields']); $attachments = $data['attachments'] ?? null;
unset($data['fields'], $data['attachments']);
$payload = array_filter($data, static function ($v) { $payload = array_filter($data, static function ($v) {
return $v !== null && $v !== '' && $v !== 0; return $v !== null && $v !== '' && $v !== 0;
}); });
if (is_array($fields)) { if (is_array($fields)) {
$payload['fields'] = (object) $fields; // auch leer senden: Damit prüft DeskHub die Angaben gegen das Kundenformular $payload['fields'] = (object) $fields; // auch leer senden: Damit prüft DeskHub die Angaben gegen das Kundenformular
} }
if (is_array($attachments) && $attachments) {
$payload['attachments'] = array_values($attachments);
}
$res = $this->request('POST', [], $payload); $res = $this->request('POST', [], $payload);
if (is_wp_error($res)) { if (is_wp_error($res)) {
return $res; return $res;
@@ -157,7 +157,7 @@ class Deskhub_Tickets_Form
$texts = []; $texts = [];
foreach ($forms as $tid => $fm) { foreach ($forms as $tid => $fm) {
$texts[$tid] = ['title' => $fm['title'], 'intro' => $fm['intro'], 'subjectShow' => $fm['subject']['show'], 'subjectLabel' => $fm['subject']['label'], $texts[$tid] = ['title' => $fm['title'], 'intro' => $fm['intro'], 'subjectShow' => $fm['subject']['show'], 'subjectLabel' => $fm['subject']['label'],
'messageShow' => $fm['message']['show'], 'messageLabel' => $fm['message']['label'], 'messageHint' => $fm['message']['hint'], 'submitLabel' => $fm['submitLabel']]; 'messageShow' => $fm['message']['show'], 'messageLabel' => $fm['message']['label'], 'messageHint' => $fm['message']['hint'], 'submitLabel' => $fm['submitLabel'], 'attachments' => $fm['attachments']['enabled']];
} }
if ($unsupported && current_user_can('manage_options')) { if ($unsupported && current_user_can('manage_options')) {
echo '<p class="dht-notice dht-error">' . esc_html__('Der DeskHub-Server kennt die Formular-Schnittstelle noch nicht (bitte DeskHub aktualisieren). Bis dahin wird das einfache Formular ohne eigene Felder gezeigt. (Diese Meldung sehen nur Administratoren.)', 'deskhub-tickets') . '</p>'; echo '<p class="dht-notice dht-error">' . esc_html__('Der DeskHub-Server kennt die Formular-Schnittstelle noch nicht (bitte DeskHub aktualisieren). Bis dahin wird das einfache Formular ohne eigene Felder gezeigt. (Diese Meldung sehen nur Administratoren.)', 'deskhub-tickets') . '</p>';
@@ -175,7 +175,7 @@ class Deskhub_Tickets_Form
$showSubject = (bool) $active['subject']['show']; $showSubject = (bool) $active['subject']['show'];
$showMessage = (bool) $active['message']['show']; $showMessage = (bool) $active['message']['show'];
?> ?>
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" class="dht-form" data-dht-forms="<?php echo esc_attr((string) wp_json_encode($texts)); ?>"> <form method="post" enctype="multipart/form-data" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" class="dht-form" data-dht-forms="<?php echo esc_attr((string) wp_json_encode($texts)); ?>">
<input type="hidden" name="action" value="deskhub_ticket_submit"> <input type="hidden" name="action" value="deskhub_ticket_submit">
<input type="hidden" name="dht_cfg" value="<?php echo esc_attr($cfgB64); ?>"> <input type="hidden" name="dht_cfg" value="<?php echo esc_attr($cfgB64); ?>">
<input type="hidden" name="dht_sig" value="<?php echo esc_attr(deskhub_tickets_sign('cfg|' . $cfgB64)); ?>"> <input type="hidden" name="dht_sig" value="<?php echo esc_attr(deskhub_tickets_sign('cfg|' . $cfgB64)); ?>">
@@ -219,6 +219,31 @@ class Deskhub_Tickets_Form
</p> </p>
<?php echo self::render_slot($forms, ['issue'], $multi, $selected, $values['fields']); ?> <?php echo self::render_slot($forms, ['issue'], $multi, $selected, $values['fields']); ?>
<?php echo self::render_slot($forms, [], $multi, $selected, $values['fields'], true); ?> <?php echo self::render_slot($forms, [], $multi, $selected, $values['fields'], true); ?>
<?php
// Dateien anhängen: ein Feld für das ganze Formular; form.js blendet es aus, wenn das gewählte Thema keine Anhänge erlaubt
$attPolicy = null;
foreach ($forms as $fm) {
if (!empty($fm['attachments']['enabled'])) {
$attPolicy = $fm['attachments'];
break;
}
}
if ($attPolicy !== null):
$attOn = !empty($active['attachments']['enabled']);
?>
<p class="dht-attach"<?php echo $attOn ? '' : ' hidden'; ?>>
<label for="dht-files"><?php echo esc_html__('Dateien anhängen (optional)', 'deskhub-tickets'); ?></label>
<input type="file" id="dht-files" name="dht_files[]" multiple accept="<?php echo esc_attr('.' . implode(',.', $attPolicy['allowed'])); ?>" <?php echo $attOn ? '' : 'disabled'; ?>>
<span class="dht-help"><?php echo esc_html(sprintf(
/* translators: 1: Anzahl Dateien, 2: Größe je Datei, 3: Größe insgesamt, 4: Dateitypen */
__('Bis zu %1$d Dateien, je höchstens %2$s, zusammen höchstens %3$s. Erlaubt: %4$s', 'deskhub-tickets'),
$attPolicy['maxFiles'],
self::format_bytes($attPolicy['maxFileBytes']),
self::format_bytes($attPolicy['maxTotalBytes']),
implode(', ', $attPolicy['allowed'])
)); ?></span>
</p>
<?php endif; ?>
<?php if (trim((string) $opts['consent_text']) !== ''): ?> <?php if (trim((string) $opts['consent_text']) !== ''): ?>
<p class="dht-consent"> <p class="dht-consent">
<label><input type="checkbox" name="dht_consent" value="1" required> <span><?php echo wp_kses((string) $opts['consent_text'], ['a' => ['href' => [], 'target' => [], 'rel' => []], 'strong' => [], 'em' => []]); ?></span></label> <label><input type="checkbox" name="dht_consent" value="1" required> <span><?php echo wp_kses((string) $opts['consent_text'], ['a' => ['href' => [], 'target' => [], 'rel' => []], 'strong' => [], 'em' => []]); ?></span></label>
@@ -247,6 +272,104 @@ class Deskhub_Tickets_Form
]; ];
} }
/**
* Angebot für Dateianhänge aus dem Formular von DeskHub. Ohne Angabe (ältere DeskHub-Version) oder wenn die Option des Plugins
* ausgeschaltet ist, gibt es keine Anhänge.
*
* @param mixed $a
* @return array{enabled:bool,maxFiles:int,maxFileBytes:int,maxTotalBytes:int,allowed:string[]}
*/
public static function normalize_attachments($a): array
{
$off = ['enabled' => false, 'maxFiles' => 0, 'maxFileBytes' => 0, 'maxTotalBytes' => 0, 'allowed' => []];
$opts = deskhub_tickets_options();
if (!is_array($a) || empty($a['enabled']) || empty($opts['attachments'])) {
return $off;
}
$allowed = [];
foreach ((array) ($a['allowedExtensions'] ?? []) as $e) {
$e = strtolower(ltrim(trim((string) $e), '.'));
if ($e !== '' && preg_match('/^[a-z0-9]{1,8}$/', $e)) {
$allowed[] = $e;
}
}
$files = max(0, min(10, (int) ($a['maxFiles'] ?? 0)));
$perFile = max(0, (int) ($a['maxFileBytes'] ?? 0));
$total = max(0, (int) ($a['maxTotalBytes'] ?? 0));
if ($files < 1 || $perFile < 1 || $total < 1 || !$allowed) {
return $off;
}
return ['enabled' => true, 'maxFiles' => $files, 'maxFileBytes' => $perFile, 'maxTotalBytes' => $total, 'allowed' => $allowed];
}
/** Menschenlesbare Größe ("5 MB"). */
private static function format_bytes(int $b): string
{
return $b >= 1048576 ? rtrim(rtrim(number_format($b / 1048576, 1, ',', ''), '0'), ',') . ' MB' : max(1, (int) round($b / 1024)) . ' KB';
}
/**
* Prüft die hochgeladenen Dateien gegen das Angebot und gibt sie fertig für die Schnittstelle zurück.
*
* @param array<string,mixed> $files $_FILES['dht_files']
* @return array{0:string[],1:array<int,array{name:string,data:string}>} [Fehler, Anhänge]
*/
public static function collect_attachments(array $files, array $policy): array
{
$names = isset($files['name']) ? (array) $files['name'] : [];
$errors = [];
$out = [];
$total = 0;
$dangerous = ['php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'phar', 'exe', 'bat', 'cmd', 'sh', 'js', 'html', 'htm', 'svg'];
foreach ($names as $i => $rawName) {
$err = (int) ($files['error'][$i] ?? UPLOAD_ERR_NO_FILE);
if ($err === UPLOAD_ERR_NO_FILE) {
continue; // nichts ausgewählt
}
$name = sanitize_file_name(wp_unslash((string) $rawName));
if (!$policy['enabled']) {
return [[__('Bei diesem Formular können keine Dateien angehängt werden.', 'deskhub-tickets')], []];
}
if (count($out) >= $policy['maxFiles']) {
$errors[] = sprintf(__('Bitte hängen Sie höchstens %d Dateien an.', 'deskhub-tickets'), $policy['maxFiles']);
break;
}
if ($err !== UPLOAD_ERR_OK) {
$errors[] = ($err === UPLOAD_ERR_INI_SIZE || $err === UPLOAD_ERR_FORM_SIZE)
? sprintf(__('Die Datei „%s“ ist zu groß (höchstens %s).', 'deskhub-tickets'), $name, self::format_bytes($policy['maxFileBytes']))
: sprintf(__('Die Datei „%s“ konnte nicht hochgeladen werden.', 'deskhub-tickets'), $name);
continue;
}
$ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
if ($name === '' || $ext === '' || in_array($ext, $dangerous, true) || !in_array($ext, $policy['allowed'], true)) {
$errors[] = sprintf(__('Der Dateityp von „%1$s“ ist nicht erlaubt. Erlaubt: %2$s', 'deskhub-tickets'), $name, implode(', ', $policy['allowed']));
continue;
}
$size = (int) ($files['size'][$i] ?? 0);
$tmp = (string) ($files['tmp_name'][$i] ?? '');
if ($size < 1 || $tmp === '' || !(is_uploaded_file($tmp) || (defined('DESKHUB_TICKETS_TESTS') && is_file($tmp)))) {
$errors[] = sprintf(__('Die Datei „%s“ konnte nicht gelesen werden.', 'deskhub-tickets'), $name);
continue;
}
if ($size > $policy['maxFileBytes']) {
$errors[] = sprintf(__('Die Datei „%1$s“ ist zu groß (höchstens %2$s).', 'deskhub-tickets'), $name, self::format_bytes($policy['maxFileBytes']));
continue;
}
$total += $size;
if ($total > $policy['maxTotalBytes']) {
$errors[] = sprintf(__('Die Dateien sind zusammen zu groß (höchstens %s).', 'deskhub-tickets'), self::format_bytes($policy['maxTotalBytes']));
break;
}
$content = file_get_contents($tmp);
if ($content === false || $content === '') {
$errors[] = sprintf(__('Die Datei „%s“ konnte nicht gelesen werden.', 'deskhub-tickets'), $name);
continue;
}
$out[] = ['name' => $name, 'data' => base64_encode($content)];
}
return [$errors, $out];
}
/** Bringt ein Formular von DeskHub (oder null) in eine feste Form mit Standardwerten, Feldern nach Plätzen sortiert. */ /** Bringt ein Formular von DeskHub (oder null) in eine feste Form mit Standardwerten, Feldern nach Plätzen sortiert. */
public static function normalize_form(?array $f): array public static function normalize_form(?array $f): array
{ {
@@ -268,6 +391,7 @@ class Deskhub_Tickets_Form
], ],
'submitLabel' => $own ? $str($f['submitLabel'] ?? '', __('Ticket absenden', 'deskhub-tickets')) : __('Ticket absenden', 'deskhub-tickets'), 'submitLabel' => $own ? $str($f['submitLabel'] ?? '', __('Ticket absenden', 'deskhub-tickets')) : __('Ticket absenden', 'deskhub-tickets'),
'fields' => [], 'fields' => [],
'attachments' => self::normalize_attachments($f['attachments'] ?? null),
]; ];
$allowed = ['text', 'textarea', 'select', 'radio', 'checkbox', 'number', 'date']; $allowed = ['text', 'textarea', 'select', 'radio', 'checkbox', 'number', 'date'];
foreach ((array) ($f['fields'] ?? []) as $fd) { foreach ((array) ($f['fields'] ?? []) as $fd) {
@@ -528,6 +652,13 @@ class Deskhub_Tickets_Form
[$fieldErrors, $fieldValues] = self::validate_fields($form['fields'], $postedFields); [$fieldErrors, $fieldValues] = self::validate_fields($form['fields'], $postedFields);
$errors = array_merge($errors, $fieldErrors); $errors = array_merge($errors, $fieldErrors);
} }
// Dateianhänge (nur wenn das Formular sie anbietet)
$attachments = [];
if (!empty($_FILES['dht_files']) && is_array($_FILES['dht_files'])) {
$policy = $form !== null ? $form['attachments'] : self::normalize_attachments(null);
[$attErrors, $attachments] = self::collect_attachments($_FILES['dht_files'], $policy);
$errors = array_merge($errors, $attErrors);
}
if (trim((string) $opts['consent_text']) !== '' && empty($_POST['dht_consent'])) { if (trim((string) $opts['consent_text']) !== '' && empty($_POST['dht_consent'])) {
$errors[] = __('Bitte stimmen Sie der Verarbeitung Ihrer Angaben zu.', 'deskhub-tickets'); $errors[] = __('Bitte stimmen Sie der Verarbeitung Ihrer Angaben zu.', 'deskhub-tickets');
} }
@@ -563,6 +694,9 @@ class Deskhub_Tickets_Form
if ($form !== null) { if ($form !== null) {
$payload['fields'] = $fieldValues; $payload['fields'] = $fieldValues;
} }
if ($attachments) {
$payload['attachments'] = $attachments;
}
$payload = apply_filters('deskhub_tickets_payload', $payload, $values); $payload = apply_filters('deskhub_tickets_payload', $payload, $values);
$result = $client->create_ticket($payload); $result = $client->create_ticket($payload);
if (is_wp_error($result)) { if (is_wp_error($result)) {
@@ -86,6 +86,7 @@ class Deskhub_Tickets_Settings
'strong' => [], 'strong' => [],
'em' => [], 'em' => [],
]); ]);
$out['attachments'] = !empty($input['attachments']) ? 1 : 0;
$accent = sanitize_hex_color((string) ($input['accent_color'] ?? '')); $accent = sanitize_hex_color((string) ($input['accent_color'] ?? ''));
$out['accent_color'] = empty($input['accent_auto']) && $accent ? $accent : ''; $out['accent_color'] = empty($input['accent_auto']) && $accent ? $accent : '';
$out['success_text'] = mb_substr(sanitize_text_field((string) ($input['success_text'] ?? '')), 0, 500); $out['success_text'] = mb_substr(sanitize_text_field((string) ($input['success_text'] ?? '')), 0, 500);
@@ -207,6 +208,13 @@ class Deskhub_Tickets_Settings
<p class="description"><?php echo esc_html__('Wenn ausgefüllt, muss der Besucher dieses Kästchen anhaken. Erlaubt sind Links (a), fett und kursiv.', 'deskhub-tickets'); ?></p> <p class="description"><?php echo esc_html__('Wenn ausgefüllt, muss der Besucher dieses Kästchen anhaken. Erlaubt sind Links (a), fett und kursiv.', 'deskhub-tickets'); ?></p>
</td> </td>
</tr> </tr>
<tr>
<th scope="row"><?php echo esc_html__('Dateianhänge', 'deskhub-tickets'); ?></th>
<td>
<label><input type="checkbox" name="<?php echo esc_attr($name); ?>[attachments]" value="1" <?php checked(!empty($o['attachments'])); ?>> <?php echo esc_html__('Besucher dürfen Dateien anhängen', 'deskhub-tickets'); ?></label>
<p class="description"><?php echo esc_html__('Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar.', 'deskhub-tickets'); ?></p>
</td>
</tr>
<tr> <tr>
<th scope="row"><label for="dht_accent"><?php echo esc_html__('Akzentfarbe', 'deskhub-tickets'); ?></label></th> <th scope="row"><label for="dht_accent"><?php echo esc_html__('Akzentfarbe', 'deskhub-tickets'); ?></label></th>
<td> <td>
@@ -18,6 +18,7 @@ function deskhub_tickets_defaults(): array
'priority_id' => 0, 'priority_id' => 0,
'consent_text' => '', 'consent_text' => '',
'accent_color' => '', 'accent_color' => '',
'attachments' => 1,
'success_text' => '', 'success_text' => '',
'status_page_url' => '', 'status_page_url' => '',
'min_seconds' => 3, 'min_seconds' => 3,
@@ -17,18 +17,33 @@ msgstr "Department"
msgid "Adresse des DeskHub-Servers" msgid "Adresse des DeskHub-Servers"
msgstr "DeskHub server address" msgstr "DeskHub server address"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Anfrage ohne weitere Angaben" msgid "Anfrage ohne weitere Angaben"
msgstr "Request without further details" msgstr "Request without further details"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Beantwortet" msgid "Beantwortet"
msgstr "Answered" msgstr "Answered"
msgid "Bei diesem Formular können keine Dateien angehängt werden."
msgstr "Files cannot be attached to this form."
msgid "Besucher dürfen Dateien anhängen"
msgstr "Visitors may attach files"
msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)" msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)"
msgstr "visitors choose a topic (label:number of the help topic)" msgstr "visitors choose a topic (label:number of the help topic)"
msgid "Betreff" msgid "Betreff"
msgstr "Subject" msgstr "Subject"
msgid "Bis zu %1$d Dateien, je höchstens %2$s, zusammen höchstens %3$s. Erlaubt: %4$s"
msgstr "Up to %1$d files, %2$s each at most, %3$s in total. Allowed: %4$s"
msgid "Bitte Server-Adresse und API-Schlüssel eintragen." msgid "Bitte Server-Adresse und API-Schlüssel eintragen."
msgstr "Please enter the server address and API key." msgstr "Please enter the server address and API key."
@@ -68,6 +83,9 @@ msgstr "Please enter a subject (at most 255 characters)."
msgid "Bitte geben Sie einen Betreff an." msgid "Bitte geben Sie einen Betreff an."
msgstr "Please enter a subject." msgstr "Please enter a subject."
msgid "Bitte hängen Sie höchstens %d Dateien an."
msgstr "Please attach no more than %d files."
msgid "Bitte prüfen Sie Ihre Angaben." msgid "Bitte prüfen Sie Ihre Angaben."
msgstr "Please check your details." msgstr "Please check your details."
@@ -95,9 +113,18 @@ msgstr "The form has expired. Please reload the page and try again."
msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab." msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab."
msgstr "That was a bit too fast. Please check your details and submit again." msgstr "That was a bit too fast. Please check your details and submit again."
msgid "Dateianhänge"
msgstr "File attachments"
msgid "Dateien anhängen (optional)"
msgstr "Attach files (optional)"
msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache." msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache."
msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching." msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching."
msgid "Der Dateityp von „%1$s“ ist nicht erlaubt. Erlaubt: %2$s"
msgstr "The file type of “%1$s” is not allowed. Allowed: %2$s"
msgid "Der DeskHub-Server ist nicht erreichbar." msgid "Der DeskHub-Server ist nicht erreichbar."
msgstr "The DeskHub server cannot be reached." msgstr "The DeskHub server cannot be reached."
@@ -143,6 +170,21 @@ msgstr "DeskHub decides"
msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)." msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)."
msgstr "The address where your DeskHub can be reached. https only (http only for local tests)." msgstr "The address where your DeskHub can be reached. https only (http only for local tests)."
msgid "Die Datei „%1$s“ ist zu groß (höchstens %2$s)."
msgstr "The file “%1$s” is too large (%2$s at most)."
msgid "Die Datei „%s“ ist zu groß (höchstens %s)."
msgstr "The file “%s” is too large (%s at most)."
msgid "Die Datei „%s“ konnte nicht gelesen werden."
msgstr "The file “%s” could not be read."
msgid "Die Datei „%s“ konnte nicht hochgeladen werden."
msgstr "The file “%s” could not be uploaded."
msgid "Die Dateien sind zusammen zu groß (höchstens %s)."
msgstr "The files together are too large (%s at most)."
msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen." msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen."
msgstr "The forms will be reloaded from DeskHub on the next request." msgstr "The forms will be reloaded from DeskHub on the next request."
@@ -182,6 +224,9 @@ msgstr "Settings"
msgid "Einwilligung (Datenschutz)" msgid "Einwilligung (Datenschutz)"
msgstr "Consent (data protection)" msgstr "Consent (data protection)"
msgid "Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar."
msgstr "DeskHub decides the allowed file types and sizes (Settings → Uploads): at most 5 files, 10 MB in total. Needs DeskHub 1.0.67 or newer, otherwise the field stays hidden."
msgid "Formular" msgid "Formular"
msgstr "Form" msgstr "Form"
@@ -263,6 +308,9 @@ msgstr "Priority"
msgid "Schlüssel entfernen" msgid "Schlüssel entfernen"
msgstr "Remove key" msgstr "Remove key"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
msgid "Seite mit der Statusabfrage" msgid "Seite mit der Statusabfrage"
msgstr "Page with the status lookup" msgstr "Page with the status lookup"
@@ -365,12 +413,3 @@ msgstr "saved, enter a new key to change it"
msgid "mit festen Voreinstellungen für dieses Formular" msgid "mit festen Voreinstellungen für dieses Formular"
msgstr "with fixed defaults for this form" msgstr "with fixed defaults for this form"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
@@ -17,18 +17,33 @@ msgstr "Department"
msgid "Adresse des DeskHub-Servers" msgid "Adresse des DeskHub-Servers"
msgstr "DeskHub server address" msgstr "DeskHub server address"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Anfrage ohne weitere Angaben" msgid "Anfrage ohne weitere Angaben"
msgstr "Request without further details" msgstr "Request without further details"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Beantwortet" msgid "Beantwortet"
msgstr "Answered" msgstr "Answered"
msgid "Bei diesem Formular können keine Dateien angehängt werden."
msgstr "Files cannot be attached to this form."
msgid "Besucher dürfen Dateien anhängen"
msgstr "Visitors may attach files"
msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)" msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)"
msgstr "visitors choose a topic (label:number of the help topic)" msgstr "visitors choose a topic (label:number of the help topic)"
msgid "Betreff" msgid "Betreff"
msgstr "Subject" msgstr "Subject"
msgid "Bis zu %1$d Dateien, je höchstens %2$s, zusammen höchstens %3$s. Erlaubt: %4$s"
msgstr "Up to %1$d files, %2$s each at most, %3$s in total. Allowed: %4$s"
msgid "Bitte Server-Adresse und API-Schlüssel eintragen." msgid "Bitte Server-Adresse und API-Schlüssel eintragen."
msgstr "Please enter the server address and API key." msgstr "Please enter the server address and API key."
@@ -68,6 +83,9 @@ msgstr "Please enter a subject (at most 255 characters)."
msgid "Bitte geben Sie einen Betreff an." msgid "Bitte geben Sie einen Betreff an."
msgstr "Please enter a subject." msgstr "Please enter a subject."
msgid "Bitte hängen Sie höchstens %d Dateien an."
msgstr "Please attach no more than %d files."
msgid "Bitte prüfen Sie Ihre Angaben." msgid "Bitte prüfen Sie Ihre Angaben."
msgstr "Please check your details." msgstr "Please check your details."
@@ -95,9 +113,18 @@ msgstr "The form has expired. Please reload the page and try again."
msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab." msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab."
msgstr "That was a bit too fast. Please check your details and submit again." msgstr "That was a bit too fast. Please check your details and submit again."
msgid "Dateianhänge"
msgstr "File attachments"
msgid "Dateien anhängen (optional)"
msgstr "Attach files (optional)"
msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache." msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache."
msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching." msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching."
msgid "Der Dateityp von „%1$s“ ist nicht erlaubt. Erlaubt: %2$s"
msgstr "The file type of “%1$s” is not allowed. Allowed: %2$s"
msgid "Der DeskHub-Server ist nicht erreichbar." msgid "Der DeskHub-Server ist nicht erreichbar."
msgstr "The DeskHub server cannot be reached." msgstr "The DeskHub server cannot be reached."
@@ -143,6 +170,21 @@ msgstr "DeskHub decides"
msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)." msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)."
msgstr "The address where your DeskHub can be reached. https only (http only for local tests)." msgstr "The address where your DeskHub can be reached. https only (http only for local tests)."
msgid "Die Datei „%1$s“ ist zu groß (höchstens %2$s)."
msgstr "The file “%1$s” is too large (%2$s at most)."
msgid "Die Datei „%s“ ist zu groß (höchstens %s)."
msgstr "The file “%s” is too large (%s at most)."
msgid "Die Datei „%s“ konnte nicht gelesen werden."
msgstr "The file “%s” could not be read."
msgid "Die Datei „%s“ konnte nicht hochgeladen werden."
msgstr "The file “%s” could not be uploaded."
msgid "Die Dateien sind zusammen zu groß (höchstens %s)."
msgstr "The files together are too large (%s at most)."
msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen." msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen."
msgstr "The forms will be reloaded from DeskHub on the next request." msgstr "The forms will be reloaded from DeskHub on the next request."
@@ -182,6 +224,9 @@ msgstr "Settings"
msgid "Einwilligung (Datenschutz)" msgid "Einwilligung (Datenschutz)"
msgstr "Consent (data protection)" msgstr "Consent (data protection)"
msgid "Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar."
msgstr "DeskHub decides the allowed file types and sizes (Settings → Uploads): at most 5 files, 10 MB in total. Needs DeskHub 1.0.67 or newer, otherwise the field stays hidden."
msgid "Formular" msgid "Formular"
msgstr "Form" msgstr "Form"
@@ -263,6 +308,9 @@ msgstr "Priority"
msgid "Schlüssel entfernen" msgid "Schlüssel entfernen"
msgstr "Remove key" msgstr "Remove key"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
msgid "Seite mit der Statusabfrage" msgid "Seite mit der Statusabfrage"
msgstr "Page with the status lookup" msgstr "Page with the status lookup"
@@ -365,12 +413,3 @@ msgstr "saved, enter a new key to change it"
msgid "mit festen Voreinstellungen für dieses Formular" msgid "mit festen Voreinstellungen für dieses Formular"
msgstr "with fixed defaults for this form" msgstr "with fixed defaults for this form"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
@@ -17,18 +17,33 @@ msgstr "Department"
msgid "Adresse des DeskHub-Servers" msgid "Adresse des DeskHub-Servers"
msgstr "DeskHub server address" msgstr "DeskHub server address"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Anfrage ohne weitere Angaben" msgid "Anfrage ohne weitere Angaben"
msgstr "Request without further details" msgstr "Request without further details"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Beantwortet" msgid "Beantwortet"
msgstr "Answered" msgstr "Answered"
msgid "Bei diesem Formular können keine Dateien angehängt werden."
msgstr "Files cannot be attached to this form."
msgid "Besucher dürfen Dateien anhängen"
msgstr "Visitors may attach files"
msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)" msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)"
msgstr "visitors choose a topic (label:number of the help topic)" msgstr "visitors choose a topic (label:number of the help topic)"
msgid "Betreff" msgid "Betreff"
msgstr "Subject" msgstr "Subject"
msgid "Bis zu %1$d Dateien, je höchstens %2$s, zusammen höchstens %3$s. Erlaubt: %4$s"
msgstr "Up to %1$d files, %2$s each at most, %3$s in total. Allowed: %4$s"
msgid "Bitte Server-Adresse und API-Schlüssel eintragen." msgid "Bitte Server-Adresse und API-Schlüssel eintragen."
msgstr "Please enter the server address and API key." msgstr "Please enter the server address and API key."
@@ -68,6 +83,9 @@ msgstr "Please enter a subject (at most 255 characters)."
msgid "Bitte geben Sie einen Betreff an." msgid "Bitte geben Sie einen Betreff an."
msgstr "Please enter a subject." msgstr "Please enter a subject."
msgid "Bitte hängen Sie höchstens %d Dateien an."
msgstr "Please attach no more than %d files."
msgid "Bitte prüfen Sie Ihre Angaben." msgid "Bitte prüfen Sie Ihre Angaben."
msgstr "Please check your details." msgstr "Please check your details."
@@ -95,9 +113,18 @@ msgstr "The form has expired. Please reload the page and try again."
msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab." msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab."
msgstr "That was a bit too fast. Please check your details and submit again." msgstr "That was a bit too fast. Please check your details and submit again."
msgid "Dateianhänge"
msgstr "File attachments"
msgid "Dateien anhängen (optional)"
msgstr "Attach files (optional)"
msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache." msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache."
msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching." msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching."
msgid "Der Dateityp von „%1$s“ ist nicht erlaubt. Erlaubt: %2$s"
msgstr "The file type of “%1$s” is not allowed. Allowed: %2$s"
msgid "Der DeskHub-Server ist nicht erreichbar." msgid "Der DeskHub-Server ist nicht erreichbar."
msgstr "The DeskHub server cannot be reached." msgstr "The DeskHub server cannot be reached."
@@ -143,6 +170,21 @@ msgstr "DeskHub decides"
msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)." msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)."
msgstr "The address where your DeskHub can be reached. https only (http only for local tests)." msgstr "The address where your DeskHub can be reached. https only (http only for local tests)."
msgid "Die Datei „%1$s“ ist zu groß (höchstens %2$s)."
msgstr "The file “%1$s” is too large (%2$s at most)."
msgid "Die Datei „%s“ ist zu groß (höchstens %s)."
msgstr "The file “%s” is too large (%s at most)."
msgid "Die Datei „%s“ konnte nicht gelesen werden."
msgstr "The file “%s” could not be read."
msgid "Die Datei „%s“ konnte nicht hochgeladen werden."
msgstr "The file “%s” could not be uploaded."
msgid "Die Dateien sind zusammen zu groß (höchstens %s)."
msgstr "The files together are too large (%s at most)."
msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen." msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen."
msgstr "The forms will be reloaded from DeskHub on the next request." msgstr "The forms will be reloaded from DeskHub on the next request."
@@ -182,6 +224,9 @@ msgstr "Settings"
msgid "Einwilligung (Datenschutz)" msgid "Einwilligung (Datenschutz)"
msgstr "Consent (data protection)" msgstr "Consent (data protection)"
msgid "Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar."
msgstr "DeskHub decides the allowed file types and sizes (Settings → Uploads): at most 5 files, 10 MB in total. Needs DeskHub 1.0.67 or newer, otherwise the field stays hidden."
msgid "Formular" msgid "Formular"
msgstr "Form" msgstr "Form"
@@ -263,6 +308,9 @@ msgstr "Priority"
msgid "Schlüssel entfernen" msgid "Schlüssel entfernen"
msgstr "Remove key" msgstr "Remove key"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
msgid "Seite mit der Statusabfrage" msgid "Seite mit der Statusabfrage"
msgstr "Page with the status lookup" msgstr "Page with the status lookup"
@@ -365,12 +413,3 @@ msgstr "saved, enter a new key to change it"
msgid "mit festen Voreinstellungen für dieses Formular" msgid "mit festen Voreinstellungen für dieses Formular"
msgstr "with fixed defaults for this form" msgstr "with fixed defaults for this form"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
@@ -17,18 +17,33 @@ msgstr "Department"
msgid "Adresse des DeskHub-Servers" msgid "Adresse des DeskHub-Servers"
msgstr "DeskHub server address" msgstr "DeskHub server address"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Anfrage ohne weitere Angaben" msgid "Anfrage ohne weitere Angaben"
msgstr "Request without further details" msgstr "Request without further details"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Beantwortet" msgid "Beantwortet"
msgstr "Answered" msgstr "Answered"
msgid "Bei diesem Formular können keine Dateien angehängt werden."
msgstr "Files cannot be attached to this form."
msgid "Besucher dürfen Dateien anhängen"
msgstr "Visitors may attach files"
msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)" msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)"
msgstr "visitors choose a topic (label:number of the help topic)" msgstr "visitors choose a topic (label:number of the help topic)"
msgid "Betreff" msgid "Betreff"
msgstr "Subject" msgstr "Subject"
msgid "Bis zu %1$d Dateien, je höchstens %2$s, zusammen höchstens %3$s. Erlaubt: %4$s"
msgstr "Up to %1$d files, %2$s each at most, %3$s in total. Allowed: %4$s"
msgid "Bitte Server-Adresse und API-Schlüssel eintragen." msgid "Bitte Server-Adresse und API-Schlüssel eintragen."
msgstr "Please enter the server address and API key." msgstr "Please enter the server address and API key."
@@ -68,6 +83,9 @@ msgstr "Please enter a subject (at most 255 characters)."
msgid "Bitte geben Sie einen Betreff an." msgid "Bitte geben Sie einen Betreff an."
msgstr "Please enter a subject." msgstr "Please enter a subject."
msgid "Bitte hängen Sie höchstens %d Dateien an."
msgstr "Please attach no more than %d files."
msgid "Bitte prüfen Sie Ihre Angaben." msgid "Bitte prüfen Sie Ihre Angaben."
msgstr "Please check your details." msgstr "Please check your details."
@@ -95,9 +113,18 @@ msgstr "The form has expired. Please reload the page and try again."
msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab." msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab."
msgstr "That was a bit too fast. Please check your details and submit again." msgstr "That was a bit too fast. Please check your details and submit again."
msgid "Dateianhänge"
msgstr "File attachments"
msgid "Dateien anhängen (optional)"
msgstr "Attach files (optional)"
msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache." msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache."
msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching." msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching."
msgid "Der Dateityp von „%1$s“ ist nicht erlaubt. Erlaubt: %2$s"
msgstr "The file type of “%1$s” is not allowed. Allowed: %2$s"
msgid "Der DeskHub-Server ist nicht erreichbar." msgid "Der DeskHub-Server ist nicht erreichbar."
msgstr "The DeskHub server cannot be reached." msgstr "The DeskHub server cannot be reached."
@@ -143,6 +170,21 @@ msgstr "DeskHub decides"
msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)." msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)."
msgstr "The address where your DeskHub can be reached. https only (http only for local tests)." msgstr "The address where your DeskHub can be reached. https only (http only for local tests)."
msgid "Die Datei „%1$s“ ist zu groß (höchstens %2$s)."
msgstr "The file “%1$s” is too large (%2$s at most)."
msgid "Die Datei „%s“ ist zu groß (höchstens %s)."
msgstr "The file “%s” is too large (%s at most)."
msgid "Die Datei „%s“ konnte nicht gelesen werden."
msgstr "The file “%s” could not be read."
msgid "Die Datei „%s“ konnte nicht hochgeladen werden."
msgstr "The file “%s” could not be uploaded."
msgid "Die Dateien sind zusammen zu groß (höchstens %s)."
msgstr "The files together are too large (%s at most)."
msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen." msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen."
msgstr "The forms will be reloaded from DeskHub on the next request." msgstr "The forms will be reloaded from DeskHub on the next request."
@@ -182,6 +224,9 @@ msgstr "Settings"
msgid "Einwilligung (Datenschutz)" msgid "Einwilligung (Datenschutz)"
msgstr "Consent (data protection)" msgstr "Consent (data protection)"
msgid "Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar."
msgstr "DeskHub decides the allowed file types and sizes (Settings → Uploads): at most 5 files, 10 MB in total. Needs DeskHub 1.0.67 or newer, otherwise the field stays hidden."
msgid "Formular" msgid "Formular"
msgstr "Form" msgstr "Form"
@@ -263,6 +308,9 @@ msgstr "Priority"
msgid "Schlüssel entfernen" msgid "Schlüssel entfernen"
msgstr "Remove key" msgstr "Remove key"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
msgid "Seite mit der Statusabfrage" msgid "Seite mit der Statusabfrage"
msgstr "Page with the status lookup" msgstr "Page with the status lookup"
@@ -365,12 +413,3 @@ msgstr "saved, enter a new key to change it"
msgid "mit festen Voreinstellungen für dieses Formular" msgid "mit festen Voreinstellungen für dieses Formular"
msgstr "with fixed defaults for this form" msgstr "with fixed defaults for this form"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
@@ -17,18 +17,33 @@ msgstr "Department"
msgid "Adresse des DeskHub-Servers" msgid "Adresse des DeskHub-Servers"
msgstr "DeskHub server address" msgstr "DeskHub server address"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Anfrage ohne weitere Angaben" msgid "Anfrage ohne weitere Angaben"
msgstr "Request without further details" msgstr "Request without further details"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Beantwortet" msgid "Beantwortet"
msgstr "Answered" msgstr "Answered"
msgid "Bei diesem Formular können keine Dateien angehängt werden."
msgstr "Files cannot be attached to this form."
msgid "Besucher dürfen Dateien anhängen"
msgstr "Visitors may attach files"
msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)" msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)"
msgstr "visitors choose a topic (label:number of the help topic)" msgstr "visitors choose a topic (label:number of the help topic)"
msgid "Betreff" msgid "Betreff"
msgstr "Subject" msgstr "Subject"
msgid "Bis zu %1$d Dateien, je höchstens %2$s, zusammen höchstens %3$s. Erlaubt: %4$s"
msgstr "Up to %1$d files, %2$s each at most, %3$s in total. Allowed: %4$s"
msgid "Bitte Server-Adresse und API-Schlüssel eintragen." msgid "Bitte Server-Adresse und API-Schlüssel eintragen."
msgstr "Please enter the server address and API key." msgstr "Please enter the server address and API key."
@@ -68,6 +83,9 @@ msgstr "Please enter a subject (at most 255 characters)."
msgid "Bitte geben Sie einen Betreff an." msgid "Bitte geben Sie einen Betreff an."
msgstr "Please enter a subject." msgstr "Please enter a subject."
msgid "Bitte hängen Sie höchstens %d Dateien an."
msgstr "Please attach no more than %d files."
msgid "Bitte prüfen Sie Ihre Angaben." msgid "Bitte prüfen Sie Ihre Angaben."
msgstr "Please check your details." msgstr "Please check your details."
@@ -95,9 +113,18 @@ msgstr "The form has expired. Please reload the page and try again."
msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab." msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab."
msgstr "That was a bit too fast. Please check your details and submit again." msgstr "That was a bit too fast. Please check your details and submit again."
msgid "Dateianhänge"
msgstr "File attachments"
msgid "Dateien anhängen (optional)"
msgstr "Attach files (optional)"
msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache." msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache."
msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching." msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching."
msgid "Der Dateityp von „%1$s“ ist nicht erlaubt. Erlaubt: %2$s"
msgstr "The file type of “%1$s” is not allowed. Allowed: %2$s"
msgid "Der DeskHub-Server ist nicht erreichbar." msgid "Der DeskHub-Server ist nicht erreichbar."
msgstr "The DeskHub server cannot be reached." msgstr "The DeskHub server cannot be reached."
@@ -143,6 +170,21 @@ msgstr "DeskHub decides"
msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)." msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)."
msgstr "The address where your DeskHub can be reached. https only (http only for local tests)." msgstr "The address where your DeskHub can be reached. https only (http only for local tests)."
msgid "Die Datei „%1$s“ ist zu groß (höchstens %2$s)."
msgstr "The file “%1$s” is too large (%2$s at most)."
msgid "Die Datei „%s“ ist zu groß (höchstens %s)."
msgstr "The file “%s” is too large (%s at most)."
msgid "Die Datei „%s“ konnte nicht gelesen werden."
msgstr "The file “%s” could not be read."
msgid "Die Datei „%s“ konnte nicht hochgeladen werden."
msgstr "The file “%s” could not be uploaded."
msgid "Die Dateien sind zusammen zu groß (höchstens %s)."
msgstr "The files together are too large (%s at most)."
msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen." msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen."
msgstr "The forms will be reloaded from DeskHub on the next request." msgstr "The forms will be reloaded from DeskHub on the next request."
@@ -182,6 +224,9 @@ msgstr "Settings"
msgid "Einwilligung (Datenschutz)" msgid "Einwilligung (Datenschutz)"
msgstr "Consent (data protection)" msgstr "Consent (data protection)"
msgid "Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar."
msgstr "DeskHub decides the allowed file types and sizes (Settings → Uploads): at most 5 files, 10 MB in total. Needs DeskHub 1.0.67 or newer, otherwise the field stays hidden."
msgid "Formular" msgid "Formular"
msgstr "Form" msgstr "Form"
@@ -263,6 +308,9 @@ msgstr "Priority"
msgid "Schlüssel entfernen" msgid "Schlüssel entfernen"
msgstr "Remove key" msgstr "Remove key"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
msgid "Seite mit der Statusabfrage" msgid "Seite mit der Statusabfrage"
msgstr "Page with the status lookup" msgstr "Page with the status lookup"
@@ -365,12 +413,3 @@ msgstr "saved, enter a new key to change it"
msgid "mit festen Voreinstellungen für dieses Formular" msgid "mit festen Voreinstellungen für dieses Formular"
msgstr "with fixed defaults for this form" msgstr "with fixed defaults for this form"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
@@ -17,18 +17,33 @@ msgstr "Department"
msgid "Adresse des DeskHub-Servers" msgid "Adresse des DeskHub-Servers"
msgstr "DeskHub server address" msgstr "DeskHub server address"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Anfrage ohne weitere Angaben" msgid "Anfrage ohne weitere Angaben"
msgstr "Request without further details" msgstr "Request without further details"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Beantwortet" msgid "Beantwortet"
msgstr "Answered" msgstr "Answered"
msgid "Bei diesem Formular können keine Dateien angehängt werden."
msgstr "Files cannot be attached to this form."
msgid "Besucher dürfen Dateien anhängen"
msgstr "Visitors may attach files"
msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)" msgid "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)"
msgstr "visitors choose a topic (label:number of the help topic)" msgstr "visitors choose a topic (label:number of the help topic)"
msgid "Betreff" msgid "Betreff"
msgstr "Subject" msgstr "Subject"
msgid "Bis zu %1$d Dateien, je höchstens %2$s, zusammen höchstens %3$s. Erlaubt: %4$s"
msgstr "Up to %1$d files, %2$s each at most, %3$s in total. Allowed: %4$s"
msgid "Bitte Server-Adresse und API-Schlüssel eintragen." msgid "Bitte Server-Adresse und API-Schlüssel eintragen."
msgstr "Please enter the server address and API key." msgstr "Please enter the server address and API key."
@@ -68,6 +83,9 @@ msgstr "Please enter a subject (at most 255 characters)."
msgid "Bitte geben Sie einen Betreff an." msgid "Bitte geben Sie einen Betreff an."
msgstr "Please enter a subject." msgstr "Please enter a subject."
msgid "Bitte hängen Sie höchstens %d Dateien an."
msgstr "Please attach no more than %d files."
msgid "Bitte prüfen Sie Ihre Angaben." msgid "Bitte prüfen Sie Ihre Angaben."
msgstr "Please check your details." msgstr "Please check your details."
@@ -95,9 +113,18 @@ msgstr "The form has expired. Please reload the page and try again."
msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab." msgid "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab."
msgstr "That was a bit too fast. Please check your details and submit again." msgstr "That was a bit too fast. Please check your details and submit again."
msgid "Dateianhänge"
msgstr "File attachments"
msgid "Dateien anhängen (optional)"
msgstr "Attach files (optional)"
msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache." msgid "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache."
msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching." msgstr "In addition there is an invisible field that only robots fill in. The form also works with page caching."
msgid "Der Dateityp von „%1$s“ ist nicht erlaubt. Erlaubt: %2$s"
msgstr "The file type of “%1$s” is not allowed. Allowed: %2$s"
msgid "Der DeskHub-Server ist nicht erreichbar." msgid "Der DeskHub-Server ist nicht erreichbar."
msgstr "The DeskHub server cannot be reached." msgstr "The DeskHub server cannot be reached."
@@ -143,6 +170,21 @@ msgstr "DeskHub decides"
msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)." msgid "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests)."
msgstr "The address where your DeskHub can be reached. https only (http only for local tests)." msgstr "The address where your DeskHub can be reached. https only (http only for local tests)."
msgid "Die Datei „%1$s“ ist zu groß (höchstens %2$s)."
msgstr "The file “%1$s” is too large (%2$s at most)."
msgid "Die Datei „%s“ ist zu groß (höchstens %s)."
msgstr "The file “%s” is too large (%s at most)."
msgid "Die Datei „%s“ konnte nicht gelesen werden."
msgstr "The file “%s” could not be read."
msgid "Die Datei „%s“ konnte nicht hochgeladen werden."
msgstr "The file “%s” could not be uploaded."
msgid "Die Dateien sind zusammen zu groß (höchstens %s)."
msgstr "The files together are too large (%s at most)."
msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen." msgid "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen."
msgstr "The forms will be reloaded from DeskHub on the next request." msgstr "The forms will be reloaded from DeskHub on the next request."
@@ -182,6 +224,9 @@ msgstr "Settings"
msgid "Einwilligung (Datenschutz)" msgid "Einwilligung (Datenschutz)"
msgstr "Consent (data protection)" msgstr "Consent (data protection)"
msgid "Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar."
msgstr "DeskHub decides the allowed file types and sizes (Settings → Uploads): at most 5 files, 10 MB in total. Needs DeskHub 1.0.67 or newer, otherwise the field stays hidden."
msgid "Formular" msgid "Formular"
msgstr "Form" msgstr "Form"
@@ -263,6 +308,9 @@ msgstr "Priority"
msgid "Schlüssel entfernen" msgid "Schlüssel entfernen"
msgstr "Remove key" msgstr "Remove key"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
msgid "Seite mit der Statusabfrage" msgid "Seite mit der Statusabfrage"
msgstr "Page with the status lookup" msgstr "Page with the status lookup"
@@ -365,12 +413,3 @@ msgstr "saved, enter a new key to change it"
msgid "mit festen Voreinstellungen für dieses Formular" msgid "mit festen Voreinstellungen für dieses Formular"
msgstr "with fixed defaults for this form" msgstr "with fixed defaults for this form"
msgid "Akzentfarbe"
msgstr "Accent color"
msgid "Automatisch vom Theme übernehmen"
msgstr "Take automatically from the theme"
msgid "Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben."
msgstr "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
+5 -2
View File
@@ -4,7 +4,7 @@ Tags: helpdesk, tickets, support, contact form
Requires at least: 5.8 Requires at least: 5.8
Tested up to: 6.6 Tested up to: 6.6
Requires PHP: 7.4 Requires PHP: 7.4
Stable tag: 1.2.2 Stable tag: 1.3.0
License: GPLv2 or later License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -33,7 +33,7 @@ German is the source language of the plugin. An English translation is included.
= Can visitors attach files? = = Can visitors attach files? =
Not in this version: the DeskHub public API accepts text only. Yes, since version 1.3.0: up to 5 files, 10 MB in total; allowed types and sizes come from DeskHub (needs DeskHub 1.0.67 or newer).
= Where is the API key stored? = = Where is the API key stored? =
@@ -41,6 +41,9 @@ In the WordPress options table. For more safety define `DESKHUB_TICKETS_API_KEY`
== Changelog == == Changelog ==
= 1.3.0 =
* Visitors can attach files (up to 5, 10 MB in total). DeskHub decides the allowed types and sizes; can be switched off in the settings. Needs DeskHub 1.0.67 or newer.
= 1.2.2 = = 1.2.2 =
* Fix: only the button takes the accent color; fields and borders are mixed from the page background and text color and are no longer tinted by theme or accent colors. Real theme buttons are preferred when detecting the accent. * Fix: only the button takes the accent color; fields and borders are mixed from the page background and text color and are no longer tinted by theme or accent colors. Real theme buttons are preferred when detecting the accent.
+79
View File
@@ -357,6 +357,85 @@ ob_start(); Deskhub_Tickets_Settings::render(); $page = (string) ob_get_clean();
$check(str_contains($page, 'type="number" min="0" class="small-text" name="deskhub_tickets_options[topic_id]"'), 'Einstellungen: bei älterem DeskHub bleibt das Zahlenfeld'); $check(str_contains($page, 'type="number" min="0" class="small-text" name="deskhub_tickets_options[topic_id]"'), 'Einstellungen: bei älterem DeskHub bleibt das Zahlenfeld');
$GLOBALS['wp_user']['caps'] = []; $GLOBALS['wp_user']['caps'] = [];
// ── Dateianhänge ────────────────────────────────────────────────────────────
define('DESKHUB_TICKETS_TESTS', true);
$policy = ['enabled' => true, 'maxFiles' => 3, 'maxFileBytes' => 1048576, 'maxTotalBytes' => 2097152, 'allowedExtensions' => ['pdf', 'png', 'txt']];
$check(Deskhub_Tickets_Form::normalize_attachments(null)['enabled'] === false, 'Anhänge: ohne Angabe vom Server (älteres DeskHub) aus');
reset_wp(['attachments' => 1]);
$na = Deskhub_Tickets_Form::normalize_attachments($policy);
$check($na['enabled'] && $na['maxFiles'] === 3 && $na['allowed'] === ['pdf', 'png', 'txt'], 'Anhänge: Angebot des Servers wird übernommen');
$check(Deskhub_Tickets_Form::normalize_attachments(['enabled' => true, 'maxFiles' => 3, 'maxFileBytes' => 100, 'maxTotalBytes' => 100, 'allowedExtensions' => ['<b>', '..']])['enabled'] === false, 'Anhänge: ungültige Dateitypen aus dem Angebot werden verworfen');
reset_wp(['attachments' => 0]);
$check(Deskhub_Tickets_Form::normalize_attachments($policy)['enabled'] === false, 'Anhänge: Option des Plugins schaltet sie aus');
reset_wp(['attachments' => 1]);
$mk = function (string $name, string $content) {
$tmp = tempnam(sys_get_temp_dir(), 'dht');
file_put_contents($tmp, $content);
return ['name' => $name, 'tmp' => $tmp, 'size' => strlen($content)];
};
$files = function (array $list) {
$out = ['name' => [], 'type' => [], 'tmp_name' => [], 'error' => [], 'size' => []];
foreach ($list as $f) { $out['name'][] = $f['name']; $out['type'][] = ''; $out['tmp_name'][] = $f['tmp']; $out['error'][] = $f['error'] ?? UPLOAD_ERR_OK; $out['size'][] = $f['size']; }
return $out;
};
$pol = Deskhub_Tickets_Form::normalize_attachments($policy);
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([$mk('Bericht.pdf', '%PDF-test'), $mk('Notiz.txt', 'Hallo')]), $pol);
$check($e === [] && count($a) === 2 && $a[0]['name'] === 'Bericht.pdf' && base64_decode($a[1]['data']) === 'Hallo', 'Anhänge: erlaubte Dateien werden Base64-kodiert übernommen');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([$mk('x.exe', 'MZ')]), $pol);
$check(count($e) === 1 && $a === [] && str_contains($e[0], 'nicht erlaubt'), 'Anhänge: .exe wird abgelehnt');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([$mk('a.php', '<?php')]), $pol);
$check(count($e) === 1 && $a === [], 'Anhänge: .php wird abgelehnt');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([$mk('a.docx', 'x')]), $pol);
$check(count($e) === 1 && $a === [], 'Anhänge: nicht freigegebener Typ (.docx) wird abgelehnt');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([$mk('gross.pdf', str_repeat('x', 1048577))]), $pol);
$check(count($e) === 1 && str_contains($e[0], 'zu groß') && $a === [], 'Anhänge: zu große Datei wird abgelehnt');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([$mk('1.txt', 'a'), $mk('2.txt', 'b'), $mk('3.txt', 'c'), $mk('4.txt', 'd')]), $pol);
$check(count($e) === 1 && str_contains($e[0], 'höchstens 3') && count($a) === 3, 'Anhänge: mehr als erlaubt wird abgelehnt');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([$mk('a.txt', str_repeat('x', 900000)), $mk('b.txt', str_repeat('x', 900000)), $mk('c.txt', str_repeat('x', 900000))]), $pol);
$check(count($e) === 1 && str_contains($e[0], 'zusammen'), 'Anhänge: zusammen zu groß wird abgelehnt');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([['name' => '', 'tmp' => '', 'size' => 0, 'error' => UPLOAD_ERR_NO_FILE]]), $pol);
$check($e === [] && $a === [], 'Anhänge: nichts ausgewählt ist kein Fehler');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([['name' => 'a.pdf', 'tmp' => '', 'size' => 0, 'error' => UPLOAD_ERR_INI_SIZE]]), $pol);
$check(count($e) === 1 && str_contains($e[0], 'zu groß'), 'Anhänge: vom Server abgelehnte Größe wird verständlich gemeldet');
[$e] = Deskhub_Tickets_Form::collect_attachments($files([$mk('a.pdf', 'x')]), Deskhub_Tickets_Form::normalize_attachments(null));
$check(count($e) === 1, 'Anhänge: ohne Angebot kein Anhang');
[$e, $a] = Deskhub_Tickets_Form::collect_attachments($files([$mk('../../etc/passwd.txt', 'x')]), $pol);
$check($e === [] && $a[0]['name'] !== '' && !str_contains($a[0]['name'], '/'), 'Anhänge: Pfadanteile im Dateinamen werden entfernt: ' . ($a[0]['name'] ?? ''));
// Formular zeigt das Dateifeld nur, wenn DeskHub und Plugin es anbieten; Absenden schickt die Anhänge mit
$fx = form_fixture();
$fxAtt = $fx;
$fxAtt['attachments'] = $policy;
reset_wp(['attachments' => 1]);
$log = [];
$GLOBALS['wp_http_handler'] = new_server($log, [3 => $fxAtt]);
$html = render_form(['topic' => '3']);
$check(str_contains($html, 'enctype="multipart/form-data"') && str_contains($html, 'name="dht_files[]"') && str_contains($html, 'accept=".pdf,.png,.txt"') && str_contains($html, 'Bis zu 3 Dateien'), 'Formular: Dateifeld mit Hinweis, erlaubten Typen und Formularkodierung');
reset_wp(['attachments' => 0]);
$GLOBALS['wp_http_handler'] = new_server($log, [3 => $fxAtt]);
$check(!str_contains(render_form(['topic' => '3']), 'dht_files'), 'Formular: Option aus: kein Dateifeld');
reset_wp(['attachments' => 1]);
$GLOBALS['wp_http_handler'] = new_server($log, [3 => $fx]);
$check(!str_contains(render_form(['topic' => '3']), 'dht_files'), 'Formular: Server bietet keine Anhänge an: kein Dateifeld');
reset_wp(['attachments' => 1]);
$log = [];
$GLOBALS['wp_http_handler'] = new_server($log, [3 => $fxAtt]);
$html = render_form(['topic' => '3']);
$_FILES = ['dht_files' => $files([$mk('Foto.png', 'PNGDATA'), $mk('Notiz.txt', 'Text')])];
$loc = run_form_post(valid_post($html, ['dht_f' => [11 => 'Drucker', 14 => '1']]));
$st = state_from($loc);
$sent = $posts($log)[0]['body'] ?? [];
$check($st && !empty($st['ok']) && count($sent['attachments'] ?? []) === 2 && $sent['attachments'][0]['name'] === 'Foto.png' && base64_decode($sent['attachments'][1]['data']) === 'Text', 'Absenden: die Anhänge gehen Base64-kodiert an DeskHub: ' . json_encode($st));
$_FILES = ['dht_files' => $files([$mk('boese.exe', 'MZ')])];
$log = [];
$GLOBALS['wp_http_handler'] = new_server($log, [3 => $fxAtt]);
$loc = run_form_post(valid_post($html, ['dht_f' => [11 => 'Drucker', 14 => '1']]));
$st = state_from($loc);
$check($st && empty($st['ok']) && $posts($log) === [] && str_contains(implode(' ', $st['errors'] ?? []), 'nicht erlaubt'), 'Absenden: ein gesperrter Dateityp stoppt vor dem Senden mit verständlicher Meldung');
$_FILES = [];
// ── Verbindungstest ───────────────────────────────────────────────────────── // ── Verbindungstest ─────────────────────────────────────────────────────────
reset_wp(); reset_wp();
foreach ([[404, true, 'Tickets lesen'], [403, true, 'keine Tickets lesen'], [401, false, 'abgelehnt'], [500, false, '500']] as [$code, $ok, $needle]) { foreach ([[404, true, 'Tickets lesen'], [403, true, 'keine Tickets lesen'], [401, false, 'abgelehnt'], [500, false, '500']] as [$code, $ok, $needle]) {
+3
View File
@@ -151,3 +151,6 @@ if (!function_exists('sanitize_hex_color')) {
if (!function_exists('checked')) { if (!function_exists('checked')) {
function checked($a, $b = true, $echo = true) { $r = (string) $a === (string) $b ? " checked='checked'" : ''; if ($echo) echo $r; return $r; } function checked($a, $b = true, $echo = true) { $r = (string) $a === (string) $b ? " checked='checked'" : ''; if ($echo) echo $r; return $r; }
} }
if (!function_exists('sanitize_file_name')) {
function sanitize_file_name($f) { $f = basename(str_replace(chr(92), '/', (string) $f)); $f = preg_replace('/[^A-Za-z0-9._ -]+/', '-', $f); return trim((string) $f, '.- ') === '' ? '' : (string) $f; }
}
+17 -4
View File
@@ -2,10 +2,15 @@
"API-Schlüssel": "API key", "API-Schlüssel": "API key",
"Abteilung": "Department", "Abteilung": "Department",
"Adresse des DeskHub-Servers": "DeskHub server address", "Adresse des DeskHub-Servers": "DeskHub server address",
"Akzentfarbe": "Accent color",
"Anfrage ohne weitere Angaben": "Request without further details", "Anfrage ohne weitere Angaben": "Request without further details",
"Automatisch vom Theme übernehmen": "Take automatically from the theme",
"Beantwortet": "Answered", "Beantwortet": "Answered",
"Bei diesem Formular können keine Dateien angehängt werden.": "Files cannot be attached to this form.",
"Besucher dürfen Dateien anhängen": "Visitors may attach files",
"Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)": "visitors choose a topic (label:number of the help topic)", "Besucher wählen ein Thema aus (Bezeichnung:Nummer des Hilfethemas)": "visitors choose a topic (label:number of the help topic)",
"Betreff": "Subject", "Betreff": "Subject",
"Bis zu %1$d Dateien, je höchstens %2$s, zusammen höchstens %3$s. Erlaubt: %4$s": "Up to %1$d files, %2$s each at most, %3$s in total. Allowed: %4$s",
"Bitte Server-Adresse und API-Schlüssel eintragen.": "Please enter the server address and API key.", "Bitte Server-Adresse und API-Schlüssel eintragen.": "Please enter the server address and API key.",
"Bitte beschreiben Sie Ihr Anliegen.": "Please describe your request.", "Bitte beschreiben Sie Ihr Anliegen.": "Please describe your request.",
"Bitte bestätigen Sie „%s“.": "Please confirm “%s”.", "Bitte bestätigen Sie „%s“.": "Please confirm “%s”.",
@@ -19,6 +24,7 @@
"Bitte geben Sie eine gültige E-Mail-Adresse an.": "Please enter a valid email address.", "Bitte geben Sie eine gültige E-Mail-Adresse an.": "Please enter a valid email address.",
"Bitte geben Sie einen Betreff an (höchstens 255 Zeichen).": "Please enter a subject (at most 255 characters).", "Bitte geben Sie einen Betreff an (höchstens 255 Zeichen).": "Please enter a subject (at most 255 characters).",
"Bitte geben Sie einen Betreff an.": "Please enter a subject.", "Bitte geben Sie einen Betreff an.": "Please enter a subject.",
"Bitte hängen Sie höchstens %d Dateien an.": "Please attach no more than %d files.",
"Bitte prüfen Sie Ihre Angaben.": "Please check your details.", "Bitte prüfen Sie Ihre Angaben.": "Please check your details.",
"Bitte stimmen Sie der Verarbeitung Ihrer Angaben zu.": "Please agree to the processing of your data.", "Bitte stimmen Sie der Verarbeitung Ihrer Angaben zu.": "Please agree to the processing of your data.",
"Bitte wählen Sie bei „%s“ eine der angebotenen Möglichkeiten.": "Please choose one of the offered options for “%s”.", "Bitte wählen Sie bei „%s“ eine der angebotenen Möglichkeiten.": "Please choose one of the offered options for “%s”.",
@@ -28,7 +34,10 @@
"Dafür fehlt die Berechtigung.": "You do not have permission to do this.", "Dafür fehlt die Berechtigung.": "You do not have permission to do this.",
"Das Formular ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es noch einmal.": "The form has expired. Please reload the page and try again.", "Das Formular ist abgelaufen. Bitte laden Sie die Seite neu und versuchen Sie es noch einmal.": "The form has expired. Please reload the page and try again.",
"Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab.": "That was a bit too fast. Please check your details and submit again.", "Das ging etwas zu schnell. Bitte prüfen Sie Ihre Angaben und senden Sie noch einmal ab.": "That was a bit too fast. Please check your details and submit again.",
"Dateianhänge": "File attachments",
"Dateien anhängen (optional)": "Attach files (optional)",
"Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache.": "In addition there is an invisible field that only robots fill in. The form also works with page caching.", "Dazu kommt ein unsichtbares Feld, das nur Roboter ausfüllen. Das Formular funktioniert auch mit Seiten-Cache.": "In addition there is an invisible field that only robots fill in. The form also works with page caching.",
"Der Dateityp von „%1$s“ ist nicht erlaubt. Erlaubt: %2$s": "The file type of “%1$s” is not allowed. Allowed: %2$s",
"Der DeskHub-Server ist nicht erreichbar.": "The DeskHub server cannot be reached.", "Der DeskHub-Server ist nicht erreichbar.": "The DeskHub server cannot be reached.",
"Der DeskHub-Server kennt die Formular-Schnittstelle noch nicht (bitte DeskHub aktualisieren). Bis dahin wird das einfache Formular ohne eigene Felder gezeigt. (Diese Meldung sehen nur Administratoren.)": "The DeskHub server does not know the form interface yet (please update DeskHub). Until then the simple form without custom fields is shown. (Only administrators see this message.)", "Der DeskHub-Server kennt die Formular-Schnittstelle noch nicht (bitte DeskHub aktualisieren). Bis dahin wird das einfache Formular ohne eigene Felder gezeigt. (Diese Meldung sehen nur Administratoren.)": "The DeskHub server does not know the form interface yet (please update DeskHub). Until then the simple form without custom fields is shown. (Only administrators see this message.)",
"Der DeskHub-Server kennt die Formular-Schnittstelle noch nicht.": "The DeskHub server does not know the form interface yet.", "Der DeskHub-Server kennt die Formular-Schnittstelle noch nicht.": "The DeskHub server does not know the form interface yet.",
@@ -44,6 +53,11 @@
"DeskHub Tickets ist noch nicht eingerichtet: Bitte unter Einstellungen → DeskHub Tickets Server-Adresse und API-Schlüssel eintragen. (Diese Meldung sehen nur Administratoren.)": "DeskHub Tickets is not set up yet: please enter the server address and API key under Settings → DeskHub Tickets. (Only administrators see this message.)", "DeskHub Tickets ist noch nicht eingerichtet: Bitte unter Einstellungen → DeskHub Tickets Server-Adresse und API-Schlüssel eintragen. (Diese Meldung sehen nur Administratoren.)": "DeskHub Tickets is not set up yet: please enter the server address and API key under Settings → DeskHub Tickets. (Only administrators see this message.)",
"DeskHub entscheidet": "DeskHub decides", "DeskHub entscheidet": "DeskHub decides",
"Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests).": "The address where your DeskHub can be reached. https only (http only for local tests).", "Die Adresse, unter der Ihr DeskHub erreichbar ist. Nur https (http nur für lokale Tests).": "The address where your DeskHub can be reached. https only (http only for local tests).",
"Die Datei „%1$s“ ist zu groß (höchstens %2$s).": "The file “%1$s” is too large (%2$s at most).",
"Die Datei „%s“ ist zu groß (höchstens %s).": "The file “%s” is too large (%s at most).",
"Die Datei „%s“ konnte nicht gelesen werden.": "The file “%s” could not be read.",
"Die Datei „%s“ konnte nicht hochgeladen werden.": "The file “%s” could not be uploaded.",
"Die Dateien sind zusammen zu groß (höchstens %s).": "The files together are too large (%s at most).",
"Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen.": "The forms will be reloaded from DeskHub on the next request.", "Die Formulare werden beim nächsten Aufruf neu aus DeskHub geladen.": "The forms will be reloaded from DeskHub on the next request.",
"Die Nummern stehen in DeskHub bei der jeweiligen Abteilung, dem Hilfethema und der Priorität. 0 = DeskHub entscheidet (Standardabteilung, Regeln des Hilfethemas). Im Shortcode lassen sich die Werte je Formular überschreiben.": "The numbers are shown in DeskHub next to each department, help topic and priority. 0 = DeskHub decides (default department, rules of the help topic). The values can be overridden per form in the shortcode.", "Die Nummern stehen in DeskHub bei der jeweiligen Abteilung, dem Hilfethema und der Priorität. 0 = DeskHub entscheidet (Standardabteilung, Regeln des Hilfethemas). Im Shortcode lassen sich die Werte je Formular überschreiben.": "The numbers are shown in DeskHub next to each department, help topic and priority. 0 = DeskHub decides (default department, rules of the help topic). The values can be overridden per form in the shortcode.",
"Die Server-Adresse ist ungültig.": "The server address is invalid.", "Die Server-Adresse ist ungültig.": "The server address is invalid.",
@@ -57,6 +71,7 @@
"Eingebaut": "Built in", "Eingebaut": "Built in",
"Einstellungen": "Settings", "Einstellungen": "Settings",
"Einwilligung (Datenschutz)": "Consent (data protection)", "Einwilligung (Datenschutz)": "Consent (data protection)",
"Erlaubte Dateitypen und Größen bestimmt DeskHub (Einstellungen → Uploads): höchstens 5 Dateien, zusammen 10 MB. Braucht DeskHub 1.0.67 oder neuer, sonst bleibt das Feld unsichtbar.": "DeskHub decides the allowed file types and sizes (Settings → Uploads): at most 5 files, 10 MB in total. Needs DeskHub 1.0.67 or newer, otherwise the field stays hidden.",
"Formular": "Form", "Formular": "Form",
"Formular zum Anlegen eines Tickets": "form for creating a ticket", "Formular zum Anlegen eines Tickets": "form for creating a ticket",
"Formulare neu laden": "Reload forms", "Formulare neu laden": "Reload forms",
@@ -84,6 +99,7 @@
"Optional: Nach dem Absenden erscheint ein Link „Stand abfragen“ zu dieser Seite (dort steht der Shortcode [deskhub_status]).": "Optional: after submitting, a link “Check status” to this page appears (it contains the shortcode [deskhub_status]).", "Optional: Nach dem Absenden erscheint ein Link „Stand abfragen“ zu dieser Seite (dort steht der Shortcode [deskhub_status]).": "Optional: after submitting, a link “Check status” to this page appears (it contains the shortcode [deskhub_status]).",
"Priorität": "Priority", "Priorität": "Priority",
"Schlüssel entfernen": "Remove key", "Schlüssel entfernen": "Remove key",
"Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben.": "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here.",
"Seite mit der Statusabfrage": "Page with the status lookup", "Seite mit der Statusabfrage": "Page with the status lookup",
"Sekunden": "seconds", "Sekunden": "seconds",
"Sie": "You", "Sie": "You",
@@ -117,8 +133,5 @@
"aus der wp-config.php": "from wp-config.php", "aus der wp-config.php": "from wp-config.php",
"entfernen": "remove", "entfernen": "remove",
"gespeichert, zum Ändern neuen Schlüssel eintragen": "saved, enter a new key to change it", "gespeichert, zum Ändern neuen Schlüssel eintragen": "saved, enter a new key to change it",
"mit festen Voreinstellungen für dieses Formular": "with fixed defaults for this form", "mit festen Voreinstellungen für dieses Formular": "with fixed defaults for this form"
"Akzentfarbe": "Accent color",
"Automatisch vom Theme übernehmen": "Take automatically from the theme",
"Schrift, Hintergrund und Rahmen übernimmt das Formular immer vom Theme. Die Akzentfarbe (Knopf, Hervorhebung) wird automatisch aus Knöpfen und Links der Seite gelesen; hier lässt sie sich fest vorgeben.": "The form always takes font, background and border from the theme. The accent color (button, highlights) is read automatically from buttons and links of the page; you can set it here."
} }