Initial commit: Hermes AI Bridge WordPress plugin for cPanel agent runtime
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user