diff --git a/js/nc_connector_source_ui.js b/js/nc_connector_source_ui.js index d69b108..f923ca3 100644 --- a/js/nc_connector_source_ui.js +++ b/js/nc_connector_source_ui.js @@ -1,6 +1,112 @@ (function () { 'use strict'; + function escapeHtml(value) { + return String(value == null ? '' : value).replace(/[&<>"']/g, function (c) { + return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]; + }); + } + + function fieldNodes(form, fieldName) { + return [].slice.call(form.querySelectorAll('[name="'+fieldName.replace(/"/g, '\\"')+'"]')); + } + + function clearPickerErrors(form) { + [].slice.call(form.querySelectorAll('[data-source-picker-error]')).forEach(function (node) { node.remove(); }); + [].slice.call(form.querySelectorAll('[data-source-picker-invalid="1"]')).forEach(function (field) { + field.removeAttribute('data-source-picker-invalid'); + if (field.getAttribute('aria-invalid') === 'true') field.removeAttribute('aria-invalid'); + field.style.borderColor = ''; + field.style.boxShadow = ''; + }); + } + + function showPickerError(form, data) { + clearPickerErrors(form); + var message = data && data.message ? data.message : 'Die Nextcloud-Ordnerauswahl konnte nicht gestartet werden.'; + var fields = data && Array.isArray(data.fields) ? data.fields : []; + + var summary = document.createElement('div'); + summary.dataset.sourcePickerError = '1'; + summary.className = 'bratonien-main-cache__warning'; + summary.style.margin = '0 0 1rem'; + summary.style.padding = '.75rem'; + summary.style.border = '1px solid currentColor'; + summary.innerHTML = 'Ordnerauswahl nicht möglich: '+escapeHtml(message); + form.insertBefore(summary, form.firstChild); + + var first = null; + fields.forEach(function (fieldName) { + fieldNodes(form, fieldName).forEach(function (field) { + field.dataset.sourcePickerInvalid = '1'; + field.setAttribute('aria-invalid', 'true'); + field.style.borderColor = '#d65a5a'; + field.style.boxShadow = '0 0 0 1px #d65a5a'; + if (!first) first = field; + }); + }); + + if (first) { + first.scrollIntoView({block:'center', behavior:'smooth'}); + window.setTimeout(function () { first.focus(); }, 150); + } else { + summary.scrollIntoView({block:'center', behavior:'smooth'}); + } + } + + function jsonResponse(response) { + return response.json().then(function (data) { + if (!response.ok || !data.ok) throw data; + return data; + }); + } + + function startSourcePicker(form, button) { + clearPickerErrors(form); + if (!form.reportValidity()) return; + + button.disabled = true; + var originalText = button.textContent; + button.textContent = 'Verbindung prüfen …'; + + var saveBody = new FormData(form); + fetch('plugins/bratonien_tools/nc-connector-edit-save.php', { + method:'POST', + credentials:'same-origin', + cache:'no-store', + headers:{'Accept':'application/json'}, + body:saveBody + }) + .then(jsonResponse) + .then(function () { + button.textContent = 'Nextcloud-Ordner laden …'; + var pickerBody = new FormData(); + var token = form.querySelector('input[name="pwg_token"]'); + var id = form.querySelector('input[name="connection_id"]'); + pickerBody.append('pwg_token', token ? token.value : ''); + pickerBody.append('connection_id', id ? id.value : ''); + return fetch('plugins/bratonien_tools/nc-connector-source-picker-start.php', { + method:'POST', + credentials:'same-origin', + cache:'no-store', + headers:{'Accept':'application/json'}, + body:pickerBody + }).then(jsonResponse); + }) + .then(function () { + try { + sessionStorage.setItem('bratonienNcWizardMode', 'migrate'); + sessionStorage.setItem('bratonienNcWizardOpen', '1'); + } catch (e) {} + window.location.reload(); + }) + .catch(function (error) { + showPickerError(form, error && typeof error === 'object' ? error : {message:String(error), fields:[]}); + button.disabled = false; + button.textContent = originalText; + }); + } + function enhanceMigrationButtons(root) { [].slice.call(root.querySelectorAll('button[value="nc_connector_migrate_start"]')).forEach(function (button) { button.textContent = 'Nextcloud-Ordner auswählen & migrieren'; @@ -14,6 +120,9 @@ form.dataset.sourceUiEnhanced = '1'; var headings = [].slice.call(form.querySelectorAll('h5')); + var webdavHeading = headings.find(function (node) { + return (node.textContent || '').trim() === 'Nextcloud / WebDAV'; + }); var legacyHeading = headings.find(function (node) { return (node.textContent || '').trim() === 'Bestehender Legacy-Weg'; }); @@ -23,11 +132,29 @@ var storageList = form.querySelector('[data-storage-list]'); var addStorage = form.querySelector('[data-add-storage]'); + if (webdavHeading && !form.querySelector('[data-webdav-source-picker]')) { + var webdavGrid = webdavHeading.nextElementSibling; + while (webdavGrid && !webdavGrid.classList.contains('bratonien-form-grid')) webdavGrid = webdavGrid.nextElementSibling; + if (webdavGrid) { + var picker = document.createElement('div'); + picker.dataset.webdavSourcePicker = '1'; + picker.style.margin = '.8rem 0 1rem'; + picker.innerHTML = '
WebDAV-Quelle: Du musst keinen Pfad kennen. Die Ordner des oben eingetragenen Nextcloud-Benutzers werden automatisch geladen und können anschließend ausgewählt werden.
'; + var button = document.createElement('button'); + button.type = 'button'; + button.className = 'buttonLike'; + button.textContent = 'Nextcloud-Ordner automatisch auswählen'; + button.addEventListener('click', function () { startSourcePicker(form, button); }); + picker.appendChild(button); + webdavGrid.insertAdjacentElement('afterend', picker); + } + } + if (legacyHeading && !form.querySelector('[data-webdav-source-note]')) { var note = document.createElement('p'); note.dataset.webdavSourceNote = '1'; note.className = 'bratonien-main-cache__warning'; - note.innerHTML = 'Wichtig: Der folgende SMB-/lokale Speicher gehört ausschließlich zum bisherigen Legacy-Fallback. Er wird nicht als WebDAV-Quelle übernommen. Die WebDAV-Quellordner werden beim Start der Migration direkt aus Nextcloud angezeigt und ausgewählt.'; + note.innerHTML = 'Wichtig: Der folgende SMB-/lokale Speicher gehört ausschließlich zum bisherigen Legacy-Fallback. Er wird nicht als WebDAV-Quelle übernommen.'; legacyHeading.insertAdjacentElement('beforebegin', note); } diff --git a/main.inc.php b/main.inc.php index c1fc095..9b803a5 100644 --- a/main.inc.php +++ b/main.inc.php @@ -1,7 +1,7 @@ false, + 'message'=>(string)$message, + 'fields'=>array_values(array_unique($fields)), + )); +} + +if (!defined('BRATONIEN_TOOLS_PATH')) +{ + bratonien_tools_nc_source_picker_json(404, array('ok'=>false, 'message'=>'Bratonien Tools ist nicht aktiv.', 'fields'=>array())); +} +if (!function_exists('is_admin') || !is_admin()) +{ + bratonien_tools_nc_source_picker_json(403, array('ok'=>false, 'message'=>'Administratorrechte erforderlich.', 'fields'=>array())); +} +if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') +{ + bratonien_tools_nc_source_picker_json(405, array('ok'=>false, 'message'=>'Nur POST ist erlaubt.', 'fields'=>array())); +} + +try +{ + check_pwg_token(); + require_once(BRATONIEN_TOOLS_PATH.'include/tool_registry.inc.php'); + + $id = (int)($_POST['connection_id'] ?? 0); + $connection = bratonien_tools_nc_connector_connection($id, true); + if (!$connection) + { + bratonien_tools_nc_source_picker_fail('Die zu bearbeitende Verbindung wurde nicht gefunden.'); + } + if ((string)$connection['adapter'] !== 'local') + { + bratonien_tools_nc_source_picker_fail('Die automatische Migrationsauswahl ist nur für die bestehende Legacy-Verbindung vorgesehen.'); + } + + $config = isset($connection['config']) && is_array($connection['config']) ? $connection['config'] : array(); + $credentials = bratonien_tools_nc_connector_scoped_secret($connection); + + $base_url = trim((string)($config['nextcloud_url'] ?? '')); + $username = trim((string)($credentials['nextcloud_user'] ?? '')); + $password = (string)($credentials['nextcloud_password'] ?? ''); + + $missing = array(); + if ($base_url === '') $missing[] = 'nc_nextcloud_url'; + if ($username === '') $missing[] = 'nc_nextcloud_user'; + if ($password === '') $missing[] = 'nc_nextcloud_password'; + if ($missing) + { + bratonien_tools_nc_source_picker_fail( + 'Für die automatische Ordnerauswahl müssen Nextcloud-Adresse, Benutzer und Passwort gespeichert sein.', + $missing + ); + } + + bratonien_tools_nc_connector_prepare_webdav_wizard_from_connection($connection, 'migrate'); + + $state = bratonien_tools_nc_wizard_state(); + if ((int)($state['step'] ?? 0) !== 2 || empty($state['scan_ok']) || empty($state['directory_selection_ready'])) + { + $detail = trim((string)($state['technical_error'] ?? '')); + bratonien_tools_nc_source_picker_fail( + $detail !== '' ? 'Die Nextcloud-Ordner konnten nicht geladen werden: '.$detail : 'Die Nextcloud-Ordner konnten nicht geladen werden.', + array('nc_nextcloud_url','nc_nextcloud_user','nc_nextcloud_password') + ); + } + + bratonien_tools_nc_source_picker_json(200, array( + 'ok'=>true, + 'message'=>'Nextcloud-Ordner wurden geladen. Die Auswahl wird geöffnet.', + 'fields'=>array(), + )); +} +catch (Throwable $e) +{ + $message = trim($e->getMessage()); + if ($message === '') $message = 'Die Nextcloud-Ordnerauswahl konnte nicht vorbereitet werden.'; + bratonien_tools_nc_source_picker_fail( + $message, + array('nc_nextcloud_url','nc_nextcloud_user','nc_nextcloud_password') + ); +}