mirror of
https://github.com/Terranom674/Piwigo_Bratonien_Tools.git
synced 2026-09-20 02:54:34 +00:00
Compare commits
33 Commits
755e7d39fa
...
ad90cd678b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad90cd678b | ||
|
|
1065651bee | ||
|
|
4e0c9007c3 | ||
|
|
1485acbd45 | ||
|
|
81a28a9282 | ||
|
|
201a44a890 | ||
|
|
a64d5b92c5 | ||
|
|
14e4943102 | ||
|
|
b562309c6e | ||
|
|
8fc0ae96d4 | ||
|
|
cbcaf2d575 | ||
|
|
0fa5430ff6 | ||
|
|
7d0d97d844 | ||
|
|
3325efce31 | ||
|
|
8b4f3193d3 | ||
|
|
47ba20e247 | ||
|
|
e44cceaacc | ||
|
|
48822bc9e9 | ||
|
|
d638dcc590 | ||
|
|
d520209956 | ||
|
|
08b33997f5 | ||
|
|
56b18e650c | ||
|
|
c3d40faa1e | ||
|
|
867d8e9804 | ||
|
|
b891e06fe5 | ||
|
|
5694659004 | ||
|
|
eeaac9caaa | ||
|
|
0a7548414b | ||
|
|
f1a117818f | ||
|
|
c2c8652557 | ||
|
|
ea3a65664d | ||
|
|
c85aa2e833 | ||
|
|
f671e76170 |
32
.github/workflows/lint.yml
vendored
Normal file
32
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Syntax Check
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
syntax:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository auschecken
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: PHP installieren
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.2'
|
||||
coverage: none
|
||||
|
||||
- name: PHP Syntax pruefen
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
while IFS= read -r -d '' file; do
|
||||
php -l "$file"
|
||||
done < <(find . -type f -name '*.php' -print0)
|
||||
|
||||
- name: Python Syntax pruefen
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 -m compileall -q runtime
|
||||
216
include/nc_connector_connection_scope.inc.php
Normal file
216
include/nc_connector_connection_scope.inc.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
if (!defined('PHPWG_ROOT_PATH'))
|
||||
{
|
||||
die('Hacking attempt!');
|
||||
}
|
||||
|
||||
function bratonien_tools_nc_wizard_finish_connection_scoped()
|
||||
{
|
||||
$state = bratonien_tools_nc_wizard_state();
|
||||
if ((int)$state['step'] !== 4 || empty($state['technical_complete']) || trim((string)$state['showcase_user']) === '') throw new RuntimeException('Der Assistent ist noch nicht vollständig.');
|
||||
|
||||
if (array_key_exists('nc_wizard_fallback_user', $_POST)) $state['_fallback_user'] = trim((string)$_POST['nc_wizard_fallback_user']);
|
||||
if (array_key_exists('nc_wizard_fallback_password', $_POST)) $state['_fallback_password'] = (string)$_POST['nc_wizard_fallback_password'];
|
||||
bratonien_tools_nc_wizard_store($state);
|
||||
|
||||
$fallback_user = trim((string)$state['_fallback_user']);
|
||||
$fallback_password = (string)$state['_fallback_password'];
|
||||
if (($fallback_user === '') !== ($fallback_password === '')) throw new RuntimeException('Fallback-Benutzer und Fallback-Passwort müssen entweder beide angegeben oder beide leer gelassen werden.');
|
||||
if ($state['api_status'] !== 'ok' && $fallback_user === '') throw new RuntimeException('Da die Piwigo-API übersprungen wurde, ist für diese Verbindung ein Fallback-Zugang erforderlich.');
|
||||
|
||||
$mapping_lines = array();
|
||||
foreach ((array)$state['storages'] as $storage)
|
||||
{
|
||||
$key = (string)$storage['storage_id'].'|'.trim((string)$storage['source_prefix'], '/').'|'.(string)$storage['local_mount'];
|
||||
$mapping_lines[$key] = (string)$storage['storage_id'].' | '.trim((string)$storage['source_prefix'], '/').' | '.(string)$storage['local_mount'];
|
||||
}
|
||||
|
||||
$_POST['nc_name']=(string)$state['connection_name'];
|
||||
$_POST['nc_host']=(string)$state['db_host'];
|
||||
$_POST['nc_port']=(string)$state['db_port'];
|
||||
$_POST['nc_database']=(string)$state['db_database'];
|
||||
$_POST['nc_user']=(string)$state['db_user'];
|
||||
$_POST['nc_db_password']=(string)$state['_db_password'];
|
||||
$_POST['nc_source_view']=(string)$state['source_view'];
|
||||
$_POST['nc_activity_view']=(string)$state['activity_view'];
|
||||
$_POST['nc_gallery_root']=(string)$state['gallery_root'];
|
||||
$_POST['nc_storages']=implode("\n",array_values($mapping_lines));
|
||||
$_POST['nc_quiet_seconds']='120';
|
||||
$_POST['nc_max_wait_seconds']='900';
|
||||
$_POST['nc_full_sync_seconds']='86400';
|
||||
$_POST['nc_piwigo_user']=$fallback_user;
|
||||
$_POST['nc_piwigo_password']=$fallback_password;
|
||||
$_POST['nc_nextcloud_url']=(string)$state['base_url'];
|
||||
$_POST['nc_showcase_user']=(string)$state['showcase_user'];
|
||||
$_POST['nc_access_user']=(string)$state['username'];
|
||||
$_POST['nc_product']=(string)$state['product'];
|
||||
$_POST['nc_version']=(string)$state['version'];
|
||||
$_POST['nc_api_validated']=$state['api_status']==='ok'?'1':'0';
|
||||
$_POST['nc_connection_api_key_id']=$state['api_status']==='ok'?(string)$state['_api_key_id']:'';
|
||||
$_POST['nc_connection_api_key_secret']=$state['api_status']==='ok'?(string)$state['_api_key_secret']:'';
|
||||
|
||||
$result = bratonien_tools_nc_connector_create_local_api_first();
|
||||
$connection_id = (int)($result['connection_id'] ?? 0);
|
||||
if ($connection_id < 1) throw new RuntimeException('Die neue Verbindung konnte nicht gespeichert werden.');
|
||||
|
||||
$connection = bratonien_tools_nc_connector_connection($connection_id, false);
|
||||
if (!$connection) throw new RuntimeException('Die neue Verbindung konnte nach dem Anlegen nicht gelesen werden.');
|
||||
$config = $connection['config'];
|
||||
$config['storages'] = array_values($state['storages']);
|
||||
$config_json = json_encode($config, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($config_json)) throw new RuntimeException('Die Verzeichnisauswahl konnte nicht serialisiert werden.');
|
||||
$table = bratonien_tools_nc_connector_table();
|
||||
pwg_query("UPDATE `$table` SET config_json='".pwg_db_real_escape_string($config_json)."' WHERE id=".$connection_id." LIMIT 1");
|
||||
|
||||
unset($_SESSION['bratonien_nc_wizard']);
|
||||
unset($result['connection_id']);
|
||||
$result['message'] = 'Verbindung wurde vollständig mit eigener Authentifizierung angelegt. '.$result['message'];
|
||||
return $result;
|
||||
}
|
||||
|
||||
function bratonien_tools_nc_connector_delete_any()
|
||||
{
|
||||
$id = (int)($_POST['connection_id'] ?? 0);
|
||||
$connection = bratonien_tools_nc_connector_connection($id, false);
|
||||
if (!$connection) throw new RuntimeException('Connector-Verbindung wurde nicht gefunden.');
|
||||
|
||||
$status_dir = rtrim(PHPWG_ROOT_PATH, '/').'/_data/bratonien-tools/nc-connector-status';
|
||||
if (!is_dir($status_dir) && !@mkdir($status_dir, 0755, true) && !is_dir($status_dir)) throw new RuntimeException('Der Connector-Statusordner konnte nicht angelegt werden.');
|
||||
|
||||
$tombstone = $status_dir.'/deleted-'.$id;
|
||||
if (@file_put_contents($tombstone, date('c')."\n", LOCK_EX) === false) throw new RuntimeException('Die Verbindung konnte nicht sicher für die Laufzeit deaktiviert werden.');
|
||||
|
||||
$public_status = $status_dir.'/connection-'.$id.'.json';
|
||||
if (is_file($public_status)) @unlink($public_status);
|
||||
|
||||
$config = is_array($connection['config'] ?? null) ? $connection['config'] : array();
|
||||
$state_dir = rtrim((string)($config['state_dir'] ?? ''), '/');
|
||||
if ($state_dir !== '' && strpos($state_dir, '/var/lib/bratonien-tools/nc-connector/connection-'.$id) === 0 && file_exists($state_dir))
|
||||
{
|
||||
bratonien_tools_nc_connector_remove_tree($state_dir);
|
||||
}
|
||||
|
||||
$table = bratonien_tools_nc_connector_table();
|
||||
pwg_query("DELETE FROM `$table` WHERE id=".$id." LIMIT 1");
|
||||
return array('message'=>'Connector-Verbindung wurde gelöscht und für weitere Laufzeitabrufe gesperrt. Nextcloud- und Piwigo-Bilder blieben unverändert.');
|
||||
}
|
||||
|
||||
function bratonien_tools_nc_connector_verify_connection_scoped()
|
||||
{
|
||||
$result = bratonien_tools_nc_connector_verify_managed();
|
||||
$id = (int)($_POST['connection_id'] ?? 0);
|
||||
$connection = bratonien_tools_nc_connector_connection($id, true);
|
||||
if (!$connection) return $result;
|
||||
|
||||
$config = is_array($connection['config'] ?? null) ? $connection['config'] : array();
|
||||
if ((string)($config['origin'] ?? '') !== 'native' || array_key_exists('api_enabled', $config)) return $result;
|
||||
|
||||
$credentials = bratonien_tools_nc_connector_credentials_from_blob($connection['secret_blob'] ?? '');
|
||||
$db_password = (string)($credentials['db_password'] ?? '');
|
||||
$fallback_user = (string)($credentials['piwigo_user'] ?? '');
|
||||
$fallback_password = (string)($credentials['piwigo_password'] ?? '');
|
||||
if ($db_password === '') return $result;
|
||||
|
||||
$api_key_id = '';
|
||||
$api_key_secret = '';
|
||||
if ($fallback_user === '')
|
||||
{
|
||||
$legacy_api = bratonien_tools_nc_api_credentials();
|
||||
$api_key_id = trim((string)($legacy_api['key_id'] ?? ''));
|
||||
$api_key_secret = trim((string)($legacy_api['key_secret'] ?? ''));
|
||||
}
|
||||
|
||||
$payload = json_encode(array(
|
||||
'v'=>2,
|
||||
'db_password'=>$db_password,
|
||||
'piwigo_user'=>$fallback_user,
|
||||
'piwigo_password'=>$fallback_password,
|
||||
'api_key_id'=>$api_key_id,
|
||||
'api_key_secret'=>$api_key_secret,
|
||||
), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($payload)) throw new RuntimeException('Verbindungsauthentifizierung konnte nicht migriert werden.');
|
||||
|
||||
$config['piwigo_auth'] = 'connection-scoped';
|
||||
$config['api_enabled'] = $api_key_id !== '';
|
||||
$config_json = json_encode($config, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($config_json)) throw new RuntimeException('Connector-Konfiguration konnte nicht migriert werden.');
|
||||
|
||||
$blob = bratonien_tools_nc_connector_encrypt_secret($payload);
|
||||
$table = bratonien_tools_nc_connector_table();
|
||||
pwg_query("UPDATE `$table` SET config_json='".pwg_db_real_escape_string($config_json)."', secret_blob='".pwg_db_real_escape_string($blob)."' WHERE id=".$id." LIMIT 1");
|
||||
return $result;
|
||||
}
|
||||
|
||||
function bratonien_tools_nc_connector_scoped_secret(array $connection)
|
||||
{
|
||||
$plain = bratonien_tools_nc_connector_decrypt_secret($connection['secret_blob'] ?? '');
|
||||
$decoded = json_decode($plain, true);
|
||||
if (is_array($decoded) && array_key_exists('db_password', $decoded))
|
||||
{
|
||||
return array(
|
||||
'v'=>2,
|
||||
'db_password'=>(string)($decoded['db_password'] ?? ''),
|
||||
'piwigo_user'=>(string)($decoded['piwigo_user'] ?? ''),
|
||||
'piwigo_password'=>(string)($decoded['piwigo_password'] ?? ''),
|
||||
'api_key_id'=>(string)($decoded['api_key_id'] ?? ''),
|
||||
'api_key_secret'=>(string)($decoded['api_key_secret'] ?? ''),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'v'=>2,
|
||||
'db_password'=>(string)$plain,
|
||||
'piwigo_user'=>'',
|
||||
'piwigo_password'=>'',
|
||||
'api_key_id'=>'',
|
||||
'api_key_secret'=>'',
|
||||
);
|
||||
}
|
||||
|
||||
function bratonien_tools_nc_connector_store_scoped_secret($id, array $connection, array $credentials)
|
||||
{
|
||||
if (trim((string)($credentials['db_password'] ?? '')) === '') throw new RuntimeException('Das Datenbankpasswort der Verbindung fehlt.');
|
||||
$payload = json_encode($credentials, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($payload)) throw new RuntimeException('Verbindungszugangsdaten konnten nicht serialisiert werden.');
|
||||
$blob = bratonien_tools_nc_connector_encrypt_secret($payload);
|
||||
|
||||
$config = is_array($connection['config'] ?? null) ? $connection['config'] : array();
|
||||
if (array_key_exists('api_enabled', $config))
|
||||
{
|
||||
$config['api_enabled'] = trim((string)($credentials['api_key_id'] ?? '')) !== '' && trim((string)($credentials['api_key_secret'] ?? '')) !== '';
|
||||
}
|
||||
$config_json = json_encode($config, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($config_json)) throw new RuntimeException('Connector-Konfiguration konnte nicht serialisiert werden.');
|
||||
|
||||
$table = bratonien_tools_nc_connector_table();
|
||||
$now = date('Y-m-d H:i:s');
|
||||
pwg_query("UPDATE `$table` SET secret_blob='".pwg_db_real_escape_string($blob)."', config_json='".pwg_db_real_escape_string($config_json)."', updated='".pwg_db_real_escape_string($now)."' WHERE id=".(int)$id." LIMIT 1");
|
||||
}
|
||||
|
||||
function bratonien_tools_nc_connector_fallback_save_scoped()
|
||||
{
|
||||
$id = (int)($_POST['connection_id'] ?? 0);
|
||||
$username = trim((string)($_POST['nc_fallback_user'] ?? ''));
|
||||
$password = (string)($_POST['nc_fallback_password'] ?? '');
|
||||
if ($username === '' || $password === '') throw new RuntimeException('Benutzername und Passwort für den Fallback müssen angegeben werden.');
|
||||
|
||||
$connection = bratonien_tools_nc_connector_connection($id, true);
|
||||
if (!$connection) throw new RuntimeException('Connector-Verbindung wurde nicht gefunden.');
|
||||
$credentials = bratonien_tools_nc_connector_scoped_secret($connection);
|
||||
$credentials['piwigo_user'] = $username;
|
||||
$credentials['piwigo_password'] = $password;
|
||||
bratonien_tools_nc_connector_store_scoped_secret($id, $connection, $credentials);
|
||||
return array('message'=>'Piwigo-Benutzername und Passwort wurden als Fallback dieser Verbindung gespeichert.');
|
||||
}
|
||||
|
||||
function bratonien_tools_nc_connector_fallback_delete_scoped()
|
||||
{
|
||||
$id = (int)($_POST['connection_id'] ?? 0);
|
||||
$connection = bratonien_tools_nc_connector_connection($id, true);
|
||||
if (!$connection) throw new RuntimeException('Connector-Verbindung wurde nicht gefunden.');
|
||||
$credentials = bratonien_tools_nc_connector_scoped_secret($connection);
|
||||
$credentials['piwigo_user'] = '';
|
||||
$credentials['piwigo_password'] = '';
|
||||
bratonien_tools_nc_connector_store_scoped_secret($id, $connection, $credentials);
|
||||
return array('message'=>'Fallback dieser Verbindung wurde gelöscht. Ein vorhandener API-Zugang blieb unverändert.');
|
||||
}
|
||||
@@ -28,11 +28,23 @@ function bratonien_tools_nc_connector_create_local_api_first()
|
||||
throw new RuntimeException('Fallback-Benutzer und Fallback-Passwort muessen entweder beide angegeben oder beide leer gelassen werden.');
|
||||
}
|
||||
|
||||
$api = bratonien_tools_nc_api_credentials();
|
||||
$wizard_auth_present = array_key_exists('nc_api_validated', $_POST);
|
||||
$validated_pending_api = (string)($_POST['nc_api_validated'] ?? '') === '1';
|
||||
if (($api['key_id'] ?? '') === '' && $fallback_user === '' && !$validated_pending_api)
|
||||
$api_key_id = trim((string)($_POST['nc_connection_api_key_id'] ?? ''));
|
||||
$api_key_secret = trim((string)($_POST['nc_connection_api_key_secret'] ?? ''));
|
||||
if (($api_key_id === '') !== ($api_key_secret === ''))
|
||||
{
|
||||
throw new RuntimeException('Es ist weder ein geprüfter Piwigo-API-Zugang noch ein Benutzername/Passwort-Fallback vorhanden.');
|
||||
throw new RuntimeException('API-Schluessel-ID und API-Geheimnis muessen entweder beide vorhanden oder beide leer sein.');
|
||||
}
|
||||
if (($validated_pending_api || (!$wizard_auth_present && $fallback_user === '')) && $api_key_id === '')
|
||||
{
|
||||
$legacy_api = bratonien_tools_nc_api_credentials();
|
||||
$api_key_id = trim((string)($legacy_api['key_id'] ?? ''));
|
||||
$api_key_secret = trim((string)($legacy_api['key_secret'] ?? ''));
|
||||
}
|
||||
if ($api_key_id === '' && $fallback_user === '')
|
||||
{
|
||||
throw new RuntimeException('Fuer diese Verbindung ist weder ein eigener gepruefter API-Zugang noch ein Benutzername/Passwort-Fallback vorhanden.');
|
||||
}
|
||||
|
||||
$port = (int)($_POST['nc_port'] ?? 5432);
|
||||
@@ -42,7 +54,7 @@ function bratonien_tools_nc_connector_create_local_api_first()
|
||||
if (strpos($gallery_root, './') === 0)
|
||||
{
|
||||
$piwigo_root = realpath(PHPWG_ROOT_PATH);
|
||||
if ($piwigo_root === false) throw new RuntimeException('Piwigo-Stammverzeichnis konnte nicht aufgelöst werden.');
|
||||
if ($piwigo_root === false) throw new RuntimeException('Piwigo-Stammverzeichnis konnte nicht aufgeloest werden.');
|
||||
$gallery_root = rtrim($piwigo_root, '/').'/'.ltrim(substr($gallery_root, 2), '/');
|
||||
}
|
||||
if ($gallery_root === '' || $gallery_root[0] !== '/') throw new RuntimeException('Der Galerie-Pfad muss ein absoluter Pfad sein.');
|
||||
@@ -60,7 +72,9 @@ function bratonien_tools_nc_connector_create_local_api_first()
|
||||
'max_wait_seconds'=>max(60,(int)($_POST['nc_max_wait_seconds'] ?? 900)),
|
||||
'full_sync_seconds'=>max(300,(int)($_POST['nc_full_sync_seconds'] ?? 86400)),
|
||||
'storages'=>bratonien_tools_nc_connector_parse_storages($_POST['nc_storages'] ?? ''),
|
||||
'origin'=>'native','piwigo_auth'=>'api-first',
|
||||
'origin'=>'native',
|
||||
'piwigo_auth'=>'connection-scoped',
|
||||
'api_enabled'=>$api_key_id !== '',
|
||||
);
|
||||
foreach (array('nextcloud_url'=>'nc_nextcloud_url','showcase_user'=>'nc_showcase_user','nextcloud_access_user'=>'nc_access_user','nextcloud_product'=>'nc_product','nextcloud_version'=>'nc_version') as $config_key=>$post_key)
|
||||
{
|
||||
@@ -69,9 +83,19 @@ function bratonien_tools_nc_connector_create_local_api_first()
|
||||
bratonien_tools_nc_connector_view_name($config['source_view']);
|
||||
bratonien_tools_nc_connector_view_name($config['activity_view']);
|
||||
|
||||
$secret_payload = json_encode(array(
|
||||
'v'=>2,
|
||||
'db_password'=>(string)$_POST['nc_db_password'],
|
||||
'piwigo_user'=>$fallback_user,
|
||||
'piwigo_password'=>$fallback_password,
|
||||
'api_key_id'=>$api_key_id,
|
||||
'api_key_secret'=>$api_key_secret,
|
||||
), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (!is_string($secret_payload)) throw new RuntimeException('Connector-Zugangsdaten konnten nicht serialisiert werden.');
|
||||
$secret_blob = bratonien_tools_nc_connector_encrypt_secret($secret_payload);
|
||||
|
||||
$table=bratonien_tools_nc_connector_table(); bratonien_tools_nc_connector_ensure_table(); $now=date('Y-m-d H:i:s');
|
||||
$connection_key='local-'.bin2hex(random_bytes(12));
|
||||
$secret_blob=bratonien_tools_nc_connector_encrypt_credentials((string)$_POST['nc_db_password'],$fallback_user,$fallback_password);
|
||||
$config_json=json_encode($config,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
|
||||
if(!is_string($config_json)) throw new RuntimeException('Connector-Konfiguration konnte nicht serialisiert werden.');
|
||||
|
||||
@@ -90,6 +114,6 @@ function bratonien_tools_nc_connector_create_local_api_first()
|
||||
|
||||
return array(
|
||||
'connection_id'=>$id,
|
||||
'message'=>$fallback_user==='' ? 'Nextcloud-Verbindung wurde API-first ohne dauerhaft gespeicherten Benutzername/Passwort-Fallback angelegt. Bitte technisch pruefen und danach im LXC aktivieren.' : 'Nextcloud-Verbindung wurde API-first mit verschluesseltem Benutzername/Passwort-Fallback angelegt. Bitte technisch pruefen und danach im LXC aktivieren.'
|
||||
'message'=>'Nextcloud-Verbindung wurde mit verbindungseigener Piwigo-Authentifizierung angelegt.'
|
||||
);
|
||||
}
|
||||
|
||||
26
include/nc_connector_wizard_flow.inc.php
Normal file
26
include/nc_connector_wizard_flow.inc.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
if (!defined('PHPWG_ROOT_PATH'))
|
||||
{
|
||||
die('Hacking attempt!');
|
||||
}
|
||||
|
||||
function bratonien_tools_nc_wizard_save_technical_flow()
|
||||
{
|
||||
$result = bratonien_tools_nc_wizard_save_technical_with_known_database();
|
||||
$state = bratonien_tools_nc_wizard_state();
|
||||
|
||||
if ((string)($state['technical_stage'] ?? '') === 'mounts')
|
||||
{
|
||||
if (!empty($state['directory_selection_ready']))
|
||||
{
|
||||
bratonien_tools_nc_wizard_refresh_directory_state($state, '');
|
||||
}
|
||||
else
|
||||
{
|
||||
$state['mount_prompted'] = true;
|
||||
}
|
||||
bratonien_tools_nc_wizard_store($state);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
367
include/nc_connector_wizard_user_scope.inc.php
Normal file
367
include/nc_connector_wizard_user_scope.inc.php
Normal file
@@ -0,0 +1,367 @@
|
||||
<?php
|
||||
if (!defined('PHPWG_ROOT_PATH'))
|
||||
{
|
||||
die('Hacking attempt!');
|
||||
}
|
||||
|
||||
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'] === '')
|
||||
{
|
||||
throw new RuntimeException('Die Nextcloud-Sitzung des Assistenten ist nicht vollständig.');
|
||||
}
|
||||
if (!function_exists('curl_init')) throw new RuntimeException('cURL ist für die Verzeichnisauswahl nicht verfügbar.');
|
||||
|
||||
$path = trim((string)$path, '/');
|
||||
if ($path !== '' && preg_match('#(^|/)\.\.(/|$)#', $path)) throw new RuntimeException('Ungültiger Verzeichnispfad.');
|
||||
|
||||
$segments = $path === '' ? array() : array_map('rawurlencode', explode('/', $path));
|
||||
$user = rawurlencode((string)$state['username']);
|
||||
$url = rtrim((string)$state['base_url'], '/').'/remote.php/dav/files/'.$user.'/'.implode('/', $segments);
|
||||
if (substr($url, -1) !== '/') $url .= '/';
|
||||
|
||||
$body = '<?xml version="1.0"?><d:propfind xmlns:d="DAV:"><d:prop><d:resourcetype/><d:displayname/></d:prop></d:propfind>';
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, array(
|
||||
CURLOPT_RETURNTRANSFER=>true,
|
||||
CURLOPT_CUSTOMREQUEST=>'PROPFIND',
|
||||
CURLOPT_POSTFIELDS=>$body,
|
||||
CURLOPT_HTTPHEADER=>array('Depth: 1','Content-Type: application/xml; charset=utf-8'),
|
||||
CURLOPT_HTTPAUTH=>CURLAUTH_BASIC,
|
||||
CURLOPT_USERPWD=>(string)$state['username'].':'.(string)$state['_password'],
|
||||
CURLOPT_CONNECTTIMEOUT=>8,
|
||||
CURLOPT_TIMEOUT=>20,
|
||||
));
|
||||
$response = curl_exec($ch);
|
||||
$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.'.');
|
||||
|
||||
libxml_use_internal_errors(true);
|
||||
$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)
|
||||
{
|
||||
$item->registerXPathNamespace('d', 'DAV:');
|
||||
$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;
|
||||
$children[$child_path] = $name;
|
||||
}
|
||||
natcasesort($children);
|
||||
|
||||
$parent = '';
|
||||
if ($path !== '')
|
||||
{
|
||||
$parts = explode('/', $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(),
|
||||
'database_prompted'=>false,'mount_prompted'=>false,
|
||||
));
|
||||
|
||||
if (!bratonien_tools_nc_wizard_apply_known_database_profile($state))
|
||||
{
|
||||
$state['technical_stage'] = 'database_details';
|
||||
$state['database_prompted'] = true;
|
||||
$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, '');
|
||||
}
|
||||
else
|
||||
{
|
||||
$state['mount_prompted'] = true;
|
||||
}
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
$state['technical_complete'] = false;
|
||||
$state['technical_stage'] = 'database_details';
|
||||
$state['database_prompted'] = true;
|
||||
$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.');
|
||||
if (empty($state['directory_selection_ready'])) return array('message'=>'Nextcloud und Datenzugriff wurden bestätigt. Der technische Speicherort muss einmal 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' || empty($state['directory_selection_ready'])) throw new RuntimeException('Die Verzeichnisauswahl ist in diesem Fenster 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' || empty($state['directory_selection_ready'])) throw new RuntimeException('Die Verzeichnisauswahl ist in diesem Fenster 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();
|
||||
if ((int)$state['step'] !== 2 || empty($state['directory_selection_ready'])) throw new RuntimeException('Die Verzeichnisauswahl ist in diesem Fenster nicht verfügbar.');
|
||||
$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();
|
||||
if ((int)$state['step'] !== 2 || (string)$state['technical_stage'] !== 'mounts') throw new RuntimeException('Die Speicher-/Verzeichnisauswahl ist in diesem Fenster nicht verfügbar.');
|
||||
|
||||
$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();
|
||||
|
||||
// Erstes sichtbares Fenster: technische Mount-Zuordnung bestätigen.
|
||||
if (empty($state['directory_selection_ready']))
|
||||
{
|
||||
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);
|
||||
$candidate['local_mount'] = $mount;
|
||||
}
|
||||
unset($candidate);
|
||||
|
||||
$state['storage_candidates'] = array_values($candidates);
|
||||
$state['mount_prompted'] = true;
|
||||
$state['directory_selection_ready'] = true;
|
||||
$state['technical_complete'] = false;
|
||||
$state['technical_stage'] = 'mounts';
|
||||
$state['directory_path'] = '';
|
||||
$state['directory_parent'] = '';
|
||||
$state['directory_children'] = array();
|
||||
$state['directory_selected'] = array();
|
||||
bratonien_tools_nc_wizard_refresh_directory_state($state, '');
|
||||
bratonien_tools_nc_wizard_store($state);
|
||||
return array('message'=>'Speicherzuordnung wurde bestätigt. Jetzt können die Verzeichnisse ausgewählt werden.');
|
||||
}
|
||||
|
||||
// Zweites sichtbares Fenster: Verzeichnisauswahl übernehmen.
|
||||
$selected = isset($state['directory_selected']) && is_array($state['directory_selected']) ? $state['directory_selected'] : array();
|
||||
if (!$selected) $selected = array('');
|
||||
$storages = array();
|
||||
|
||||
foreach ($candidates as $candidate)
|
||||
{
|
||||
$mount = rtrim(trim((string)($candidate['local_mount'] ?? '')), '/');
|
||||
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 === 4)
|
||||
{
|
||||
// Abschluss -> API
|
||||
$state['step'] = 3;
|
||||
}
|
||||
elseif ($step === 3)
|
||||
{
|
||||
// API -> Verbindungsname
|
||||
$state['step'] = 2;
|
||||
$state['technical_complete'] = true;
|
||||
$state['technical_stage'] = 'ready';
|
||||
$state['directory_selection_ready'] = false;
|
||||
}
|
||||
elseif (!empty($state['technical_complete']))
|
||||
{
|
||||
// Verbindungsname -> Verzeichnisauswahl
|
||||
$state['technical_complete'] = false;
|
||||
$state['technical_stage'] = 'mounts';
|
||||
$state['directory_selection_ready'] = true;
|
||||
bratonien_tools_nc_wizard_refresh_directory_state($state);
|
||||
}
|
||||
elseif ((string)($state['technical_stage'] ?? '') === 'mounts' && !empty($state['directory_selection_ready']))
|
||||
{
|
||||
// Verzeichnisauswahl -> vorher tatsächlich sichtbares Fenster.
|
||||
if (!empty($state['mount_prompted']))
|
||||
{
|
||||
$state['directory_selection_ready'] = false;
|
||||
}
|
||||
elseif (!empty($state['database_prompted']))
|
||||
{
|
||||
$state['technical_stage'] = 'database_details';
|
||||
$state['directory_selection_ready'] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$state['step'] = 1;
|
||||
}
|
||||
}
|
||||
elseif ((string)($state['technical_stage'] ?? '') === 'mounts')
|
||||
{
|
||||
// Mount-Zuordnung -> Datenbankfenster, falls es sichtbar war, sonst Anmeldung.
|
||||
if (!empty($state['database_prompted']))
|
||||
{
|
||||
$state['technical_stage'] = 'database_details';
|
||||
}
|
||||
else
|
||||
{
|
||||
$state['step'] = 1;
|
||||
}
|
||||
}
|
||||
elseif ((string)($state['technical_stage'] ?? '') === 'database_details')
|
||||
{
|
||||
// Datenbankfenster -> Anmeldung.
|
||||
$state['step'] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$state['step'] = 1;
|
||||
}
|
||||
|
||||
bratonien_tools_nc_wizard_store($state);
|
||||
return array('message'=>'Ein Fenster zurück.');
|
||||
}
|
||||
@@ -23,6 +23,9 @@ require_once(BRATONIEN_TOOLS_PATH . 'include/nc_connector_create_api.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH . 'include/nc_connector_piwigo_api.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH . 'include/nc_connector_wizard.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH . 'include/nc_connector_wizard_db_bridge.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH . 'include/nc_connector_wizard_user_scope.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH . 'include/nc_connector_wizard_flow.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH . 'include/nc_connector_connection_scope.inc.php');
|
||||
|
||||
function bratonien_tools_get_tools()
|
||||
{
|
||||
@@ -48,25 +51,29 @@ function bratonien_tools_get_tools()
|
||||
'album_share_regenerate_link' => array('handler' => 'bratonien_tools_regenerate_album_share_link'),
|
||||
'album_share_revoke' => array('handler' => 'bratonien_tools_revoke_album_share'),
|
||||
'nc_connector_create_local' => array('handler' => 'bratonien_tools_nc_connector_create_local_api_first'),
|
||||
'nc_connector_delete' => array('handler' => 'bratonien_tools_nc_connector_delete'),
|
||||
'nc_connector_delete' => array('handler' => 'bratonien_tools_nc_connector_delete_any'),
|
||||
'nc_connector_update_name' => array('handler' => 'bratonien_tools_nc_connector_update_name'),
|
||||
'nc_connector_update_technical' => array('handler' => 'bratonien_tools_nc_connector_update_technical'),
|
||||
'nc_connector_wizard_scan' => array('handler' => 'bratonien_tools_nc_wizard_scan_with_known_database'),
|
||||
'nc_connector_wizard_save_technical' => array('handler' => 'bratonien_tools_nc_wizard_save_technical_with_known_database'),
|
||||
'nc_connector_wizard_save_mounts' => array('handler' => 'bratonien_tools_nc_wizard_save_mounts_with_directories'),
|
||||
'nc_connector_wizard_select_user' => array('handler' => 'bratonien_tools_nc_wizard_select_user'),
|
||||
'nc_connector_wizard_scan' => array('handler' => 'bratonien_tools_nc_wizard_scan_user_scoped'),
|
||||
'nc_connector_wizard_save_technical' => array('handler' => 'bratonien_tools_nc_wizard_save_technical_flow'),
|
||||
'nc_connector_wizard_directory_browse' => array('handler' => 'bratonien_tools_nc_wizard_directory_browse'),
|
||||
'nc_connector_wizard_directory_add' => array('handler' => 'bratonien_tools_nc_wizard_directory_add'),
|
||||
'nc_connector_wizard_directory_remove' => array('handler' => 'bratonien_tools_nc_wizard_directory_remove'),
|
||||
'nc_connector_wizard_save_mounts' => array('handler' => 'bratonien_tools_nc_wizard_save_mounts_server_side'),
|
||||
'nc_connector_wizard_select_user' => array('handler' => 'bratonien_tools_nc_wizard_select_current_user'),
|
||||
'nc_connector_wizard_api_test' => array('handler' => 'bratonien_tools_nc_wizard_api_test'),
|
||||
'nc_connector_wizard_api_skip' => array('handler' => 'bratonien_tools_nc_wizard_api_skip'),
|
||||
'nc_connector_wizard_finish' => array('handler' => 'bratonien_tools_nc_wizard_finish_with_directories'),
|
||||
'nc_connector_wizard_finish' => array('handler' => 'bratonien_tools_nc_wizard_finish_connection_scoped'),
|
||||
'nc_connector_wizard_back' => array('handler' => 'bratonien_tools_nc_wizard_back'),
|
||||
'nc_connector_wizard_reset' => array('handler' => 'bratonien_tools_nc_wizard_reset'),
|
||||
'nc_connector_import_legacy' => array('handler' => 'bratonien_tools_nc_connector_import_legacy'),
|
||||
'nc_connector_verify' => array('handler' => 'bratonien_tools_nc_connector_verify_managed'),
|
||||
'nc_connector_verify' => array('handler' => 'bratonien_tools_nc_connector_verify_connection_scoped'),
|
||||
'nc_connector_prepare_takeover' => array('handler' => 'bratonien_tools_nc_connector_prepare_takeover'),
|
||||
'nc_connector_cancel_takeover' => array('handler' => 'bratonien_tools_nc_connector_cancel_takeover'),
|
||||
'nc_connector_piwigo_api_test' => array('handler' => 'bratonien_tools_nc_connector_piwigo_api_test'),
|
||||
'nc_connector_piwigo_api_delete' => array('handler' => 'bratonien_tools_nc_connector_api_delete'),
|
||||
'nc_connector_fallback_save' => array('handler' => 'bratonien_tools_nc_connector_fallback_save'),
|
||||
'nc_connector_fallback_delete' => array('handler' => 'bratonien_tools_nc_connector_fallback_delete'),
|
||||
'nc_connector_fallback_save' => array('handler' => 'bratonien_tools_nc_connector_fallback_save_scoped'),
|
||||
'nc_connector_fallback_delete' => array('handler' => 'bratonien_tools_nc_connector_fallback_delete_scoped'),
|
||||
'nc_connector_fallback_once' => array('handler' => 'bratonien_tools_nc_connector_fallback_once'),
|
||||
'self_update_check' => array('handler' => 'bratonien_tools_self_update_check'),
|
||||
'self_update_run' => array('handler' => 'bratonien_tools_self_update_run'),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/*
|
||||
Plugin Name: Bratonien Tools
|
||||
Version: 0.9.4.5
|
||||
Version: 0.9.4.9
|
||||
Description: Erweiterbare Administrationswerkzeuge fuer die Bratonien-Piwigo-Installation.
|
||||
Plugin URI: https://github.com/Terranom674/Piwigo_Bratonien_Tools
|
||||
Author: Bratonien
|
||||
|
||||
@@ -58,7 +58,6 @@ function decrypt_install_credentials($blob, $hexKey)
|
||||
$decoded = json_decode($plain, true);
|
||||
if (!is_array($decoded))
|
||||
{
|
||||
// Backward compatibility: old connections stored only the DB password.
|
||||
return array('db_password'=>$plain,'piwigo_user'=>'','piwigo_password'=>'');
|
||||
}
|
||||
if (empty($decoded['db_password'])) fail_install('Datenbankpasswort fehlt in den Connector-Zugangsdaten.');
|
||||
@@ -124,10 +123,13 @@ try
|
||||
@unlink($piwigoPasswordPath);
|
||||
}
|
||||
|
||||
$storageLines = array('# storage_id<TAB>source_prefix<TAB>local_mount');
|
||||
$storageLines = array('# storage_id<TAB>source_prefix<TAB>local_mount<TAB>include_prefix');
|
||||
foreach ((array)($config['storages'] ?? array()) as $storage)
|
||||
{
|
||||
$storageLines[] = (string)($storage['storage_id'] ?? '')."\t".trim((string)($storage['source_prefix'] ?? ''), '/')."\t".(string)($storage['local_mount'] ?? '');
|
||||
$storageLines[] = (string)($storage['storage_id'] ?? '')."\t"
|
||||
.trim((string)($storage['source_prefix'] ?? ''), '/')."\t"
|
||||
.(string)($storage['local_mount'] ?? '')."\t"
|
||||
.trim((string)($storage['include_prefix'] ?? ''), '/');
|
||||
}
|
||||
if (count($storageLines) === 1) fail_install('Keine Storage-Zuordnungen gespeichert.');
|
||||
file_put_contents($storagePath, implode("\n", $storageLines)."\n", LOCK_EX); chmod($storagePath, 0600);
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
$piwigo_root = realpath(dirname(__DIR__, 2));
|
||||
if ($piwigo_root === false)
|
||||
{
|
||||
http_response_code(500);
|
||||
exit;
|
||||
}
|
||||
define('PHPWG_ROOT_PATH', rtrim($piwigo_root, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR);
|
||||
include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-store, max-age=0');
|
||||
|
||||
if (!defined('BRATONIEN_TOOLS_PATH'))
|
||||
{
|
||||
http_response_code(404);
|
||||
echo json_encode(array('state'=>'unavailable','message'=>'Bratonien Tools ist nicht aktiv.'));
|
||||
exit;
|
||||
}
|
||||
if (!function_exists('is_admin') || !is_admin())
|
||||
{
|
||||
http_response_code(403);
|
||||
echo json_encode(array('state'=>'forbidden','message'=>'Administratorrechte erforderlich.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once(BRATONIEN_TOOLS_PATH.'include/nc_connector.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH.'include/nc_connector_wizard.inc.php');
|
||||
require_once(BRATONIEN_TOOLS_PATH.'include/nc_connector_wizard_db_bridge.inc.php');
|
||||
|
||||
try
|
||||
{
|
||||
$state = bratonien_tools_nc_wizard_state();
|
||||
echo json_encode(array(
|
||||
'state'=>'ok',
|
||||
'ready'=>!empty($state['directory_selection_ready']),
|
||||
'storages'=>bratonien_tools_nc_wizard_directory_options($state),
|
||||
), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
http_response_code(500);
|
||||
echo json_encode(array('state'=>'error','message'=>$e->getMessage()), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
@@ -14,19 +14,13 @@ function fail_sync($message)
|
||||
function http_error_detail($body)
|
||||
{
|
||||
$body = trim((string)$body);
|
||||
if ($body === '')
|
||||
{
|
||||
return '';
|
||||
}
|
||||
if ($body === '') return '';
|
||||
|
||||
$decoded = json_decode($body, true);
|
||||
if (is_array($decoded))
|
||||
{
|
||||
$detail = (string)($decoded['message'] ?? $decoded['err'] ?? '');
|
||||
if ($detail !== '')
|
||||
{
|
||||
return $detail;
|
||||
}
|
||||
if ($detail !== '') return $detail;
|
||||
}
|
||||
|
||||
if (function_exists('simplexml_load_string'))
|
||||
@@ -38,19 +32,12 @@ function http_error_detail($body)
|
||||
if ($xml !== false)
|
||||
{
|
||||
$detail = trim((string)($xml->message ?? $xml->err ?? ''));
|
||||
if ($detail !== '')
|
||||
{
|
||||
return $detail;
|
||||
}
|
||||
if ($detail !== '') return $detail;
|
||||
}
|
||||
}
|
||||
|
||||
$plain = trim(preg_replace('/\s+/', ' ', strip_tags($body)));
|
||||
if ($plain === '')
|
||||
{
|
||||
return '';
|
||||
}
|
||||
return mb_substr($plain, 0, 500);
|
||||
return $plain === '' ? '' : mb_substr($plain, 0, 500);
|
||||
}
|
||||
|
||||
function http_request($url, array $fields, array $headers = array(), $cookie_file = null)
|
||||
@@ -65,10 +52,7 @@ function http_request($url, array $fields, array $headers = array(), $cookie_fil
|
||||
CURLOPT_FOLLOWLOCATION => false,
|
||||
CURLOPT_USERAGENT => 'Bratonien-NC-Connector',
|
||||
);
|
||||
if ($headers)
|
||||
{
|
||||
$options[CURLOPT_HTTPHEADER] = $headers;
|
||||
}
|
||||
if ($headers) $options[CURLOPT_HTTPHEADER] = $headers;
|
||||
if ($cookie_file !== null)
|
||||
{
|
||||
$options[CURLOPT_COOKIEJAR] = $cookie_file;
|
||||
@@ -81,42 +65,29 @@ function http_request($url, array $fields, array $headers = array(), $cookie_fil
|
||||
$http = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($body === false || $errno !== 0)
|
||||
{
|
||||
fail_sync('HTTP-Aufruf fehlgeschlagen: '.$error);
|
||||
}
|
||||
if ($body === false || $errno !== 0) fail_sync('HTTP-Aufruf fehlgeschlagen: '.$error);
|
||||
if ($http < 200 || $http >= 300)
|
||||
{
|
||||
$detail = http_error_detail((string)$body);
|
||||
fail_sync('HTTP-Aufruf antwortete mit Status '.$http.($detail !== '' ? ': '.$detail : '.'));
|
||||
}
|
||||
|
||||
return (string)$body;
|
||||
}
|
||||
|
||||
function xml_value_sync(SimpleXMLElement $node)
|
||||
{
|
||||
$children = $node->children();
|
||||
if (count($children) === 0)
|
||||
{
|
||||
return (string)$node;
|
||||
}
|
||||
if (count($children) === 0) return (string)$node;
|
||||
$result = array();
|
||||
foreach ($children as $name => $child)
|
||||
{
|
||||
$value = xml_value_sync($child);
|
||||
if (array_key_exists($name, $result))
|
||||
{
|
||||
if (!is_array($result[$name]) || !array_is_list($result[$name]))
|
||||
{
|
||||
$result[$name] = array($result[$name]);
|
||||
}
|
||||
if (!is_array($result[$name]) || !array_is_list($result[$name])) $result[$name] = array($result[$name]);
|
||||
$result[$name][] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[$name] = $value;
|
||||
}
|
||||
else $result[$name] = $value;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@@ -126,34 +97,22 @@ function decode_ws($body)
|
||||
$decoded = json_decode((string)$body, true);
|
||||
if (!is_array($decoded))
|
||||
{
|
||||
if (!function_exists('simplexml_load_string'))
|
||||
{
|
||||
fail_sync('Piwigo lieferte XML, aber SimpleXML ist nicht verfuegbar.');
|
||||
}
|
||||
if (!function_exists('simplexml_load_string')) fail_sync('Piwigo lieferte XML, aber SimpleXML ist nicht verfuegbar.');
|
||||
$previous = libxml_use_internal_errors(true);
|
||||
$xml = simplexml_load_string((string)$body);
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($previous);
|
||||
if ($xml === false || $xml->getName() !== 'rsp')
|
||||
{
|
||||
fail_sync('Piwigo lieferte weder gueltiges JSON noch eine gueltige XML-Webservice-Antwort.');
|
||||
}
|
||||
if ($xml === false || $xml->getName() !== 'rsp') fail_sync('Piwigo lieferte weder gueltiges JSON noch eine gueltige XML-Webservice-Antwort.');
|
||||
$decoded = array('stat'=>(string)$xml['stat']);
|
||||
foreach ($xml->children() as $name => $child)
|
||||
{
|
||||
$value = xml_value_sync($child);
|
||||
if (array_key_exists($name, $decoded))
|
||||
{
|
||||
if (!is_array($decoded[$name]) || !array_is_list($decoded[$name]))
|
||||
{
|
||||
$decoded[$name] = array($decoded[$name]);
|
||||
}
|
||||
if (!is_array($decoded[$name]) || !array_is_list($decoded[$name])) $decoded[$name] = array($decoded[$name]);
|
||||
$decoded[$name][] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$decoded[$name] = $value;
|
||||
}
|
||||
else $decoded[$name] = $value;
|
||||
}
|
||||
}
|
||||
if (($decoded['stat'] ?? '') !== 'ok')
|
||||
@@ -161,36 +120,22 @@ function decode_ws($body)
|
||||
$message = (string)($decoded['message'] ?? $decoded['err'] ?? 'Piwigo-Aufruf wurde abgelehnt.');
|
||||
fail_sync($message);
|
||||
}
|
||||
|
||||
if (array_key_exists('result', $decoded))
|
||||
{
|
||||
return $decoded['result'];
|
||||
}
|
||||
|
||||
if (array_key_exists('result', $decoded)) return $decoded['result'];
|
||||
unset($decoded['stat']);
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
function decrypt_blob($blob, $hex_key)
|
||||
{
|
||||
if (!preg_match('/^[a-f0-9]{64}$/', (string)$hex_key))
|
||||
{
|
||||
fail_sync('Connector-Schluessel ist ungueltig.');
|
||||
}
|
||||
if (!preg_match('/^[a-f0-9]{64}$/', (string)$hex_key)) fail_sync('Connector-Schluessel ist ungueltig.');
|
||||
$outer = base64_decode(trim((string)$blob), true);
|
||||
$payload = is_string($outer) ? json_decode($outer, true) : null;
|
||||
if (!is_array($payload) || (int)($payload['v'] ?? 0) !== 1)
|
||||
{
|
||||
fail_sync('Gespeicherte Zugangsdaten haben ein unbekanntes Format.');
|
||||
}
|
||||
if (!is_array($payload) || (int)($payload['v'] ?? 0) !== 1) fail_sync('Gespeicherte Zugangsdaten haben ein unbekanntes Format.');
|
||||
$iv = base64_decode((string)($payload['iv'] ?? ''), true);
|
||||
$tag = base64_decode((string)($payload['tag'] ?? ''), true);
|
||||
$cipher = base64_decode((string)($payload['data'] ?? ''), true);
|
||||
$plain = openssl_decrypt($cipher, 'aes-256-gcm', hex2bin($hex_key), OPENSSL_RAW_DATA, $iv, $tag);
|
||||
if ($plain === false)
|
||||
{
|
||||
fail_sync('Gespeicherte Zugangsdaten konnten nicht entschluesselt werden.');
|
||||
}
|
||||
if ($plain === false) fail_sync('Gespeicherte Zugangsdaten konnten nicht entschluesselt werden.');
|
||||
return (string)$plain;
|
||||
}
|
||||
|
||||
@@ -200,77 +145,64 @@ try
|
||||
$piwigo_root = rtrim((string)($options['piwigo-root'] ?? ''), '/');
|
||||
$connection_id = (int)($options['connection-id'] ?? 0);
|
||||
$base_url = rtrim((string)($options['base-url'] ?? 'http://127.0.0.1'), '/');
|
||||
|
||||
if ($piwigo_root === '' || $connection_id < 1)
|
||||
{
|
||||
fail_sync('Parameter --piwigo-root und --connection-id werden benoetigt.');
|
||||
}
|
||||
if (!function_exists('curl_init'))
|
||||
{
|
||||
fail_sync('PHP-cURL ist nicht verfuegbar.');
|
||||
}
|
||||
if ($piwigo_root === '' || $connection_id < 1) fail_sync('Parameter --piwigo-root und --connection-id werden benoetigt.');
|
||||
if (!function_exists('curl_init')) fail_sync('PHP-cURL ist nicht verfuegbar.');
|
||||
|
||||
$db_config = $piwigo_root.'/local/config/database.inc.php';
|
||||
if (!is_readable($db_config))
|
||||
{
|
||||
fail_sync('Piwigo-Datenbankkonfiguration ist nicht lesbar.');
|
||||
}
|
||||
|
||||
if (!is_readable($db_config)) fail_sync('Piwigo-Datenbankkonfiguration ist nicht lesbar.');
|
||||
$conf = array();
|
||||
$prefixeTable = 'piwigo_';
|
||||
require $db_config;
|
||||
foreach (array('db_host','db_user','db_password','db_base') as $key)
|
||||
{
|
||||
if (!isset($conf[$key]))
|
||||
{
|
||||
fail_sync('Piwigo-Datenbankkonfiguration ist unvollstaendig: '.$key);
|
||||
}
|
||||
}
|
||||
foreach (array('db_host','db_user','db_password','db_base') as $key) if (!isset($conf[$key])) fail_sync('Piwigo-Datenbankkonfiguration ist unvollstaendig: '.$key);
|
||||
|
||||
$db = new mysqli($conf['db_host'], $conf['db_user'], $conf['db_password'], $conf['db_base']);
|
||||
if ($db->connect_errno)
|
||||
{
|
||||
fail_sync('Piwigo-Datenbank ist nicht erreichbar: '.$db->connect_error);
|
||||
}
|
||||
if ($db->connect_errno) fail_sync('Piwigo-Datenbank ist nicht erreichbar: '.$db->connect_error);
|
||||
$db->set_charset('utf8mb4');
|
||||
|
||||
$key_result = $db->query("SELECT value FROM `{$prefixeTable}config` WHERE param='bratonien_nc_connector_secret' LIMIT 1");
|
||||
if (!$key_result || !$key_result->num_rows)
|
||||
{
|
||||
fail_sync('Connector-Schluessel wurde nicht gefunden.');
|
||||
}
|
||||
if (!$key_result || !$key_result->num_rows) fail_sync('Connector-Schluessel wurde nicht gefunden.');
|
||||
$hex_key = (string)$key_result->fetch_assoc()['value'];
|
||||
|
||||
$connection_table = $prefixeTable.'bratonien_tools_nc_connections';
|
||||
$connection_result = $db->query('SELECT config_json, secret_blob FROM `'.$connection_table.'` WHERE id='.$connection_id.' LIMIT 1');
|
||||
if (!$connection_result || !$connection_result->num_rows) fail_sync('Connector-Verbindung #'.$connection_id.' wurde nicht gefunden.');
|
||||
$connection_row = $connection_result->fetch_assoc();
|
||||
$connection_config = json_decode((string)$connection_row['config_json'], true);
|
||||
if (!is_array($connection_config)) $connection_config = array();
|
||||
$connection_plain = decrypt_blob((string)$connection_row['secret_blob'], $hex_key);
|
||||
$connection_credentials = json_decode($connection_plain, true);
|
||||
if (!is_array($connection_credentials)) $connection_credentials = array();
|
||||
|
||||
$api = array('key_id'=>'', 'key_secret'=>'');
|
||||
$api_result = $db->query("SELECT value FROM `{$prefixeTable}config` WHERE param='bratonien_nc_piwigo_api' LIMIT 1");
|
||||
if ($api_result && $api_result->num_rows)
|
||||
$connection_scoped = (string)($connection_config['piwigo_auth'] ?? '') === 'connection-scoped' || array_key_exists('api_enabled', $connection_config);
|
||||
if ($connection_scoped)
|
||||
{
|
||||
$api_blob = (string)$api_result->fetch_assoc()['value'];
|
||||
if ($api_blob !== '')
|
||||
if (!empty($connection_config['api_enabled']))
|
||||
{
|
||||
$api_plain = decrypt_blob($api_blob, $hex_key);
|
||||
$api_decoded = json_decode($api_plain, true);
|
||||
if (is_array($api_decoded))
|
||||
$api['key_id'] = trim((string)($connection_credentials['api_key_id'] ?? ''));
|
||||
$api['key_secret'] = trim((string)($connection_credentials['api_key_secret'] ?? ''));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nur fuer bereits aktive Altverbindungen: bisheriger globaler API-Zugang.
|
||||
$api_result = $db->query("SELECT value FROM `{$prefixeTable}config` WHERE param='bratonien_nc_piwigo_api' LIMIT 1");
|
||||
if ($api_result && $api_result->num_rows)
|
||||
{
|
||||
$api_blob = (string)$api_result->fetch_assoc()['value'];
|
||||
if ($api_blob !== '')
|
||||
{
|
||||
$api['key_id'] = (string)($api_decoded['key_id'] ?? '');
|
||||
$api['key_secret'] = (string)($api_decoded['key_secret'] ?? '');
|
||||
$api_plain = decrypt_blob($api_blob, $hex_key);
|
||||
$api_decoded = json_decode($api_plain, true);
|
||||
if (is_array($api_decoded))
|
||||
{
|
||||
$api['key_id'] = (string)($api_decoded['key_id'] ?? '');
|
||||
$api['key_secret'] = (string)($api_decoded['key_secret'] ?? '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$connection_table = $prefixeTable.'bratonien_tools_nc_connections';
|
||||
$connection_result = $db->query('SELECT secret_blob FROM `'.$connection_table.'` WHERE id='.$connection_id.' LIMIT 1');
|
||||
if (!$connection_result || !$connection_result->num_rows)
|
||||
{
|
||||
fail_sync('Connector-Verbindung #'.$connection_id.' wurde nicht gefunden.');
|
||||
}
|
||||
$connection_blob = (string)$connection_result->fetch_assoc()['secret_blob'];
|
||||
$connection_plain = decrypt_blob($connection_blob, $hex_key);
|
||||
$connection_credentials = json_decode($connection_plain, true);
|
||||
if (!is_array($connection_credentials))
|
||||
{
|
||||
$connection_credentials = array();
|
||||
}
|
||||
$fallback_user = (string)($connection_credentials['piwigo_user'] ?? '');
|
||||
$fallback_password = (string)($connection_credentials['piwigo_password'] ?? '');
|
||||
|
||||
@@ -284,16 +216,8 @@ try
|
||||
'Accept: application/json, text/xml;q=0.9',
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
);
|
||||
decode_ws(http_request(
|
||||
$base_url.'/ws.php?format=json',
|
||||
array('method'=>'bratonien.nc.syncProductive', 'site_id'=>1),
|
||||
$headers
|
||||
));
|
||||
$orphan = decode_ws(http_request(
|
||||
$base_url.'/ws.php?format=json',
|
||||
array('method'=>'bratonien.nc.syncOrphans', 'site_id'=>1, 'simulate'=>0),
|
||||
$headers
|
||||
));
|
||||
decode_ws(http_request($base_url.'/ws.php?format=json', array('method'=>'bratonien.nc.syncProductive', 'site_id'=>1), $headers));
|
||||
$orphan = decode_ws(http_request($base_url.'/ws.php?format=json', array('method'=>'bratonien.nc.syncOrphans', 'site_id'=>1, 'simulate'=>0), $headers));
|
||||
$added = (int)($orphan['added_orphans'] ?? 0);
|
||||
$deleted = (int)($orphan['deleted_orphans'] ?? 0);
|
||||
echo "Piwigo-Synchronisierung per API erfolgreich\n";
|
||||
@@ -308,55 +232,27 @@ try
|
||||
}
|
||||
else
|
||||
{
|
||||
$api_error = 'Keine gespeicherten API-Zugangsdaten.';
|
||||
$api_error = $connection_scoped ? 'Fuer diese Verbindung ist keine API konfiguriert.' : 'Keine gespeicherten API-Zugangsdaten.';
|
||||
fwrite(STDERR, "Piwigo-API nicht nutzbar: ".$api_error."\n");
|
||||
}
|
||||
|
||||
if ($fallback_user === '' || $fallback_password === '')
|
||||
{
|
||||
fail_sync('Kein gespeicherter Benutzername/Passwort-Fallback vorhanden.');
|
||||
}
|
||||
if ($fallback_user === '' || $fallback_password === '') fail_sync('Kein gespeicherter Benutzername/Passwort-Fallback fuer diese Verbindung vorhanden.');
|
||||
|
||||
$cookie_file = tempnam(sys_get_temp_dir(), 'br-nc-sync-');
|
||||
if ($cookie_file === false)
|
||||
{
|
||||
fail_sync('Temporare Piwigo-Sitzung konnte nicht angelegt werden.');
|
||||
}
|
||||
if ($cookie_file === false) fail_sync('Temporare Piwigo-Sitzung konnte nicht angelegt werden.');
|
||||
|
||||
try
|
||||
{
|
||||
decode_ws(http_request(
|
||||
$base_url.'/ws.php?format=json',
|
||||
array('method'=>'pwg.session.login', 'username'=>$fallback_user, 'password'=>$fallback_password),
|
||||
array(),
|
||||
$cookie_file
|
||||
));
|
||||
|
||||
decode_ws(http_request($base_url.'/ws.php?format=json', array('method'=>'pwg.session.login', 'username'=>$fallback_user, 'password'=>$fallback_password), array(), $cookie_file));
|
||||
http_request(
|
||||
$base_url.'/admin.php?page=site_update&site=1',
|
||||
array(
|
||||
'sync'=>'files',
|
||||
'display_info'=>1,
|
||||
'privacy_level'=>0,
|
||||
'sync_meta'=>1,
|
||||
'simulate'=>0,
|
||||
'subcats-included'=>1,
|
||||
'bratonien_connector'=>1,
|
||||
'submit'=>1,
|
||||
),
|
||||
array('sync'=>'files','display_info'=>1,'privacy_level'=>0,'sync_meta'=>1,'simulate'=>0,'subcats-included'=>1,'bratonien_connector'=>1,'submit'=>1),
|
||||
array(),
|
||||
$cookie_file
|
||||
);
|
||||
|
||||
$orphan = decode_ws(http_request(
|
||||
$base_url.'/ws.php?format=json',
|
||||
array('method'=>'bratonien.nc.syncOrphans', 'site_id'=>1, 'simulate'=>0),
|
||||
array(),
|
||||
$cookie_file
|
||||
));
|
||||
$orphan = decode_ws(http_request($base_url.'/ws.php?format=json', array('method'=>'bratonien.nc.syncOrphans', 'site_id'=>1, 'simulate'=>0), array(), $cookie_file));
|
||||
$added = (int)($orphan['added_orphans'] ?? 0);
|
||||
$deleted = (int)($orphan['deleted_orphans'] ?? 0);
|
||||
|
||||
echo "Piwigo-Datenbanksynchronisierung per Benutzername/Passwort-Fallback erfolgreich\n";
|
||||
echo "Piwigo-Orphans synchronisiert: +$added / -$deleted\n";
|
||||
}
|
||||
|
||||
@@ -13,7 +13,31 @@ fi
|
||||
|
||||
result=0
|
||||
for config in "${configs[@]}"; do
|
||||
echo "NC Connector: $(basename "$config")"
|
||||
name="$(basename "$config")"
|
||||
connection_id=""
|
||||
if [[ "$name" =~ ^connection-([0-9]+)\.conf$ ]]; then
|
||||
connection_id="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
|
||||
piwigo_root="$(sed -n 's/^PIWIGO_ROOT=//p' "$config" | tail -n 1)"
|
||||
piwigo_root="${piwigo_root%\"}"
|
||||
piwigo_root="${piwigo_root#\"}"
|
||||
piwigo_root="${piwigo_root%\'}"
|
||||
piwigo_root="${piwigo_root#\'}"
|
||||
[[ -n "$piwigo_root" ]] || piwigo_root="/var/www/piwigo"
|
||||
tombstone_dir="${piwigo_root%/}/_data/bratonien-tools/nc-connector-status"
|
||||
|
||||
if [[ -n "$connection_id" && -f "$tombstone_dir/deleted-$connection_id" ]]; then
|
||||
echo "NC Connector: Verbindung $connection_id wurde geloescht; Laufzeitdateien werden entfernt."
|
||||
rm -f -- "$CONFIG_DIR/connection-$connection_id.conf" \
|
||||
"$CONFIG_DIR/connection-$connection_id.db-password" \
|
||||
"$CONFIG_DIR/connection-$connection_id.piwigo-password" \
|
||||
"$CONFIG_DIR/connection-$connection_id.storages.tsv"
|
||||
rm -f -- "$tombstone_dir/deleted-$connection_id"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "NC Connector: $name"
|
||||
if ! env PIWIGO_CONFIG="$config" bash "$SCRIPT_DIR/sync.sh"; then
|
||||
result=1
|
||||
fi
|
||||
|
||||
@@ -32,7 +32,28 @@
|
||||
<dialog id="bratonien-nc-wizard-dialog" style="width:min(980px,calc(100vw - 3rem));max-height:88vh;overflow:auto;background:#444;color:inherit;border:1px solid #777;border-radius:4px;padding:0;box-shadow:0 18px 60px rgba(0,0,0,.55)">
|
||||
<div style="padding:1.25rem 1.5rem">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:1rem">
|
||||
<div><h4 style="margin:0">Neue Verbindung</h4><p class="bratonien-base-note" style="margin:.35rem 0 0"><strong>Schritt {$NC_CONNECTOR.wizard.step|escape:html} von 4</strong></p></div>
|
||||
<div>
|
||||
<h4 style="margin:0">Neue Verbindung</h4>
|
||||
<p class="bratonien-base-note" style="margin:.35rem 0 0"><strong>
|
||||
{if $NC_CONNECTOR.wizard.step == 1}
|
||||
Anmeldung
|
||||
{elseif $NC_CONNECTOR.wizard.step == 2 && $NC_CONNECTOR.wizard.technical_stage == 'database_details'}
|
||||
Datenbank prüfen
|
||||
{elseif $NC_CONNECTOR.wizard.step == 2 && $NC_CONNECTOR.wizard.technical_stage == 'mounts' && !$NC_CONNECTOR.wizard.directory_selection_ready}
|
||||
Speicher zuordnen
|
||||
{elseif $NC_CONNECTOR.wizard.step == 2 && $NC_CONNECTOR.wizard.technical_stage == 'mounts' && $NC_CONNECTOR.wizard.directory_selection_ready}
|
||||
Verzeichnisse auswählen
|
||||
{elseif $NC_CONNECTOR.wizard.step == 2 && $NC_CONNECTOR.wizard.technical_complete}
|
||||
Verbindung benennen
|
||||
{elseif $NC_CONNECTOR.wizard.step == 3}
|
||||
Piwigo-API
|
||||
{elseif $NC_CONNECTOR.wizard.step == 4}
|
||||
Abschluss
|
||||
{else}
|
||||
Einrichtung
|
||||
{/if}
|
||||
</strong></p>
|
||||
</div>
|
||||
<button class="buttonLike" type="button" id="bratonien-nc-wizard-close">Schließen</button>
|
||||
</div>
|
||||
|
||||
@@ -52,7 +73,7 @@
|
||||
</form>
|
||||
|
||||
{elseif $NC_CONNECTOR.wizard.step == 2}
|
||||
<p class="bratonien-base-note"><strong>Nextcloud wurde gefunden.</strong> Der Assistent verwendet den Zugang aus dem ersten Schritt auch für den benötigten Lesezugriff.</p>
|
||||
<p class="bratonien-base-note"><strong>Nextcloud wurde gefunden.</strong> Für den Datenzugriff wird die bekannte Reader-Verbindung verwendet. Verzeichnisse werden ausschließlich mit dem angemeldeten Nextcloud-Benutzer gelesen.</p>
|
||||
<div class="bratonien-form-grid">
|
||||
<span class="bratonien-label">Adresse</span><strong>{$NC_CONNECTOR.wizard.base_url|escape:html}</strong>
|
||||
<span class="bratonien-label">Version</span><strong>{if $NC_CONNECTOR.wizard.version}{$NC_CONNECTOR.wizard.version|escape:html}{else}Nicht gemeldet{/if}</strong>
|
||||
@@ -62,7 +83,7 @@
|
||||
{if $NC_CONNECTOR.wizard.technical_stage == 'database_details'}
|
||||
<hr>
|
||||
<h5>Datenbank-Adresse prüfen</h5>
|
||||
<p class="bratonien-base-note">Der Zugang aus dem ersten Schritt bleibt unverändert. Nur die Verbindungsadresse konnte nicht automatisch bestätigt werden.</p>
|
||||
<p class="bratonien-base-note">Die bekannte Reader-Verbindung konnte mit der gespeicherten Adresse nicht bestätigt werden.</p>
|
||||
{if $NC_CONNECTOR.wizard.technical_error}<details><summary>Technische Details</summary><p class="bratonien-main-cache__warning">{$NC_CONNECTOR.wizard.technical_error|escape:html}</p></details>{/if}
|
||||
<form method="post" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
@@ -76,46 +97,103 @@
|
||||
|
||||
{elseif $NC_CONNECTOR.wizard.technical_stage == 'mounts'}
|
||||
<hr>
|
||||
<h5>Speicherort bestätigen</h5>
|
||||
<p class="bratonien-base-note">Die Datenquelle wurde gefunden. Nur Speicherorte, die nicht sicher erkannt werden konnten, müssen jetzt einmalig zugeordnet werden.</p>
|
||||
<form method="post" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
{if $NC_CONNECTOR.wizard.directory_selection_ready}
|
||||
<h5>Verzeichnisse auswählen</h5>
|
||||
<p class="bratonien-base-note">Es werden nur Verzeichnisse angezeigt, auf die <strong>{$NC_CONNECTOR.wizard.username|escape:html}</strong> in Nextcloud Zugriff hat. Mehrere Verzeichnisse können hinzugefügt werden. Bleibt die Auswahl leer, wird automatisch das Stammverzeichnis verwendet.</p>
|
||||
|
||||
<div class="bratonien-form-grid">
|
||||
{foreach from=$NC_CONNECTOR.wizard.storage_candidates item=storage key=storage_index}
|
||||
<span class="bratonien-label">Speicher {$storage_index+1}</span>
|
||||
{if $storage.local_mount}
|
||||
<strong>Automatisch erkannt</strong>
|
||||
<input type="hidden" name="nc_wizard_storage_mount[{$storage_index|escape:html}]" value="{$storage.local_mount|escape:html}">
|
||||
<span class="bratonien-label">Ausgewählt</span>
|
||||
<div>
|
||||
{if $NC_CONNECTOR.wizard.directory_selected|@count > 0}
|
||||
{foreach from=$NC_CONNECTOR.wizard.directory_selected item=selected_path}
|
||||
<form method="post" class="bratonien-actions" style="margin:.25rem 0" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
<input type="hidden" name="nc_wizard_directory_remove" value="{$selected_path|escape:html}">
|
||||
<strong style="flex:1">{if $selected_path}{$selected_path|escape:html}{else}Stammverzeichnis{/if}</strong>
|
||||
<button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_directory_remove">Entfernen</button>
|
||||
</form>
|
||||
{/foreach}
|
||||
{else}
|
||||
<input name="nc_wizard_storage_mount[{$storage_index|escape:html}]" type="text" placeholder="Eingebundener Speicherpfad" required>
|
||||
<span class="bratonien-base-note">Keine Auswahl – Stammverzeichnis wird verwendet.</span>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</div>
|
||||
|
||||
<span class="bratonien-label">Aktueller Ordner</span><strong>/{if $NC_CONNECTOR.wizard.directory_path}{$NC_CONNECTOR.wizard.directory_path|escape:html}{/if}</strong>
|
||||
</div>
|
||||
<p><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_save_mounts">Speicher prüfen</button></p>
|
||||
</form>
|
||||
|
||||
<div class="bratonien-actions" style="margin:.75rem 0">
|
||||
<form method="post" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
<button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_directory_add">Diesen Ordner hinzufügen</button>
|
||||
</form>
|
||||
{if $NC_CONNECTOR.wizard.directory_path}
|
||||
<form method="post" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
<input type="hidden" name="nc_wizard_directory_path" value="{$NC_CONNECTOR.wizard.directory_parent|escape:html}">
|
||||
<button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_directory_browse">Eine Ebene hoch</button>
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div style="margin:.75rem 0">
|
||||
{if $NC_CONNECTOR.wizard.directory_children|@count > 0}
|
||||
{foreach from=$NC_CONNECTOR.wizard.directory_children item=directory_name key=directory_path}
|
||||
<form method="post" style="margin:.3rem 0" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
<input type="hidden" name="nc_wizard_directory_path" value="{$directory_path|escape:html}">
|
||||
<button class="buttonLike" style="width:100%;text-align:left" type="submit" name="bratonien_tool" value="nc_connector_wizard_directory_browse">📁 {$directory_name|escape:html}</button>
|
||||
</form>
|
||||
{/foreach}
|
||||
{else}
|
||||
<p class="bratonien-base-note">Keine Unterordner vorhanden.</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<form method="post" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
{foreach from=$NC_CONNECTOR.wizard.storage_candidates item=storage key=storage_index}
|
||||
<input type="hidden" name="nc_wizard_storage_mount[{$storage_index|escape:html}]" value="{$storage.local_mount|escape:html}">
|
||||
{/foreach}
|
||||
<p><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_save_mounts">Verzeichnisse übernehmen</button></p>
|
||||
</form>
|
||||
{else}
|
||||
<h5>Speicherort bestätigen</h5>
|
||||
<p class="bratonien-base-note">Die Datenquelle wurde gefunden. Ein technischer Speicherort konnte nicht automatisch zugeordnet werden.</p>
|
||||
<form method="post" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
<div class="bratonien-form-grid">
|
||||
{foreach from=$NC_CONNECTOR.wizard.storage_candidates item=storage key=storage_index}
|
||||
<span class="bratonien-label">Speicher {$storage_index+1}</span>
|
||||
{if $storage.local_mount}
|
||||
<strong>Automatisch erkannt</strong>
|
||||
<input type="hidden" name="nc_wizard_storage_mount[{$storage_index|escape:html}]" value="{$storage.local_mount|escape:html}">
|
||||
{else}
|
||||
<input name="nc_wizard_storage_mount[{$storage_index|escape:html}]" type="text" placeholder="Eingebundener Speicherpfad" required>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</div>
|
||||
<p><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_save_mounts">Speicher prüfen</button></p>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
{elseif $NC_CONNECTOR.wizard.technical_complete}
|
||||
<hr>
|
||||
<h5>Welche Freigaben sollen verwendet werden?</h5>
|
||||
<p class="bratonien-base-note"><strong>Empfehlung:</strong> ein eigener Showcase-Benutzer. So bleibt die Verbindung unabhängig von persönlichen Konten.</p>
|
||||
<h5>Verbindung benennen</h5>
|
||||
<p class="bratonien-base-note">Diese Verbindung verwendet ausschließlich den in Schritt 1 angemeldeten Nextcloud-Benutzer.</p>
|
||||
<form method="post" data-bratonien-wizard-form>
|
||||
<input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}">
|
||||
<div class="bratonien-form-grid">
|
||||
<label class="bratonien-label" for="nc_wizard_connection_name">Name der Verbindung</label><input id="nc_wizard_connection_name" name="nc_wizard_connection_name" type="text" value="{$NC_CONNECTOR.wizard.connection_name|escape:html}" required>
|
||||
<label class="bratonien-label" for="nc_wizard_showcase_user">Nextcloud-Benutzer</label>
|
||||
{if $NC_CONNECTOR.wizard.can_list_users && $NC_CONNECTOR.wizard.users|@count > 0}
|
||||
<select id="nc_wizard_showcase_user" name="nc_wizard_showcase_user" required>
|
||||
{foreach from=$NC_CONNECTOR.wizard.users item=nc_user}<option value="{$nc_user|escape:html}"{if $nc_user == 'showcase'} selected{/if}>{$nc_user|escape:html}{if $nc_user == 'showcase'} · empfohlen{/if}</option>{/foreach}
|
||||
</select>
|
||||
{else}
|
||||
<input id="nc_wizard_showcase_user" name="nc_wizard_showcase_user" type="text" value="{if $NC_CONNECTOR.wizard.showcase_user}{$NC_CONNECTOR.wizard.showcase_user|escape:html}{else}showcase{/if}" required>
|
||||
{/if}
|
||||
<span class="bratonien-label">Nextcloud-Benutzer</span><strong>{$NC_CONNECTOR.wizard.username|escape:html}</strong>
|
||||
</div>
|
||||
<p><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_select_user">Weiter</button></p>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
<form method="post" style="margin-top:1rem" data-bratonien-wizard-form><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_reset" data-bratonien-wizard-end>Neu beginnen</button></form>
|
||||
<div class="bratonien-actions" style="margin-top:1rem">
|
||||
<form method="post" data-bratonien-wizard-form><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_back">Zurück</button></form>
|
||||
<form method="post" data-bratonien-wizard-form><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_reset" data-bratonien-wizard-end>Neu beginnen</button></form>
|
||||
</div>
|
||||
|
||||
{elseif $NC_CONNECTOR.wizard.step == 3}
|
||||
<p class="bratonien-base-note"><strong>Nextcloud ist vorbereitet.</strong> Jetzt wird der bevorzugte Piwigo-Zugang geprüft.</p>
|
||||
@@ -128,13 +206,14 @@
|
||||
</div>
|
||||
<div class="bratonien-actions"><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_api_test">API testen</button><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_api_skip" formnovalidate>Überspringen</button></div>
|
||||
</form>
|
||||
<form method="post" style="margin-top:1rem" data-bratonien-wizard-form><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_back">Zurück</button></form>
|
||||
|
||||
{elseif $NC_CONNECTOR.wizard.step == 4}
|
||||
<p class="bratonien-base-note"><strong>Fast fertig.</strong> Die Verbindung wurde noch nicht angelegt. Erst der letzte Button übernimmt die Einstellungen.</p>
|
||||
<div class="bratonien-form-grid">
|
||||
<span class="bratonien-label">Verbindung</span><strong>{$NC_CONNECTOR.wizard.connection_name|escape:html}</strong>
|
||||
<span class="bratonien-label">Nextcloud</span><strong>{$NC_CONNECTOR.wizard.base_url|escape:html}</strong>
|
||||
<span class="bratonien-label">Freigaben von</span><strong>{$NC_CONNECTOR.wizard.showcase_user|escape:html}</strong>
|
||||
<span class="bratonien-label">Nextcloud-Benutzer</span><strong>{$NC_CONNECTOR.wizard.username|escape:html}</strong>
|
||||
<span class="bratonien-label">Piwigo-API</span><strong>{if $NC_CONNECTOR.wizard.api_status == 'ok'}Erfolgreich geprüft{else}Übersprungen{/if}</strong>
|
||||
</div>
|
||||
<hr>
|
||||
@@ -148,6 +227,7 @@
|
||||
</div>
|
||||
<div class="bratonien-actions"><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_finish" data-bratonien-wizard-end>Verbindung anlegen</button><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_reset" formnovalidate data-bratonien-wizard-end>Abbrechen</button></div>
|
||||
</form>
|
||||
<form method="post" style="margin-top:1rem" data-bratonien-wizard-form><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_wizard_back">Zurück</button></form>
|
||||
{/if}
|
||||
</div>
|
||||
</dialog>
|
||||
@@ -184,14 +264,28 @@
|
||||
{if $NC_CONNECTOR.connection_count > 0}
|
||||
{foreach from=$NC_CONNECTOR.connections item=connection}
|
||||
<details style="margin:.6rem 0">
|
||||
<summary><strong>{$connection.display_name|escape:html}</strong> · {if $connection.enabled}aktiv{else}{$connection.takeover_state|escape:html}{/if}</summary>
|
||||
<summary><strong>{$connection.display_name|escape:html}</strong> · {if $connection.enabled}aktiv{else}{$connection.takeover_state|escape:html}{/if}{if isset($connection.last_sync) && ($connection.last_sync.state == 'error' || $connection.last_sync.state == 'warning')} · Laufzeitproblem{/if}</summary>
|
||||
<div style="padding:.75rem 0">
|
||||
<form method="post" class="bratonien-actions"><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><input type="hidden" name="connection_id" value="{$connection.id|escape:html}"><input name="connection_name" type="text" value="{$connection.name|escape:html}" required><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_update_name">Name speichern</button></form>
|
||||
<div class="bratonien-actions" style="margin-top:.6rem">
|
||||
{if $connection.adapter == 'local' && !$connection.enabled}<form method="post"><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><input type="hidden" name="connection_id" value="{$connection.id|escape:html}"><button class="buttonLike" type="submit" name="bratonien_tool" value="nc_connector_verify">Verbindung prüfen</button></form>{/if}
|
||||
{if !$connection.enabled && $connection.takeover_state != 'active'}<form method="post"><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><input type="hidden" name="connection_id" value="{$connection.id|escape:html}"><button class="buttonLike bratonien-delete-button" type="submit" name="bratonien_tool" value="nc_connector_delete" onclick="return confirm('Verbindung wirklich löschen? Bilder in Nextcloud oder Piwigo werden nicht gelöscht.');">Löschen</button></form>{/if}
|
||||
<form method="post"><input type="hidden" name="pwg_token" value="{$PWG_TOKEN|escape:html}"><input type="hidden" name="connection_id" value="{$connection.id|escape:html}"><button class="buttonLike bratonien-delete-button" type="submit" name="bratonien_tool" value="nc_connector_delete" onclick="return confirm('Verbindung wirklich löschen? Die Verbindung wird sofort aus Bratonien Tools entfernt und beim nächsten Connector-Lauf auch aus der Laufzeit entfernt. Bilder in Nextcloud oder Piwigo werden nicht gelöscht.');">Löschen</button></form>
|
||||
</div>
|
||||
{if isset($connection.last_sync) && $connection.last_sync.timestamp > 0}<p class="bratonien-base-note"><strong>Letzter Abgleich:</strong> {$connection.last_sync.label|escape:html} · {$connection.last_sync.message|escape:html}</p>{/if}
|
||||
{if isset($connection.last_sync) && $connection.last_sync.timestamp > 0}
|
||||
<p class="bratonien-base-note"><strong>Letzter Abgleich:</strong> {$connection.last_sync.label|escape:html} · {$connection.last_sync.message|escape:html}</p>
|
||||
{if $connection.last_sync.state == 'error'}<p class="bratonien-main-cache__warning"><strong>Laufzeitfehler:</strong> {$connection.last_sync.message|escape:html}</p>{/if}
|
||||
{if $connection.last_sync.state == 'warning'}<p class="bratonien-main-cache__warning"><strong>Laufzeitwarnung:</strong> {$connection.last_sync.message|escape:html}</p>{/if}
|
||||
{if $connection.last_sync.api_state == 'error'}<p class="bratonien-main-cache__warning"><strong>API:</strong> {$connection.last_sync.api_message|escape:html}</p>{/if}
|
||||
{if $connection.last_sync.fallback_state == 'error'}<p class="bratonien-main-cache__warning"><strong>Fallback:</strong> {$connection.last_sync.fallback_message|escape:html}</p>{/if}
|
||||
{if $connection.last_sync.error_detail}<details><summary>Technische Laufzeitdetails</summary><p class="bratonien-main-cache__warning">{$connection.last_sync.error_detail|escape:html}</p></details>{/if}
|
||||
{else}
|
||||
<p class="bratonien-base-note"><strong>Laufzeit:</strong> Noch kein Laufstatus für diese Verbindung vorhanden.</p>
|
||||
{/if}
|
||||
{if isset($connection.config.api_enabled)}
|
||||
<p class="bratonien-base-note"><strong>Piwigo-Zugang dieser Verbindung:</strong> {if $connection.config.api_enabled}eigene API{elseif $connection.fallback_stored}Fallback{else}kein Zugang gespeichert{/if}</p>
|
||||
{else}
|
||||
<p class="bratonien-base-note"><strong>Piwigo-Zugang:</strong> bestehende Legacy-Konfiguration</p>
|
||||
{/if}
|
||||
{if $connection.verification_checks|@count > 0}<details><summary>Letzte Prüfung</summary><ul>{foreach from=$connection.verification_checks item=check}<li>{if $check.ok}✓{else}✗{/if} {$check.name|escape:html}: {$check.detail|escape:html}</li>{/foreach}</ul></details>{/if}
|
||||
<details style="margin-top:.75rem"><summary>Technische Einstellungen</summary>
|
||||
{if $connection.enabled || $connection.takeover_state == 'active'}<p class="bratonien-main-cache__warning">Aktive Verbindungen können technisch nicht geändert werden.</p>{else}
|
||||
|
||||
Reference in New Issue
Block a user