Files
glastree/app/Services/StorageRepositoryService.php
T

173 lines
6.4 KiB
PHP
Raw Normal View History

2026-05-28 09:34:28 +02:00
<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\StorageRepository;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
use League\Flysystem\Filesystem;
use League\Flysystem\WebDAV\WebDAVAdapter;
use As247\Flysystem\GoogleDrive\GoogleDriveAdapter;
use Sabre\DAV\Client as WebDAVClient;
class StorageRepositoryService
{
public function buildFilesystem(StorageRepository $repo): ?Filesystem
{
try {
$config = $repo->getDecryptedConfig();
return match ($repo->tipo) {
'webdav' => $this->buildWebDAV($config),
'google_drive' => $this->buildGoogleDrive($config),
default => null,
};
} catch (\Exception $e) {
Log::error("StorageRepository: failed to build filesystem for repo #{$repo->id} ({$repo->nome}): " . $e->getMessage());
return null;
}
}
public function testConnection(StorageRepository $repo): array
{
try {
$config = $repo->getDecryptedConfig();
if ($repo->tipo === 'google_drive') {
if (empty($config['client_id']) || empty($config['client_secret']) || empty($config['refresh_token'])) {
return ['success' => false, 'message' => 'Configurazione incompleta: client_id, client_secret e refresh_token sono necessari per Google Drive.'];
}
}
2026-05-28 09:34:28 +02:00
$filesystem = $this->buildFilesystem($repo);
if (!$filesystem) {
return ['success' => false, 'message' => 'Impossibile costruire il filesystem per questo tipo di repository.'];
}
$rootPath = $this->normalizePath('/');
$contents = $filesystem->listContents($rootPath, false)->toArray();
return ['success' => true, 'message' => 'Connessione riuscita. ' . count($contents) . ' elementi trovati nella root.'];
} catch (\Exception $e) {
Log::error("StorageRepository: test connection failed for repo #{$repo->id} ({$repo->nome}): " . $e->getMessage());
return ['success' => false, 'message' => 'Errore di connessione: ' . $e->getMessage()];
}
}
public function listContents(StorageRepository $repo, string $path = '/'): array
{
try {
$config = $repo->getDecryptedConfig();
if ($repo->tipo === 'google_drive') {
if (empty($config['client_id']) || empty($config['client_secret']) || empty($config['refresh_token'])) {
Log::warning("StorageRepository: listContents failed for repo #{$repo->id} ({$repo->nome}): credenziali Google Drive mancanti");
return [];
}
}
$filesystem = $this->buildFilesystem($repo);
if (!$filesystem) {
return [];
}
2026-05-28 09:34:28 +02:00
$normalizedPath = $this->normalizePath($path);
$items = $filesystem->listContents($normalizedPath, false)->toArray();
$result = [];
foreach ($items as $item) {
$result[] = [
'path' => $item->path(),
'type' => $item->type(),
'basename' => basename($item->path()),
'lastModified' => $item->lastModified(),
'fileSize' => $item->fileSize(),
'mimeType' => $item->mimeType(),
];
}
usort($result, fn($a, $b) => $a['type'] === 'dir' && $b['type'] !== 'dir' ? -1 : ($b['type'] === 'dir' && $a['type'] !== 'dir' ? 1 : strcasecmp($a['basename'], $b['basename'])));
return $result;
} catch (\Exception $e) {
Log::error("StorageRepository: listContents failed for repo #{$repo->id} path '{$path}': " . $e->getMessage());
return [];
}
}
public function encryptSensitiveConfig(array $config, string $tipo, array $existingConfig = []): array
2026-05-28 09:34:28 +02:00
{
$sensitiveFields = match ($tipo) {
'webdav' => ['password'],
'google_drive' => ['client_secret', 'refresh_token'],
default => [],
};
foreach ($sensitiveFields as $field) {
if (!empty($config[$field]) && !$this->isEncrypted($config[$field])) {
$config[$field] = Crypt::encryptString($config[$field]);
} elseif (empty($config[$field]) && !empty($existingConfig[$field])) {
$config[$field] = $existingConfig[$field];
2026-05-28 09:34:28 +02:00
}
}
return $config;
}
private function normalizePath(string $path): string
{
$path = trim($path);
if ($path === '' || $path === '\\') {
return '';
}
if ($path === '/') {
return '';
2026-05-28 09:34:28 +02:00
}
return ltrim($path, '/\\');
}
private function isEncrypted(string $value): bool
{
return str_starts_with($value, 'ey') || str_contains($value, ':');
}
private function buildWebDAV(array $config): ?Filesystem
{
$authType = match ($config['auth_type'] ?? 'basic') {
'basic' => WebDAVClient::AUTH_BASIC,
'digest' => WebDAVClient::AUTH_DIGEST,
'ntlm' => WebDAVClient::AUTH_NTLM,
default => WebDAVClient::AUTH_BASIC,
};
2026-05-28 09:34:28 +02:00
$client = new WebDAVClient([
'baseUri' => rtrim($config['base_uri'] ?? '', '/') . '/',
'userName' => $config['username'] ?? '',
'password' => $config['password'] ?? '',
'authType' => $authType,
2026-05-28 09:34:28 +02:00
]);
$root = ltrim($config['root'] ?? '/', '/');
$adapter = new WebDAVAdapter($client, $root);
return new Filesystem($adapter);
}
private function buildGoogleDrive(array $config): ?Filesystem
{
if (empty($config['client_id']) || empty($config['client_secret']) || empty($config['refresh_token'])) {
throw new \InvalidArgumentException('Google Drive richiede client_id, client_secret e refresh_token per l\'autenticazione.');
}
2026-05-28 09:34:28 +02:00
$client = new \Google_Client();
$client->setClientId($config['client_id']);
$client->setClientSecret($config['client_secret']);
$client->refreshToken($config['refresh_token']);
2026-05-28 09:34:28 +02:00
$client->addScope(\Google_Service_Drive::DRIVE);
$service = new \Google_Service_Drive($client);
$adapter = new GoogleDriveAdapter($service, $config['root_folder_id'] ?? 'root');
return new Filesystem($adapter);
}
}