remote upload backend functionality

This commit is contained in:
Čarodej
2022-04-20 18:19:25 +02:00
parent 19e29e69e0
commit dc8e3c8141
9 changed files with 272 additions and 11 deletions

View File

@@ -0,0 +1,102 @@
<?php
namespace Domain\Files\Actions;
use App\Users\Models\User;
use Domain\Files\Models\File;
use Error;
use ErrorException;
use Illuminate\Support\Str;
use Domain\Sharing\Models\Share;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Log;
use Spatie\QueueableAction\QueueableAction;
class GetContentFromExternalSource
{
use QueueableAction;
public function __construct(
public ProcessFileAction $processFile,
public StoreFileExifMetadataAction $storeExifMetadata,
public MoveFileToFTPStorageAction $moveFileToFTPStorage,
public ProcessImageThumbnailAction $createImageThumbnail,
public MoveFileToExternalStorageAction $moveFileToExternalStorage,
) {}
public function __invoke(
array $payload,
User $user,
) {
foreach ($payload['urls'] as $url) {
try {
// Get local disk instance
$localDisk = Storage::disk('local');
// Get file from external source
$response = Http::get($url);
// Get extension from response
$extension = extractExtensionFromUrl($url, $response);
// Get blacklisted mimetypes
$this->checkDisabledMimetypes($extension);
// Get file basename
$basename = Str::uuid() . ".$extension";
// Get file name
$name = array_key_exists('filename', pathinfo($url))
? explode('?', pathinfo($url)['filename'])[0]
: Str::uuid();
// Get file path
$path = "files/$user->id/$basename";
// Store file to main storage disk
$localDisk->put($path, $response->getBody());
// Create multiple image thumbnails
($this->createImageThumbnail)($basename, $user->id);
// Create new file
$file = File::create([
'mimetype' => $extension,
'type' => getFileType($localDisk->mimeType($path)),
'parent_id' => $payload['parent_id'] ?? null,
'name' => $name ?? $basename,
'basename' => $basename,
'filesize' => $localDisk->size($path),
'user_id' => $user->id,
'creator_id' => auth()->id(),
]);
// Store file exif information
($this->storeExifMetadata)($file);
// Move file to external storage
match (config('filesystems.default')) {
's3' => ($this->moveFileToExternalStorage)($basename, $user->id),
'ftp', 'azure' => ($this->moveFileToFTPStorage)($basename, $user->id),
default => null
};
} catch ( ErrorException | Error $e) {
Log::error("Remote upload failed as {$e->getMessage()}");
Log::error($e->getTraceAsString());
}
}
}
/**
* @param string|null $extension
*/
protected function checkDisabledMimetypes(?string $extension): void
{
$mimetypeBlacklist = explode(',', get_settings('mimetypes_blacklist')) ?? null;
// If is extension in mimetype blacklist, Abort!
if ($extension && array_intersect([str_replace('.', '', ".$extension")], $mimetypeBlacklist)) {
abort(422);
}
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Domain\Files\Controllers;
use Domain\Folders\Models\Folder;
use Illuminate\Http\Response;
use Domain\Sharing\Models\Share;
use App\Http\Controllers\Controller;
use Domain\Files\Requests\RemoteUploadRequest;
use Domain\Files\Actions\GetContentFromExternalSource;
class RemoteUploadFileController extends Controller
{
public function __construct(
public GetContentFromExternalSource $getContentFromExternalSource,
) {}
public function __invoke(RemoteUploadRequest $request, ?Share $shared = null): Response|array
{
if (is_demo_account()) {
return response('Files were successfully added to the upload queue', 201);
}
// Get user
$user = $request->filled('parent_id')
? Folder::find($request->input('parent_id'))->getLatestParent()->user
: auth()->user();
// Execute job for get content from url and save
($this->getContentFromExternalSource)
->onQueue()
->execute($request->all(), $user);
return response('Files were successfully added to the upload queue', 201);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Domain\Files\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RemoteUploadRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'urls.*' => 'required|url',
'parent_id' => 'nullable|uuid',
];
}
}

View File

@@ -1157,4 +1157,36 @@ if (! function_exists('replace_occurrence')) {
return "{$degrees}°$minutes'$seconds\"$ref";
}
}
if (! function_exists('extractExtensionFromUrl')) {
/**
* Extract extension from the url
*
* TODO: make unit test
*/
function extractExtensionFromUrl($url, $response): string|null
{
$string = str_replace(['&'], '?', pathinfo($url)['extension']);
// Get extension from url path
$extension = array_key_exists('extension', pathinfo($url))
? explode('?', $string)[0]
: null;
// Return pure extension
if ($extension) {
return $extension;
}
// Prepare header for extracting content-type line
$header = array_change_key_case($response->headers(), CASE_LOWER);
// Get extension
if (array_key_exists('content-type', $header)) {
return '.' . explode('/', $header['content-type'][0])[1];
}
return null;
}
}
}