mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-05-15 17:55:02 +00:00
Merge remote-tracking branch 'origin/remote-upload-merge'
# Conflicts: # public/mix-manifest.json
This commit is contained in:
@@ -38,6 +38,7 @@ use VueFileManager\Subscription\App\User\Traits\Billable;
|
||||
* @method static where(string $string, string $string1)
|
||||
* @method static create(array $array)
|
||||
* @method static find(mixed $email)
|
||||
* @method canUpload(int $size)
|
||||
*/
|
||||
class User extends Authenticatable implements MustVerifyEmail
|
||||
{
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
namespace Domain\Files\Actions;
|
||||
|
||||
use Log;
|
||||
use Error;
|
||||
use ErrorException;
|
||||
use App\Users\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Domain\Files\Models\File;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ class MoveFileToFTPStorageAction
|
||||
string $file,
|
||||
string $userId
|
||||
): void {
|
||||
|
||||
// Stream file object to ftp
|
||||
Storage::putFileAs("files/$userId", config('filesystems.disks.local.root') . "/files/$userId/$file", $file, 'private');
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
namespace Domain\Files\Actions;
|
||||
|
||||
use App\Users\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Domain\Files\Models\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Domain\Files\Requests\UploadRequest;
|
||||
use Domain\Traffic\Actions\RecordUploadAction;
|
||||
|
||||
class ProcessFileAction
|
||||
{
|
||||
public function __construct(
|
||||
public RecordUploadAction $recordUpload,
|
||||
public GetFileParentId $getFileParentId,
|
||||
public StoreFileExifMetadataAction $storeExifMetadata,
|
||||
public MoveFileToFTPStorageAction $moveFileToFTPStorage,
|
||||
public ProcessImageThumbnailAction $createImageThumbnail,
|
||||
public MoveFileToExternalStorageAction $moveFileToExternalStorage,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload new file
|
||||
*/
|
||||
public function __invoke(
|
||||
UploadRequest $request,
|
||||
User $user,
|
||||
string $chunkPath,
|
||||
) {
|
||||
// Get local disk instance
|
||||
$localDisk = Storage::disk('local');
|
||||
|
||||
// Get file data
|
||||
$size = $localDisk->size($chunkPath);
|
||||
$mimetype = $localDisk->mimeType($chunkPath);
|
||||
$name = Str::uuid() . '.' . $request->input('extension');
|
||||
|
||||
// Get upload limit
|
||||
$uploadLimit = get_settings('upload_limit');
|
||||
|
||||
// File size handling
|
||||
if ($uploadLimit && $size > format_bytes($uploadLimit)) {
|
||||
abort(413);
|
||||
}
|
||||
|
||||
// Check if user has enough space to upload file
|
||||
if (! $user->canUpload($size)) {
|
||||
// Delete file from chunk directory
|
||||
$localDisk->delete($chunkPath);
|
||||
|
||||
// Set up response
|
||||
$response = response([
|
||||
'type' => 'error',
|
||||
'message' => __t('user_action_not_allowed'),
|
||||
], 401);
|
||||
|
||||
// Abort code
|
||||
abort($response);
|
||||
}
|
||||
|
||||
// Move file to user directory
|
||||
$localDisk->move($chunkPath, "files/$user->id/$name");
|
||||
|
||||
// Create multiple image thumbnails
|
||||
($this->createImageThumbnail)($name, $user->id);
|
||||
|
||||
// Move file to external storage
|
||||
match (config('filesystems.default')) {
|
||||
's3' => ($this->moveFileToExternalStorage)($name, $user->id),
|
||||
'ftp', 'azure' => ($this->moveFileToFTPStorage)($name, $user->id),
|
||||
default => null
|
||||
};
|
||||
|
||||
// Create new file
|
||||
$file = File::create([
|
||||
'mimetype' => $request->input('extension'),
|
||||
'type' => getFileType($mimetype),
|
||||
'parent_id' => ($this->getFileParentId)($request, $user->id),
|
||||
'name' => $request->input('name'),
|
||||
'basename' => $name,
|
||||
'filesize' => $size,
|
||||
'user_id' => $user->id,
|
||||
'creator_id' => auth()->check() ? auth()->id() : $user->id,
|
||||
]);
|
||||
|
||||
// Store file exif data
|
||||
($this->storeExifMetadata)($file);
|
||||
|
||||
// Return new file
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
@@ -22,28 +22,33 @@ class ProcessImageThumbnailAction
|
||||
* Create image thumbnail from uploaded image
|
||||
*/
|
||||
public function __invoke(
|
||||
string $fileName,
|
||||
$file,
|
||||
string $userId
|
||||
string $name,
|
||||
string $userId,
|
||||
): void {
|
||||
// Create thumbnail from image
|
||||
if (in_array($file->getClientMimeType(), $this->availableFormats)) {
|
||||
// Make copy of file for the thumbnail generation
|
||||
Storage::disk('local')->copy("files/$userId/{$fileName}", "temp/$userId/{$fileName}");
|
||||
// Get local disk instance
|
||||
$disk = Storage::disk('local');
|
||||
|
||||
// Create thumbnails instantly
|
||||
($this->generateImageThumbnail)(
|
||||
fileName: $fileName,
|
||||
userId: $userId,
|
||||
execution: 'immediately'
|
||||
);
|
||||
if (! in_array($disk->mimeType("files/$userId/$name"), $this->availableFormats)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create thumbnails later
|
||||
($this->generateImageThumbnail)->onQueue('high')->execute(
|
||||
fileName: $fileName,
|
||||
// Make copy of file for the thumbnail generation
|
||||
$disk->copy("files/$userId/$name", "temp/$userId/$name");
|
||||
|
||||
// Create thumbnails instantly
|
||||
($this->generateImageThumbnail)(
|
||||
fileName: $name,
|
||||
userId: $userId,
|
||||
execution: 'immediately'
|
||||
);
|
||||
|
||||
// Create thumbnails later
|
||||
($this->generateImageThumbnail)
|
||||
->onQueue('high')
|
||||
->execute(
|
||||
fileName: $name,
|
||||
userId: $userId,
|
||||
execution: 'later'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace Domain\Files\Actions;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Domain\Files\Requests\UploadRequest;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
|
||||
class StoreFileChunksAction
|
||||
{
|
||||
/**
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public function __invoke(UploadRequest $request)
|
||||
{
|
||||
// Get uploaded file
|
||||
$file = $request->file('file');
|
||||
|
||||
// Get chunk name
|
||||
$name = $file->getClientOriginalName();
|
||||
|
||||
// Get chunk file path
|
||||
$path = Storage::disk('local')->path("chunks/$name");
|
||||
|
||||
// Build the file
|
||||
File::append($path, $file->get());
|
||||
|
||||
// If last chunk, then return file path
|
||||
if ($request->boolean('is_last')) {
|
||||
return "chunks/$name";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,22 @@
|
||||
<?php
|
||||
namespace Domain\Files\Actions;
|
||||
|
||||
use Domain\Files\Models\File;
|
||||
|
||||
class StoreFileExifMetadataAction
|
||||
{
|
||||
public function __invoke($item, $file)
|
||||
public function __invoke(File $file)
|
||||
{
|
||||
// Get exif metadata
|
||||
$exif_data = get_image_meta_data($file);
|
||||
$data = readExifData("files/$file->user_id/$file->basename");
|
||||
|
||||
if ($exif_data) {
|
||||
// Convert array to collection
|
||||
$data = json_decode(json_encode($exif_data));
|
||||
if (is_null($data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item->exif()->create([
|
||||
$file
|
||||
->exif()
|
||||
->create([
|
||||
'date_time_original' => $data->DateTimeOriginal ?? null,
|
||||
'artist' => $data->OwnerName ?? null,
|
||||
'width' => $data->COMPUTED->Width ?? null,
|
||||
@@ -33,6 +37,5 @@ class StoreFileExifMetadataAction
|
||||
'longitude_ref' => $data->GPSLongitudeRef ?? null,
|
||||
'latitude_ref' => $data->GPSLatitudeRef ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
namespace Domain\Files\Actions;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Domain\Folders\Models\Folder;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Domain\Files\Requests\UploadRequest;
|
||||
use Domain\Files\Models\File as UserFile;
|
||||
use Domain\Traffic\Actions\RecordUploadAction;
|
||||
use App\Users\Exceptions\InvalidUserActionException;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
|
||||
class UploadFileAction
|
||||
{
|
||||
public function __construct(
|
||||
public RecordUploadAction $recordUpload,
|
||||
public GetFileParentId $getFileParentId,
|
||||
public StoreFileExifMetadataAction $storeExifMetadata,
|
||||
public MoveFileToFTPStorageAction $moveFileToFTPStorage,
|
||||
public ProcessImageThumbnailAction $createImageThumbnail,
|
||||
public MoveFileToExternalStorageAction $moveFileToExternalStorage,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload new file
|
||||
*
|
||||
* @throws InvalidUserActionException|FileNotFoundException
|
||||
*/
|
||||
public function __invoke(
|
||||
UploadRequest $request,
|
||||
?string $userId = null,
|
||||
) {
|
||||
$file = $request->file('file');
|
||||
|
||||
$chunkName = $file->getClientOriginalName();
|
||||
|
||||
// File Path
|
||||
$filePath = Storage::disk('local')->path('chunks/' . $chunkName);
|
||||
|
||||
// Generate file
|
||||
File::append($filePath, $file->get());
|
||||
|
||||
// Size of file
|
||||
$fileSize = File::size($filePath);
|
||||
|
||||
// Size of limit
|
||||
$uploadLimit = get_settings('upload_limit');
|
||||
|
||||
// File size handling
|
||||
if ($uploadLimit && $fileSize > format_bytes($uploadLimit)) {
|
||||
abort(413);
|
||||
}
|
||||
|
||||
// If last then process file
|
||||
if ($request->boolean('is_last')) {
|
||||
$disk_local = Storage::disk('local');
|
||||
|
||||
// File name
|
||||
$fileName = Str::uuid() . '.' . $request->input('extension');
|
||||
|
||||
// Get user
|
||||
$user = $request->filled('parent_id')
|
||||
? Folder::find($request->input('parent_id'))->getLatestParent()->user
|
||||
: auth()->user();
|
||||
|
||||
// File Info
|
||||
$fileSize = $disk_local->size("chunks/$chunkName");
|
||||
$fileMimetype = $disk_local->mimeType("chunks/$chunkName");
|
||||
|
||||
// Check if user has enough space to upload file
|
||||
if (! $user->canUpload($fileSize)) {
|
||||
Storage::disk('local')->delete("chunks/$chunkName");
|
||||
|
||||
throw new InvalidUserActionException();
|
||||
}
|
||||
|
||||
// Move finished file from chunk to file-manager directory
|
||||
$disk_local->move("chunks/$chunkName", "files/$user->id/$fileName");
|
||||
|
||||
// Create multiple image thumbnails
|
||||
($this->createImageThumbnail)($fileName, $file, $user->id);
|
||||
|
||||
// Move files to external storage
|
||||
match (config('filesystems.default')) {
|
||||
's3' => ($this->moveFileToExternalStorage)($fileName, $user->id),
|
||||
'ftp', 'azure' => ($this->moveFileToFTPStorage)($fileName, $user->id),
|
||||
default => null
|
||||
};
|
||||
|
||||
// Create new file
|
||||
$item = UserFile::create([
|
||||
'mimetype' => $request->input('extension'),
|
||||
'type' => get_file_type($fileMimetype),
|
||||
'parent_id' => ($this->getFileParentId)($request, $user->id),
|
||||
'name' => $request->input('filename'),
|
||||
'basename' => $fileName,
|
||||
'filesize' => $fileSize,
|
||||
'user_id' => $user->id,
|
||||
'creator_id' => auth()->id(),
|
||||
]);
|
||||
|
||||
// Store exif metadata for files
|
||||
($this->storeExifMetadata)($item, $file);
|
||||
|
||||
// Return new file
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace Domain\Files\Controllers;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
use Domain\Sharing\Models\Share;
|
||||
use Domain\Folders\Models\Folder;
|
||||
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)($request->all(), $user);
|
||||
|
||||
return response('Files were successfully added to the upload queue', 201);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,28 @@
|
||||
<?php
|
||||
namespace Domain\Files\Controllers;
|
||||
|
||||
use Domain\Files\Models\File;
|
||||
use Domain\Folders\Models\Folder;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Files\Requests\UploadRequest;
|
||||
use Domain\Files\Resources\FileResource;
|
||||
use Domain\Files\Actions\UploadFileAction;
|
||||
use Domain\Files\Actions\ProcessFileAction;
|
||||
use Support\Demo\Actions\FakeUploadFileAction;
|
||||
use App\Users\Exceptions\InvalidUserActionException;
|
||||
use Domain\Files\Actions\StoreFileChunksAction;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
|
||||
class UploadFileController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
public UploadFileAction $uploadFiles,
|
||||
public ProcessFileAction $processFie,
|
||||
public FakeUploadFileAction $fakeUploadFile,
|
||||
public StoreFileChunksAction $storeFileChunks,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file for authenticated master|editor user
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public function __invoke(UploadRequest $request)
|
||||
{
|
||||
@@ -26,20 +30,22 @@ class UploadFileController extends Controller
|
||||
return ($this->fakeUploadFile)($request);
|
||||
}
|
||||
|
||||
try {
|
||||
// Upload and store file record
|
||||
if (! $request->boolean('is_last')) {
|
||||
return ($this->uploadFiles)($request);
|
||||
}
|
||||
// Store file chunks
|
||||
$chunkPath = ($this->storeFileChunks)($request);
|
||||
|
||||
$file = ($this->uploadFiles)($request);
|
||||
// Proceed after last chunk
|
||||
if ($request->boolean('is_last')) {
|
||||
// Get user
|
||||
$user = $request->filled('parent_id')
|
||||
? Folder::find($request->input('parent_id'))
|
||||
->getLatestParent()
|
||||
->user
|
||||
: auth()->user();
|
||||
|
||||
// Process file
|
||||
$file = ($this->processFie)($request, $user, $chunkPath);
|
||||
|
||||
return response(new FileResource($file), 201);
|
||||
} catch (InvalidUserActionException $e) {
|
||||
return response([
|
||||
'type' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace Domain\Files\Controllers;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
use Domain\Sharing\Models\Share;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Files\Requests\RemoteUploadRequest;
|
||||
use Domain\Sharing\Actions\ProtectShareRecordAction;
|
||||
use Domain\Sharing\Actions\VerifyAccessToItemAction;
|
||||
use Domain\Files\Actions\GetContentFromExternalSource;
|
||||
|
||||
class VisitorRemoteUploadFileController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
public ProtectShareRecordAction $protectShareRecord,
|
||||
public VerifyAccessToItemAction $verifyAccessToItem,
|
||||
public GetContentFromExternalSource $getContentFromExternalSource,
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(RemoteUploadRequest $request, ?Share $shared = null): Response|array
|
||||
{
|
||||
// Check ability to access protected share record
|
||||
($this->protectShareRecord)($shared);
|
||||
|
||||
// Check shared permission
|
||||
if (is_visitor($shared)) {
|
||||
abort(403, "You don't have access to this item");
|
||||
}
|
||||
|
||||
// Check access to requested directory
|
||||
($this->verifyAccessToItem)($request->input('parent_id'), $shared);
|
||||
|
||||
// Execute job for get content from url and save
|
||||
($this->getContentFromExternalSource)($request->all(), $shared->user);
|
||||
|
||||
return response('Files were successfully added to the upload queue', 201);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
<?php
|
||||
namespace Domain\Files\Controllers;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
use Domain\Sharing\Models\Share;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Files\Requests\UploadRequest;
|
||||
use Domain\Files\Resources\FileResource;
|
||||
use Domain\Files\Actions\UploadFileAction;
|
||||
use Domain\Files\Actions\ProcessFileAction;
|
||||
use Support\Demo\Actions\FakeUploadFileAction;
|
||||
use App\Users\Exceptions\InvalidUserActionException;
|
||||
use Domain\Files\Actions\StoreFileChunksAction;
|
||||
use Domain\Sharing\Actions\ProtectShareRecordAction;
|
||||
use Domain\Sharing\Actions\VerifyAccessToItemAction;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
@@ -19,7 +18,8 @@ use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
class VisitorUploadFileController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private UploadFileAction $uploadFile,
|
||||
public ProcessFileAction $processFie,
|
||||
public StoreFileChunksAction $storeFileChunks,
|
||||
private FakeUploadFileAction $fakeUploadFile,
|
||||
private ProtectShareRecordAction $protectShareRecord,
|
||||
private VerifyAccessToItemAction $verifyAccessToItem,
|
||||
@@ -32,7 +32,7 @@ class VisitorUploadFileController extends Controller
|
||||
public function __invoke(
|
||||
UploadRequest $request,
|
||||
Share $shared,
|
||||
): Response | array {
|
||||
) {
|
||||
if (is_demo_account()) {
|
||||
return ($this->fakeUploadFile)($request);
|
||||
}
|
||||
@@ -48,19 +48,18 @@ class VisitorUploadFileController extends Controller
|
||||
// Check access to requested directory
|
||||
($this->verifyAccessToItem)($request->input('parent_id'), $shared);
|
||||
|
||||
try {
|
||||
// Return new uploaded file
|
||||
$file = ($this->uploadFile)($request, $shared->user_id);
|
||||
// Store file chunks
|
||||
$chunkPath = ($this->storeFileChunks)($request);
|
||||
|
||||
// Proceed after last chunk
|
||||
if ($request->boolean('is_last')) {
|
||||
// Process file
|
||||
$file = ($this->processFie)($request, $shared->user, $chunkPath);
|
||||
|
||||
// Set public access url
|
||||
$file->setSharedPublicUrl($shared->token);
|
||||
|
||||
return response(new FileResource($file), 201);
|
||||
} catch (InvalidUserActionException $e) {
|
||||
return response([
|
||||
'type' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,9 @@ class UploadRequest extends FormRequest
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'filename' => 'required|string',
|
||||
'name' => 'required|string',
|
||||
'parent_id' => 'nullable|uuid',
|
||||
'path' => 'required|string',
|
||||
'path' => 'sometimes|string',
|
||||
'is_last' => 'sometimes|string',
|
||||
'extension' => 'sometimes|string|nullable',
|
||||
'file' => ['required', 'file', new DisabledMimetypes],
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Domain\Settings\Actions;
|
||||
|
||||
use ErrorException;
|
||||
use League\Flysystem\Ftp\UnableToAuthenticate;
|
||||
use League\Flysystem\UnableToWriteFile;
|
||||
use Storage;
|
||||
use ErrorException;
|
||||
use League\Flysystem\UnableToWriteFile;
|
||||
use League\Flysystem\Ftp\UnableToAuthenticate;
|
||||
|
||||
class TestFTPConnectionAction
|
||||
{
|
||||
@@ -40,4 +39,4 @@ class TestFTPConnectionAction
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
namespace Domain\Settings\Controllers;
|
||||
|
||||
use Artisan;
|
||||
use Domain\Settings\Actions\TestFTPConnectionAction;
|
||||
use Illuminate\Http\Response;
|
||||
use Domain\Settings\DTO\S3CredentialsData;
|
||||
use Domain\Settings\Actions\TestS3ConnectionAction;
|
||||
use Domain\Settings\Actions\TestFTPConnectionAction;
|
||||
use Domain\Settings\Requests\StoreStorageCredentialsRequest;
|
||||
|
||||
class StoreStorageCredentialsController
|
||||
@@ -13,7 +13,8 @@ class StoreStorageCredentialsController
|
||||
public function __construct(
|
||||
private TestFTPConnectionAction $testFTPConnection,
|
||||
private TestS3ConnectionAction $testS3Connection,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new email credentials to .env file
|
||||
@@ -27,11 +28,10 @@ class StoreStorageCredentialsController
|
||||
$driver = match ($request->input('storage.driver')) {
|
||||
's3', 'storj', 'spaces', 'wasabi', 'backblaze', 'oss', 'other' => 's3',
|
||||
'local' => 'local',
|
||||
'ftp' => 'ftp',
|
||||
'ftp' => 'ftp',
|
||||
};
|
||||
|
||||
if (! app()->runningUnitTests()) {
|
||||
|
||||
// Test driver connection
|
||||
match ($driver) {
|
||||
's3' => ($this->testS3Connection)(
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
namespace Domain\SetupWizard\Controllers;
|
||||
|
||||
use Artisan;
|
||||
use Domain\Settings\Actions\TestFTPConnectionAction;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Domain\Settings\DTO\S3CredentialsData;
|
||||
use Domain\Settings\Actions\TestS3ConnectionAction;
|
||||
use Domain\Settings\Actions\TestFTPConnectionAction;
|
||||
use Domain\Settings\Actions\TestSESConnectionAction;
|
||||
use Domain\Settings\Actions\TestSMTPConnectionAction;
|
||||
use Domain\Settings\Actions\TestMailgunConnectionAction;
|
||||
@@ -22,7 +22,8 @@ class StoreEnvironmentSettingsController extends Controller
|
||||
private TestSMTPConnectionAction $testSMTPConnection,
|
||||
private TestMailgunConnectionAction $testMailgunConnection,
|
||||
private TestPostmarkConnectionAction $testPostmarkConnection,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Store environment setup
|
||||
@@ -35,7 +36,7 @@ class StoreEnvironmentSettingsController extends Controller
|
||||
$StorageDriver = match ($request->input('storage.driver')) {
|
||||
's3', 'storj', 'spaces', 'wasabi', 'backblaze', 'oss', 'other' => 's3',
|
||||
'local' => 'local',
|
||||
'ftp' => 'ftp',
|
||||
'ftp' => 'ftp',
|
||||
};
|
||||
|
||||
// Test driver connection
|
||||
|
||||
@@ -4,15 +4,16 @@ namespace Domain\UploadRequest\Controllers;
|
||||
use DB;
|
||||
use Domain\Folders\Models\Folder;
|
||||
use Domain\Files\Resources\FileResource;
|
||||
use Domain\Files\Actions\UploadFileAction;
|
||||
use Domain\Files\Actions\ProcessFileAction;
|
||||
use Domain\UploadRequest\Models\UploadRequest;
|
||||
use App\Users\Exceptions\InvalidUserActionException;
|
||||
use Domain\Files\Actions\StoreFileChunksAction;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
|
||||
class UploadFilesForUploadRequestController
|
||||
{
|
||||
public function __construct(
|
||||
private UploadFileAction $uploadFile,
|
||||
private ProcessFileAction $processFie,
|
||||
private StoreFileChunksAction $storeFileChunks,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -29,14 +30,18 @@ class UploadFilesForUploadRequestController
|
||||
$this->createFolder($uploadRequest);
|
||||
}
|
||||
|
||||
try {
|
||||
// Set default parent_id for uploaded file
|
||||
if (is_null($request->input('parent_id'))) {
|
||||
$request->merge(['parent_id' => $uploadRequest->id]);
|
||||
}
|
||||
// Set default parent_id for uploaded file
|
||||
if (is_null($request->input('parent_id'))) {
|
||||
$request->merge(['parent_id' => $uploadRequest->id]);
|
||||
}
|
||||
|
||||
// Upload file
|
||||
$file = ($this->uploadFile)($request, $uploadRequest->user_id);
|
||||
// Store file chunks
|
||||
$chunkPath = ($this->storeFileChunks)($request);
|
||||
|
||||
// Proceed after last chunk
|
||||
if ($request->boolean('is_last')) {
|
||||
// Process file
|
||||
$file = ($this->processFie)($request, $uploadRequest->user, $chunkPath);
|
||||
|
||||
// Set public access url
|
||||
$file->setUploadRequestPublicUrl($uploadRequest->id);
|
||||
@@ -44,13 +49,7 @@ class UploadFilesForUploadRequestController
|
||||
// Set timestamp for auto filling
|
||||
cache()->set("auto-filling.$uploadRequest->id", now()->toString());
|
||||
|
||||
// Return new uploaded file
|
||||
return response(new FileResource($file), 201);
|
||||
} catch (InvalidUserActionException $e) {
|
||||
return response([
|
||||
'type' => 'error',
|
||||
'message' => $e->getMessage(),
|
||||
], 401);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
namespace Domain\UploadRequest\Controllers;
|
||||
|
||||
use DB;
|
||||
use Domain\Folders\Models\Folder;
|
||||
use Domain\Files\Requests\RemoteUploadRequest;
|
||||
use Domain\UploadRequest\Models\UploadRequest;
|
||||
use Domain\Files\Actions\GetContentFromExternalSource;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
|
||||
class UploadFilesRemotelyForUploadRequestController
|
||||
{
|
||||
public function __construct(
|
||||
private GetContentFromExternalSource $getContentFromExternalSource,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public function __invoke(RemoteUploadRequest $request, UploadRequest $uploadRequest)
|
||||
{
|
||||
// Get upload request root folder query
|
||||
$folder = Folder::where('id', $uploadRequest->id);
|
||||
|
||||
// Create folder if not exist
|
||||
if ($folder->doesntExist()) {
|
||||
$this->createFolder($uploadRequest);
|
||||
}
|
||||
|
||||
// Set default parent_id for uploaded file
|
||||
if (is_null($request->input('parent_id'))) {
|
||||
$request->merge(['parent_id' => $uploadRequest->id]);
|
||||
}
|
||||
|
||||
// Execute job for get content from url and save
|
||||
($this->getContentFromExternalSource)($request->all(), $uploadRequest->user);
|
||||
|
||||
// Set timestamp for auto filling
|
||||
cache()->set("auto-filling.$uploadRequest->id", now()->toString());
|
||||
|
||||
return response('Files were successfully added to the upload queue', 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create root Upload Request folder
|
||||
*/
|
||||
private function createFolder(UploadRequest $uploadRequest): void
|
||||
{
|
||||
// Format timestamp
|
||||
$timestamp = format_date($uploadRequest->created_at, 'd. M. Y');
|
||||
|
||||
// Create folder
|
||||
DB::table('folders')->insert([
|
||||
'id' => $uploadRequest->id,
|
||||
'parent_id' => $uploadRequest->folder_id ?? null,
|
||||
'user_id' => $uploadRequest->user_id,
|
||||
'name' => $uploadRequest->name ?? __t('upload_request_default_folder', ['timestamp' => $timestamp]),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
// Update upload request status
|
||||
$uploadRequest->update([
|
||||
'status' => 'filling',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ class FakeUploadFileAction
|
||||
return [
|
||||
'data' => [
|
||||
'id' => Str::uuid(),
|
||||
'type' => get_file_type($file->getMimeType()),
|
||||
'type' => getFileType($file->getMimeType()),
|
||||
'attributes' => [
|
||||
'filesize' => Metric::bytes($file->getSize())->format(),
|
||||
'name' => $request->input('filename'),
|
||||
|
||||
+14
-14
@@ -1,17 +1,17 @@
|
||||
<?php
|
||||
|
||||
function accessDeniedError(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'error',
|
||||
'message' => 'Access Denied',
|
||||
];
|
||||
}
|
||||
function accessDeniedError(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'error',
|
||||
'message' => 'Access Denied',
|
||||
];
|
||||
}
|
||||
|
||||
function userActionNotAllowedError(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'error',
|
||||
'message' => 'This user action is not allowed.',
|
||||
];
|
||||
}
|
||||
function userActionNotAllowedError(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'error',
|
||||
'message' => 'This user action is not allowed.',
|
||||
];
|
||||
}
|
||||
|
||||
+58
-14
@@ -210,7 +210,6 @@ if (! function_exists('setEnvironmentValue')) {
|
||||
|
||||
if (count($values) > 0) {
|
||||
foreach ($values as $envKey => $envValue) {
|
||||
|
||||
$str .= "\n"; // In case the searched variable is in the last line without \n
|
||||
$keyPosition = strpos($str, "{$envKey}=");
|
||||
|
||||
@@ -640,7 +639,7 @@ if (! function_exists('get_file_type')) {
|
||||
/**
|
||||
* Get file type from mimetype
|
||||
*/
|
||||
function get_file_type(string $fileMimetype): string
|
||||
function getFileType(string $fileMimetype): string
|
||||
{
|
||||
// Get mimetype from file
|
||||
$mimetype = explode('/', $fileMimetype);
|
||||
@@ -747,22 +746,32 @@ if (! function_exists('getPrettyName')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('get_image_meta_data')) {
|
||||
if (! function_exists('readExifData')) {
|
||||
/**
|
||||
* Get exif data from jpeg image
|
||||
*
|
||||
* @param $file
|
||||
* @return array|null
|
||||
*/
|
||||
function get_image_meta_data($file)
|
||||
function readExifData(string $file): object|null
|
||||
{
|
||||
if (get_file_type_from_mimetype($file->getMimeType()) === 'jpeg') {
|
||||
try {
|
||||
// Try to get the exif data
|
||||
return mb_convert_encoding(Image::make($file->getRealPath())->exif(), 'UTF8', 'UTF8');
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
$disk = Storage::disk('local');
|
||||
|
||||
$type = get_file_type_from_mimetype(
|
||||
$disk->mimeType($file)
|
||||
);
|
||||
|
||||
if ($type !== 'jpeg') {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to get the exif data
|
||||
$data = Image::make($disk->path($file))->exif();
|
||||
|
||||
// Encode data
|
||||
$encodedData = mb_convert_encoding($data, 'UTF8', 'UTF8');
|
||||
|
||||
return json_decode(json_encode($encodedData));
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1148,4 +1157,39 @@ 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
|
||||
{
|
||||
$extension = null;
|
||||
|
||||
if (array_key_exists('extension', pathinfo($url))) {
|
||||
// Break attributes
|
||||
$string = str_replace(['&'], '?', pathinfo($url)['extension']);
|
||||
|
||||
// Get extension from url path
|
||||
$extension = explode('?', $string)[0];
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user