diff --git a/include/nc_connector_wizard_user_scope.inc.php b/include/nc_connector_wizard_user_scope.inc.php index 0ed6185..4c6a603 100644 --- a/include/nc_connector_wizard_user_scope.inc.php +++ b/include/nc_connector_wizard_user_scope.inc.php @@ -4,123 +4,6 @@ if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!'); } -function bratonien_tools_nc_wizard_scan_user_scoped() -{ - $state = bratonien_tools_nc_wizard_state(); - $host_input = trim((string)($_POST['nc_wizard_host'] ?? $state['host_input'])); - $username = trim((string)($_POST['nc_wizard_user'] ?? $state['username'])); - $password = array_key_exists('nc_wizard_password', $_POST) ? (string)$_POST['nc_wizard_password'] : (string)$state['_password']; - - $state['step'] = 1; - $state['host_input'] = $host_input; - $state['username'] = $username; - $state['_password'] = $password; - bratonien_tools_nc_wizard_store($state); - - if ($username === '' || $password === '') throw new RuntimeException('Nextcloud-Benutzer und Passwort werden für den Scan benötigt.'); - - $base_url = ''; - $status_data = null; - foreach (bratonien_tools_nc_wizard_candidate_urls($host_input) as $candidate_url) - { - try - { - $response = bratonien_tools_nc_wizard_http($candidate_url.'/status.php'); - if ($response['status'] < 200 || $response['status'] >= 300) continue; - $candidate_status = json_decode($response['body'], true); - if (!is_array($candidate_status) || empty($candidate_status['installed'])) continue; - $base_url = $candidate_url; - $status_data = $candidate_status; - break; - } - catch (Throwable $ignored) - { - } - } - - if ($base_url === '' || !is_array($status_data)) throw new RuntimeException('Unter dieser Adresse konnte keine Nextcloud erreicht werden. HTTP und HTTPS wurden automatisch geprüft.'); - - $user_response = bratonien_tools_nc_wizard_http( - $base_url.'/ocs/v2.php/cloud/user?format=json', - $username, - $password, - array('OCS-APIRequest: true') - ); - if ($user_response['status'] === 401 || $user_response['status'] === 403) throw new RuntimeException('Nextcloud hat Benutzername oder Passwort abgelehnt.'); - if ($user_response['status'] < 200 || $user_response['status'] >= 300) throw new RuntimeException('Nextcloud ist erreichbar, aber die Anmeldung konnte nicht geprüft werden.'); - - $user_data = bratonien_tools_nc_wizard_ocs_data($user_response['body']); - $resolved_username = trim((string)($user_data['id'] ?? $username)); - if ($resolved_username === '') $resolved_username = $username; - $url_host = (string)parse_url($base_url, PHP_URL_HOST); - - $state = array_merge($state, array( - 'step'=>2, - 'scan_ok'=>true, - 'base_url'=>$base_url, - 'host_input'=>$host_input, - 'username'=>$resolved_username, - 'display_name'=>(string)($user_data['display-name'] ?? $user_data['displayname'] ?? ''), - 'version'=>(string)($status_data['versionstring'] ?? $status_data['version'] ?? ''), - 'product'=>(string)($status_data['productname'] ?? 'Nextcloud'), - 'users'=>array(), - 'can_list_users'=>false, - 'showcase_user'=>$resolved_username, - 'connection_name'=>$url_host !== '' ? $url_host : 'Nextcloud', - 'scan_message'=>'Nextcloud wurde erkannt und der Benutzerzugriff wurde bestätigt.', - '_password'=>$password, - 'api_status'=>'pending','api_username'=>'','api_error'=>'', - 'db_host'=>strtolower($url_host),'db_port'=>'5432','db_database'=>'nextcloud','db_user'=>'','db_password_set'=>false,'_db_password'=>'', - 'source_view'=>'piwigo_showcase_sources','activity_view'=>'piwigo_showcase_activity', - 'gallery_root'=>rtrim(PHPWG_ROOT_PATH, '/').'/galleries/nextcloud', - 'storages'=>array(),'storage_candidates'=>array(), - 'technical_stage'=>'auto_check','technical_source'=>'Automatische Prüfung','technical_error'=>'','technical_complete'=>false, - 'directory_selection_ready'=>false, - )); - - if (!bratonien_tools_nc_wizard_apply_known_database_profile($state)) - { - $state['technical_stage'] = 'database_details'; - $state['technical_source'] = 'Keine bekannte Reader-Verbindung gefunden'; - $state['technical_error'] = 'Für diese Nextcloud ist noch keine bekannte Datenbank-Reader-Verbindung gespeichert.'; - bratonien_tools_nc_wizard_store($state); - return array('message'=>'Nextcloud wurde gefunden. Für den Datenzugriff wird eine separate Reader-Verbindung benötigt.'); - } - - $known_storages = isset($state['storages']) && is_array($state['storages']) ? $state['storages'] : array(); - try - { - bratonien_tools_nc_wizard_finish_data_access_for_selection($state, $known_storages); - } - catch (Throwable $e) - { - $state['technical_complete'] = false; - $state['technical_stage'] = 'database_details'; - $state['technical_error'] = $e->getMessage(); - } - bratonien_tools_nc_wizard_store($state); - - if ($state['technical_stage'] === 'database_details') return array('message'=>'Nextcloud wurde gefunden. Die bekannte Reader-Verbindung konnte noch nicht vollständig bestätigt werden.'); - return array('message'=>'Nextcloud und Datenzugriff wurden bestätigt. Jetzt können die Verzeichnisse des angemeldeten Benutzers gewählt werden.'); -} - -function bratonien_tools_nc_wizard_select_current_user() -{ - $state = bratonien_tools_nc_wizard_state(); - if (empty($state['scan_ok'])) throw new RuntimeException('Bitte zuerst Nextcloud erfolgreich scannen.'); - if (empty($state['technical_complete'])) throw new RuntimeException('Die Verbindung ist noch nicht vollständig geprüft.'); - - $connection_name = trim((string)($_POST['nc_wizard_connection_name'] ?? $state['connection_name'])); - if ($connection_name === '') throw new RuntimeException('Bitte einen Namen für die Verbindung angeben.'); - - $state['connection_name'] = $connection_name; - $state['showcase_user'] = (string)$state['username']; - $state['step'] = 3; - $state['api_error'] = ''; - bratonien_tools_nc_wizard_store($state); - return array('message'=>'Nextcloud-Benutzer übernommen. Jetzt folgt der Piwigo-API-Zugang.'); -} - function bratonien_tools_nc_wizard_webdav_list(array $state, $path = '') { if (empty($state['scan_ok']) || trim((string)$state['base_url']) === '' || trim((string)$state['username']) === '' || (string)$state['_password'] === '') @@ -153,6 +36,7 @@ function bratonien_tools_nc_wizard_webdav_list(array $state, $path = '') $errno = curl_errno($ch); $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); + if ($response === false || $errno !== 0) throw new RuntimeException('Nextcloud-Verzeichnisse konnten nicht geladen werden.'); if ($status === 401 || $status === 403) throw new RuntimeException('Nextcloud hat den Zugriff auf dieses Verzeichnis abgelehnt.'); if ($status !== 207) throw new RuntimeException('Nextcloud-Verzeichnisabfrage antwortete mit HTTP '.$status.'.'); @@ -161,6 +45,7 @@ function bratonien_tools_nc_wizard_webdav_list(array $state, $path = '') $xml = simplexml_load_string((string)$response); if ($xml === false) throw new RuntimeException('Nextcloud hat eine ungültige WebDAV-Antwort geliefert.'); $xml->registerXPathNamespace('d', 'DAV:'); + $children = array(); foreach ($xml->xpath('//d:response') as $item) { @@ -168,10 +53,12 @@ function bratonien_tools_nc_wizard_webdav_list(array $state, $path = '') $hrefs = $item->xpath('d:href'); $collections = $item->xpath('d:propstat/d:prop/d:resourcetype/d:collection'); if (!$hrefs || !$collections) continue; + $href = rawurldecode((string)$hrefs[0]); $href_path = (string)parse_url($href, PHP_URL_PATH); $base_path = (string)parse_url($url, PHP_URL_PATH); if (rtrim($href_path, '/') === rtrim($base_path, '/')) continue; + $name = basename(rtrim($href_path, '/')); if ($name === '') continue; $child_path = $path === '' ? $name : $path.'/'.$name; @@ -186,14 +73,193 @@ function bratonien_tools_nc_wizard_webdav_list(array $state, $path = '') array_pop($parts); $parent = implode('/', $parts); } + return array('current'=>$path, 'parent'=>$parent, 'children'=>$children); } +function bratonien_tools_nc_wizard_refresh_directory_state(array &$state, $path = null) +{ + if ($path === null) $path = (string)($state['directory_path'] ?? ''); + $listing = bratonien_tools_nc_wizard_webdav_list($state, $path); + $state['directory_path'] = (string)$listing['current']; + $state['directory_parent'] = (string)$listing['parent']; + $state['directory_children'] = (array)$listing['children']; + if (!isset($state['directory_selected']) || !is_array($state['directory_selected'])) $state['directory_selected'] = array(); +} + +function bratonien_tools_nc_wizard_scan_user_scoped() +{ + $state = bratonien_tools_nc_wizard_state(); + $host_input = trim((string)($_POST['nc_wizard_host'] ?? $state['host_input'])); + $username = trim((string)($_POST['nc_wizard_user'] ?? $state['username'])); + $password = array_key_exists('nc_wizard_password', $_POST) ? (string)$_POST['nc_wizard_password'] : (string)$state['_password']; + + $state['step'] = 1; + $state['host_input'] = $host_input; + $state['username'] = $username; + $state['_password'] = $password; + bratonien_tools_nc_wizard_store($state); + if ($username === '' || $password === '') throw new RuntimeException('Nextcloud-Benutzer und Passwort werden für den Scan benötigt.'); + + $base_url = ''; + $status_data = null; + foreach (bratonien_tools_nc_wizard_candidate_urls($host_input) as $candidate_url) + { + try + { + $response = bratonien_tools_nc_wizard_http($candidate_url.'/status.php'); + if ($response['status'] < 200 || $response['status'] >= 300) continue; + $candidate_status = json_decode($response['body'], true); + if (!is_array($candidate_status) || empty($candidate_status['installed'])) continue; + $base_url = $candidate_url; + $status_data = $candidate_status; + break; + } + catch (Throwable $ignored) {} + } + if ($base_url === '' || !is_array($status_data)) throw new RuntimeException('Unter dieser Adresse konnte keine Nextcloud erreicht werden. HTTP und HTTPS wurden automatisch geprüft.'); + + $user_response = bratonien_tools_nc_wizard_http($base_url.'/ocs/v2.php/cloud/user?format=json', $username, $password, array('OCS-APIRequest: true')); + if ($user_response['status'] === 401 || $user_response['status'] === 403) throw new RuntimeException('Nextcloud hat Benutzername oder Passwort abgelehnt.'); + if ($user_response['status'] < 200 || $user_response['status'] >= 300) throw new RuntimeException('Nextcloud ist erreichbar, aber die Anmeldung konnte nicht geprüft werden.'); + + $user_data = bratonien_tools_nc_wizard_ocs_data($user_response['body']); + $resolved_username = trim((string)($user_data['id'] ?? $username)); + if ($resolved_username === '') $resolved_username = $username; + $url_host = (string)parse_url($base_url, PHP_URL_HOST); + + $state = array_merge($state, array( + 'step'=>2,'scan_ok'=>true,'base_url'=>$base_url,'host_input'=>$host_input,'username'=>$resolved_username, + 'display_name'=>(string)($user_data['display-name'] ?? $user_data['displayname'] ?? ''), + 'version'=>(string)($status_data['versionstring'] ?? $status_data['version'] ?? ''),'product'=>(string)($status_data['productname'] ?? 'Nextcloud'), + 'users'=>array(),'can_list_users'=>false,'showcase_user'=>$resolved_username,'connection_name'=>$url_host !== '' ? $url_host : 'Nextcloud', + 'scan_message'=>'Nextcloud wurde erkannt und der Benutzerzugriff wurde bestätigt.','_password'=>$password, + 'api_status'=>'pending','api_username'=>'','api_error'=>'','db_host'=>strtolower($url_host),'db_port'=>'5432','db_database'=>'nextcloud','db_user'=>'','db_password_set'=>false,'_db_password'=>'', + 'source_view'=>'piwigo_showcase_sources','activity_view'=>'piwigo_showcase_activity','gallery_root'=>rtrim(PHPWG_ROOT_PATH, '/').'/galleries/nextcloud', + 'storages'=>array(),'storage_candidates'=>array(),'technical_stage'=>'auto_check','technical_source'=>'Automatische Prüfung','technical_error'=>'','technical_complete'=>false, + 'directory_selection_ready'=>false,'directory_path'=>'','directory_parent'=>'','directory_children'=>array(),'directory_selected'=>array(), + )); + + if (!bratonien_tools_nc_wizard_apply_known_database_profile($state)) + { + $state['technical_stage'] = 'database_details'; + $state['technical_source'] = 'Keine bekannte Reader-Verbindung gefunden'; + $state['technical_error'] = 'Für diese Nextcloud ist noch keine bekannte Datenbank-Reader-Verbindung gespeichert.'; + bratonien_tools_nc_wizard_store($state); + return array('message'=>'Nextcloud wurde gefunden. Für den Datenzugriff wird eine separate Reader-Verbindung benötigt.'); + } + + $known_storages = isset($state['storages']) && is_array($state['storages']) ? $state['storages'] : array(); + try + { + bratonien_tools_nc_wizard_finish_data_access_for_selection($state, $known_storages); + if (!empty($state['directory_selection_ready'])) bratonien_tools_nc_wizard_refresh_directory_state($state, ''); + } + catch (Throwable $e) + { + $state['technical_complete'] = false; + $state['technical_stage'] = 'database_details'; + $state['technical_error'] = $e->getMessage(); + } + bratonien_tools_nc_wizard_store($state); + + if ($state['technical_stage'] === 'database_details') return array('message'=>'Nextcloud wurde gefunden. Die bekannte Reader-Verbindung konnte noch nicht vollständig bestätigt werden.'); + return array('message'=>'Nextcloud und Datenzugriff wurden bestätigt. Jetzt können die Verzeichnisse des angemeldeten Benutzers gewählt werden.'); +} + +function bratonien_tools_nc_wizard_directory_browse() +{ + $state = bratonien_tools_nc_wizard_state(); + if ((int)$state['step'] !== 2 || (string)$state['technical_stage'] !== 'mounts') throw new RuntimeException('Die Verzeichnisauswahl ist in diesem Schritt nicht verfügbar.'); + $path = trim((string)($_POST['nc_wizard_directory_path'] ?? ''), '/'); + bratonien_tools_nc_wizard_refresh_directory_state($state, $path); + bratonien_tools_nc_wizard_store($state); + return array('message'=>'Verzeichnis geöffnet.'); +} + +function bratonien_tools_nc_wizard_directory_add() +{ + $state = bratonien_tools_nc_wizard_state(); + if ((int)$state['step'] !== 2 || (string)$state['technical_stage'] !== 'mounts') throw new RuntimeException('Die Verzeichnisauswahl ist in diesem Schritt nicht verfügbar.'); + $path = trim((string)($state['directory_path'] ?? ''), '/'); + $selected = isset($state['directory_selected']) && is_array($state['directory_selected']) ? $state['directory_selected'] : array(); + if (!in_array($path, $selected, true)) $selected[] = $path; + $state['directory_selected'] = array_values($selected); + bratonien_tools_nc_wizard_store($state); + return array('message'=>$path === '' ? 'Stammverzeichnis ausgewählt.' : 'Verzeichnis hinzugefügt.'); +} + +function bratonien_tools_nc_wizard_directory_remove() +{ + $state = bratonien_tools_nc_wizard_state(); + $path = trim((string)($_POST['nc_wizard_directory_remove'] ?? ''), '/'); + $selected = isset($state['directory_selected']) && is_array($state['directory_selected']) ? $state['directory_selected'] : array(); + $state['directory_selected'] = array_values(array_filter($selected, function($value) use ($path) { return (string)$value !== $path; })); + bratonien_tools_nc_wizard_store($state); + return array('message'=>'Verzeichnis entfernt.'); +} + +function bratonien_tools_nc_wizard_save_mounts_server_side() +{ + $state = bratonien_tools_nc_wizard_state(); + $candidates = isset($state['storage_candidates']) && is_array($state['storage_candidates']) ? $state['storage_candidates'] : array(); + if (!$candidates) throw new RuntimeException('Es wurden noch keine Speicherorte erkannt.'); + + $mounts = isset($_POST['nc_wizard_storage_mount']) && is_array($_POST['nc_wizard_storage_mount']) ? $_POST['nc_wizard_storage_mount'] : array(); + $selected = isset($state['directory_selected']) && is_array($state['directory_selected']) ? $state['directory_selected'] : array(); + if (!$selected) $selected = array(''); + $storages = array(); + + foreach ($candidates as $index=>$candidate) + { + $mount = rtrim(trim((string)($candidate['local_mount'] ?? '')), '/'); + if ($mount === '') $mount = rtrim(trim((string)($mounts[$index] ?? '')), '/'); + if ($mount === '' || $mount[0] !== '/') throw new RuntimeException('Für einen Speicherort fehlt ein gültiger lokaler Pfad.'); + if (!is_dir($mount) || !is_readable($mount)) throw new RuntimeException('Der angegebene Speicherort ist nicht vorhanden oder nicht lesbar: '.$mount); + + foreach ($selected as $directory) + { + $directory = trim((string)$directory, '/'); + if ($directory !== '' && preg_match('#(^|/)\.\.(/|$)#', $directory)) throw new RuntimeException('Ungültige Verzeichnisauswahl.'); + $storages[] = array( + 'storage_id'=>(string)($candidate['storage_id'] ?? ''), + 'source_prefix'=>trim((string)($candidate['source_prefix'] ?? ''), '/'), + 'local_mount'=>$mount, + 'include_prefix'=>$directory, + ); + } + } + + $state['storages'] = $storages; + $state['technical_complete'] = true; + $state['technical_stage'] = 'ready'; + $state['technical_error'] = ''; + $state['directory_selection_ready'] = false; + bratonien_tools_nc_wizard_store($state); + return array('message'=>'Verzeichnisauswahl wurde übernommen.'); +} + +function bratonien_tools_nc_wizard_select_current_user() +{ + $state = bratonien_tools_nc_wizard_state(); + if (empty($state['scan_ok'])) throw new RuntimeException('Bitte zuerst Nextcloud erfolgreich scannen.'); + if (empty($state['technical_complete'])) throw new RuntimeException('Die Verbindung ist noch nicht vollständig geprüft.'); + $connection_name = trim((string)($_POST['nc_wizard_connection_name'] ?? $state['connection_name'])); + if ($connection_name === '') throw new RuntimeException('Bitte einen Namen für die Verbindung angeben.'); + $state['connection_name'] = $connection_name; + $state['showcase_user'] = (string)$state['username']; + $state['step'] = 3; + $state['api_error'] = ''; + bratonien_tools_nc_wizard_store($state); + return array('message'=>'Nextcloud-Benutzer übernommen. Jetzt folgt der Piwigo-API-Zugang.'); +} + function bratonien_tools_nc_wizard_back() { $state = bratonien_tools_nc_wizard_state(); $step = (int)($state['step'] ?? 1); if ($step <= 1) return array('message'=>'Bereits am Anfang des Assistenten.'); + if ($step === 2) { $state['step'] = 1; @@ -201,8 +267,10 @@ function bratonien_tools_nc_wizard_back() elseif ($step === 3) { $state['step'] = 2; - $state['technical_complete'] = true; - $state['technical_stage'] = 'ready'; + $state['technical_complete'] = false; + $state['technical_stage'] = 'mounts'; + $state['directory_selection_ready'] = true; + bratonien_tools_nc_wizard_refresh_directory_state($state); } else {