146 lines
5.3 KiB
PHP
146 lines
5.3 KiB
PHP
<?php
|
|
/**
|
|
* Nextcloud Bridge — File operations on same-server Nextcloud instance.
|
|
*/
|
|
namespace HermesAiBridge;
|
|
|
|
defined('ABSPATH') or die();
|
|
|
|
class NextcloudBridge {
|
|
protected $base_url;
|
|
protected $username;
|
|
protected $password;
|
|
protected $webdav_url;
|
|
|
|
public function __construct() {
|
|
$this->base_url = get_option('hermes_nextcloud_url', '');
|
|
$this->username = get_option('hermes_nextcloud_user', '');
|
|
$this->password = get_option('hermes_nextcloud_pass', '');
|
|
$this->webdav_url = rtrim($this->base_url, '/') . '/remote.php/dav/files/' . $this->username . '/';
|
|
}
|
|
|
|
/**
|
|
* List files in Nextcloud directory.
|
|
*/
|
|
public function list_files($path = '/') {
|
|
if (!$this->is_configured()) return new \WP_Error('not_configured', 'Nextcloud not configured');
|
|
|
|
$url = $this->webdav_url . ltrim($path, '/');
|
|
$response = $this->propfind($url);
|
|
|
|
if (is_wp_error($response)) return $response;
|
|
|
|
$files = [];
|
|
$dom = new \DOMDocument();
|
|
$dom->loadXML($response);
|
|
|
|
foreach ($dom->getElementsByTagNameNS('DAV:', 'response') as $node) {
|
|
$href = $node->getElementsByTagNameNS('DAV:', 'href')->item(0)->nodeValue ?? '';
|
|
if ($href === $this->webdav_url) continue; // skip root
|
|
|
|
$files[] = [
|
|
'path' => $href,
|
|
'name' => basename($href),
|
|
'size' => $node->getElementsByTagNameNS('DAV:', 'getcontentlength')->item(0)->nodeValue ?? 0,
|
|
'modified' => $node->getElementsByTagNameNS('DAV:', 'getlastmodified')->item(0)->nodeValue ?? '',
|
|
'type' => $node->getElementsByTagNameNS('DAV:', 'getcontenttype')->item(0)->nodeValue ?? 'directory',
|
|
];
|
|
}
|
|
|
|
return $files;
|
|
}
|
|
|
|
/**
|
|
* Upload a file to Nextcloud from WordPress Media Library.
|
|
*/
|
|
public function upload_from_media($attachment_id, $destination_path = '/') {
|
|
if (!$this->is_configured()) return new \WP_Error('not_configured', 'Nextcloud not configured');
|
|
|
|
$file_path = get_attached_file($attachment_id);
|
|
if (!$file_path || !file_exists($file_path)) {
|
|
return new \WP_Error('file_not_found', 'Attachment file not found on disk');
|
|
}
|
|
|
|
$filename = basename($file_path);
|
|
$dest_url = $this->webdav_url . ltrim($destination_path, '/') . '/' . $filename;
|
|
|
|
$response = wp_remote_request($dest_url, [
|
|
'method' => 'PUT',
|
|
'headers' => [
|
|
'Authorization' => 'Basic ' . base64_encode($this->username . ':' . $this->password),
|
|
'Content-Type' => get_post_mime_type($attachment_id) ?: 'application/octet-stream',
|
|
],
|
|
'body' => file_get_contents($file_path),
|
|
'timeout' => 60,
|
|
]);
|
|
|
|
if (is_wp_error($response)) return $response;
|
|
|
|
$status = wp_remote_retrieve_response_code($response);
|
|
if ($status < 200 || $status >= 300) {
|
|
return new \WP_Error('upload_failed', "WebDAV upload returned $status");
|
|
}
|
|
|
|
RestController::log('info', 'File uploaded to Nextcloud', ['file' => $filename, 'dest' => $dest_url]);
|
|
return ['success' => true, 'path' => $dest_url];
|
|
}
|
|
|
|
/**
|
|
* Download a file from Nextcloud into WordPress Media Library.
|
|
*/
|
|
public function import_to_media($nextcloud_path) {
|
|
if (!$this->is_configured()) return new \WP_Error('not_configured', 'Nextcloud not configured');
|
|
|
|
$url = $this->webdav_url . ltrim($nextcloud_path, '/');
|
|
$response = wp_remote_get($url, [
|
|
'headers' => [
|
|
'Authorization' => 'Basic ' . base64_encode($this->username . ':' . $this->password),
|
|
],
|
|
'timeout' => 60,
|
|
]);
|
|
|
|
if (is_wp_error($response)) return $response;
|
|
|
|
$body = wp_remote_retrieve_body($response);
|
|
$filename = basename($nextcloud_path);
|
|
$upload = wp_upload_bits($filename, null, $body);
|
|
|
|
if ($upload['error']) {
|
|
return new \WP_Error('upload_failed', $upload['error']);
|
|
}
|
|
|
|
$attachment = [
|
|
'post_mime_type' => wp_check_filetype($filename)['type'] ?: 'application/octet-stream',
|
|
'post_title' => sanitize_file_name($filename),
|
|
'post_content' => '',
|
|
'post_status' => 'inherit',
|
|
'guid' => $upload['url'],
|
|
];
|
|
|
|
$attach_id = wp_insert_attachment($attachment, $upload['file']);
|
|
require_once ABSPATH . 'wp-admin/includes/image.php';
|
|
wp_generate_attachment_metadata($attach_id, $upload['file']);
|
|
|
|
RestController::log('info', 'File imported from Nextcloud', ['file' => $filename, 'attachment_id' => $attach_id]);
|
|
return ['success' => true, 'attachment_id' => $attach_id, 'url' => $upload['url']];
|
|
}
|
|
|
|
protected function propfind($url) {
|
|
$response = wp_remote_request($url, [
|
|
'method' => 'PROPFIND',
|
|
'headers' => [
|
|
'Authorization' => 'Basic ' . base64_encode($this->username . ':' . $this->password),
|
|
'Depth' => '1',
|
|
],
|
|
'timeout' => 30,
|
|
]);
|
|
|
|
if (is_wp_error($response)) return $response;
|
|
return wp_remote_retrieve_body($response);
|
|
}
|
|
|
|
protected function is_configured() {
|
|
return !empty($this->base_url) && !empty($this->username) && !empty($this->password);
|
|
}
|
|
}
|