2026-05-28 09:34:28 +02:00
< ? php
declare ( strict_types = 1 );
namespace App\Http\Controllers ;
use App\Models\StorageRepository ;
use App\Services\StorageRepositoryService ;
use Illuminate\Http\JsonResponse ;
use Illuminate\Http\RedirectResponse ;
use Illuminate\Http\Request ;
2026-05-28 13:25:47 +02:00
use Illuminate\View\View ;
2026-05-28 09:34:28 +02:00
use Symfony\Component\HttpFoundation\StreamedResponse ;
class StorageRepositoryController extends Controller
{
public function __construct (
private readonly StorageRepositoryService $repoService
) {}
public function index ( Request $request )
{
$this -> authorizeWrite ( 'settings' );
$repositories = StorageRepository :: orderBy ( 'ordine' ) -> get ();
if ( $request -> ajax ()) {
return response () -> json ( $repositories );
}
return view ( 'storage-repositories.index' , compact ( 'repositories' ));
}
public function store ( Request $request ) : RedirectResponse
{
$this -> authorizeWrite ( 'settings' );
$validated = $request -> validate ([
'nome' => 'required|string|max:255' ,
'tipo' => 'required|string|in:webdav,google_drive' ,
'config' => 'required|array' ,
'is_active' => 'boolean' ,
'ordine' => 'nullable|integer|min:0' ,
]);
$maxOrdine = StorageRepository :: max ( 'ordine' ) ? ? 0 ;
$validated [ 'ordine' ] ? ? = $maxOrdine + 1 ;
$validated [ 'config' ] = $this -> repoService -> encryptSensitiveConfig ( $validated [ 'config' ], $validated [ 'tipo' ]);
StorageRepository :: create ( $validated );
return redirect ( '/impostazioni#repository' ) -> with ( 'success' , 'Repository creato.' );
}
public function update ( Request $request , StorageRepository $storageRepository ) : RedirectResponse
{
$this -> authorizeWrite ( 'settings' );
$validated = $request -> validate ([
'nome' => 'required|string|max:255' ,
'tipo' => 'required|string|in:webdav,google_drive' ,
'config' => 'required|array' ,
'is_active' => 'boolean' ,
'ordine' => 'nullable|integer|min:0' ,
]);
2026-05-28 13:25:47 +02:00
$validated [ 'config' ] = $this -> repoService -> encryptSensitiveConfig (
$validated [ 'config' ],
$validated [ 'tipo' ],
$storageRepository -> config
);
2026-05-28 09:34:28 +02:00
$storageRepository -> update ( $validated );
return redirect ( '/impostazioni#repository' ) -> with ( 'success' , 'Repository aggiornato.' );
}
public function destroy ( StorageRepository $storageRepository ) : JsonResponse | RedirectResponse
{
$this -> authorizeDelete ( 'settings' );
$docCount = $storageRepository -> documenti () -> count ();
if ( $docCount > 0 ) {
$message = " Impossibile eliminare: { $docCount } documenti associati a questo repository. " ;
if ( request () -> expectsJson ()) {
return response () -> json ([ 'success' => false , 'message' => $message ], 409 );
}
return redirect ( '/impostazioni#repository' ) -> with ( 'error' , $message );
}
$storageRepository -> delete ();
if ( request () -> expectsJson ()) {
return response () -> json ([ 'success' => true ]);
}
return redirect ( '/impostazioni#repository' ) -> with ( 'success' , 'Repository eliminato.' );
}
public function test ( StorageRepository $storageRepository ) : JsonResponse
{
$this -> authorizeWrite ( 'settings' );
$result = $this -> repoService -> testConnection ( $storageRepository );
return response () -> json ( $result );
}
public function browse ( Request $request , StorageRepository $storageRepository ) : JsonResponse
{
$this -> authorizeRead ( 'documenti' );
$path = $request -> get ( 'path' , '/' );
$contents = $this -> repoService -> listContents ( $storageRepository , $path );
return response () -> json ([
'success' => true ,
'contents' => $contents ,
'path' => $path ,
'repository' => [
'id' => $storageRepository -> id ,
'nome' => $storageRepository -> nome ,
'tipo' => $storageRepository -> tipo ,
],
]);
}
public function reorder ( Request $request ) : JsonResponse
{
$this -> authorizeWrite ( 'settings' );
$order = $request -> input ( 'order' , []);
foreach ( $order as $index => $id ) {
StorageRepository :: where ( 'id' , $id ) -> update ([ 'ordine' => $index ]);
}
return response () -> json ([ 'success' => true ]);
}
public function downloadRemote ( StorageRepository $storageRepository , Request $request ) : StreamedResponse
{
$this -> authorizeRead ( 'documenti' );
$path = $request -> get ( 'path' );
if ( ! $path ) {
abort ( 400 , 'Path required' );
}
$filesystem = $this -> repoService -> buildFilesystem ( $storageRepository );
if ( ! $filesystem || ! $filesystem -> fileExists ( $path )) {
abort ( 404 );
}
$stream = $filesystem -> readStream ( $path );
if ( ! $stream ) {
abort ( 404 );
}
$mimeType = $filesystem -> mimeType ( $path ) ? ? 'application/octet-stream' ;
$basename = basename ( $path );
return response () -> stream ( function () use ( $stream ) {
fpassthru ( $stream );
fclose ( $stream );
}, 200 , [
'Content-Type' => $mimeType ,
'Content-Disposition' => 'attachment; filename="' . $basename . '"' ,
]);
}
public function previewRemote ( StorageRepository $storageRepository , Request $request ) : StreamedResponse
{
$this -> authorizeRead ( 'documenti' );
$path = $request -> get ( 'path' );
if ( ! $path ) {
abort ( 400 , 'Path required' );
}
$filesystem = $this -> repoService -> buildFilesystem ( $storageRepository );
if ( ! $filesystem || ! $filesystem -> fileExists ( $path )) {
abort ( 404 );
}
$stream = $filesystem -> readStream ( $path );
if ( ! $stream ) {
abort ( 404 );
}
$mimeType = $filesystem -> mimeType ( $path ) ? ? 'application/octet-stream' ;
$basename = basename ( $path );
return response () -> stream ( function () use ( $stream ) {
fpassthru ( $stream );
fclose ( $stream );
}, 200 , [
'Content-Type' => $mimeType ,
'Content-Disposition' => 'inline; filename="' . $basename . '"' ,
]);
}
2026-05-28 13:25:47 +02:00
public function oauthRedirect ( Request $request ) : RedirectResponse
{
$this -> authorizeWrite ( 'settings' );
$clientId = $request -> get ( 'client_id' );
$clientSecret = $request -> get ( 'client_secret' );
$repoId = ( int ) $request -> get ( 'repo_id' , 0 );
if ( empty ( $clientId ) || empty ( $clientSecret )) {
return redirect ( '/impostazioni#repository' ) -> with ( 'error' , 'Inserisci Client ID e Client Secret prima di autorizzare.' );
}
session ([ 'google_drive_oauth' => [
'client_id' => $clientId ,
'client_secret' => $clientSecret ,
'repo_id' => $repoId ,
'nome' => $request -> get ( 'nome' , '' ),
'is_active' => $request -> get ( 'is_active' , '1' ),
'root_folder_id' => $request -> get ( 'root_folder_id' , 'root' ),
]]);
$client = new \Google_Client ();
$client -> setClientId ( $clientId );
$client -> setClientSecret ( $clientSecret );
$client -> setRedirectUri ( url ( '/auth/google-drive/callback' ));
$client -> addScope ( \Google_Service_Drive :: DRIVE );
$client -> setAccessType ( 'offline' );
$client -> setPrompt ( 'consent' );
$authUrl = $client -> createAuthUrl ();
return redirect () -> away ( $authUrl );
}
public function oauthCallback ( Request $request ) : RedirectResponse
{
$this -> authorizeWrite ( 'settings' );
if ( $request -> get ( 'error' )) {
return redirect ( '/impostazioni#repository' ) -> with ( 'error' , 'Autorizzazione Google Drive annullata o fallita.' );
}
$code = $request -> get ( 'code' );
if ( ! $code ) {
return redirect ( '/impostazioni#repository' ) -> with ( 'error' , 'Codice di autorizzazione mancante.' );
}
$oauthData = session ( 'google_drive_oauth' );
if ( ! $oauthData ) {
return redirect ( '/impostazioni#repository' ) -> with ( 'error' , 'Sessione scaduta. Riprova l\'autorizzazione.' );
}
try {
$client = new \Google_Client ();
$client -> setClientId ( $oauthData [ 'client_id' ]);
$client -> setClientSecret ( $oauthData [ 'client_secret' ]);
$client -> setRedirectUri ( url ( '/auth/google-drive/callback' ));
$client -> addScope ( \Google_Service_Drive :: DRIVE );
$token = $client -> fetchAccessTokenWithAuthCode ( $code );
if ( isset ( $token [ 'error' ])) {
throw new \Exception ( $token [ 'error_description' ] ? ? $token [ 'error' ]);
}
$refreshToken = $client -> getRefreshToken ();
if ( ! $refreshToken ) {
throw new \Exception ( 'Refresh token non ricevuto. Assicurati che l\'app OAuth sia configurata con access_type=offline e prompt=consent nella Google Cloud Console.' );
}
$repoId = $oauthData [ 'repo_id' ];
session () -> forget ( 'google_drive_oauth' );
if ( $repoId > 0 ) {
$repo = StorageRepository :: find ( $repoId );
if ( $repo ) {
$config = $repo -> config ;
$config [ 'client_id' ] = $oauthData [ 'client_id' ];
$config [ 'client_secret' ] = $oauthData [ 'client_secret' ];
$config [ 'refresh_token' ] = $refreshToken ;
$config = $this -> repoService -> encryptSensitiveConfig ( $config , 'google_drive' );
$repo -> update ([ 'config' => $config ]);
return redirect ( '/impostazioni#repository' ) -> with ( 'success' , 'Google Drive autorizzato con successo! Refresh token salvato.' );
}
return redirect ( '/impostazioni#repository' ) -> with ( 'error' , 'Repository non trovato (ID: ' . $repoId . ').' );
}
session () -> flash ( 'google_drive_new_token' , [
'refresh_token' => $refreshToken ,
'client_id' => $oauthData [ 'client_id' ],
'client_secret' => $oauthData [ 'client_secret' ],
'nome' => $oauthData [ 'nome' ] ? ? '' ,
'is_active' => $oauthData [ 'is_active' ] ? ? '1' ,
'root_folder_id' => $oauthData [ 'root_folder_id' ] ? ? 'root' ,
]);
return redirect ( '/impostazioni#repository' ) -> with ( 'success' , 'Autorizzazione Google Drive completata! Ora completa la creazione del repository e salva.' );
} catch ( \Exception $e ) {
return redirect ( '/impostazioni#repository' ) -> with ( 'error' , 'Errore autorizzazione Google Drive: ' . $e -> getMessage ());
}
}
2026-05-28 09:34:28 +02:00
}