Merge remote-tracking branch 'origin/master' into folders_upload

This commit is contained in:
Milos Holba
2021-08-11 17:46:57 +02:00
330 changed files with 3749 additions and 3423 deletions
@@ -1,18 +0,0 @@
<?php
namespace Domain\Browsing\Controllers;
use Domain\Files\Models\File;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
class BrowseParticipantsUploadsController
{
public function __invoke(): Collection
{
return File::with(['parent'])
->where('user_id', Auth::id())
->whereAuthor('visitor')
->sortable()
->get();
}
}
@@ -29,6 +29,7 @@ class SearchFilesAndFoldersController
// Collect folders and files to single array
return collect([$searched_folders, $searched_files])
->collapse();
->collapse()
->take(10);
}
}
@@ -65,6 +65,7 @@ class VisitorSearchFilesAndFoldersController extends Controller
// Collect folders and files to single array
return collect([$folders, $files])
->collapse();
->collapse()
->take(10);
}
}
@@ -27,7 +27,7 @@ class UploadFileAction
public function __invoke(
UploadRequest $request,
?Share $shared = null,
): UserFile {
) {
// Get parent_id from request
$file = $request->file('file');
@@ -20,7 +20,7 @@ class UploadFileController extends Controller
*/
public function __invoke(
UploadRequest $request,
): File | array {
) {
if (is_demo_account('howdy@hi5ve.digital')) {
return ($this->fakeUploadFile)($request);
}
@@ -20,49 +20,21 @@ class StoreEnvironmentSettingsController extends Controller
'FILESYSTEM_DRIVER' => 'local',
],
's3' => [
'FILESYSTEM_DRIVER' => $request->input('storage.driver') ?? null,
'AWS_ACCESS_KEY_ID' => $request->input('storage.key') ?? null,
'AWS_SECRET_ACCESS_KEY' => $request->input('storage.secret') ?? null,
'AWS_DEFAULT_REGION' => $request->input('storage.region') ?? null,
'AWS_BUCKET' => $request->input('storage.bucket') ?? null,
],
'spaces' => [
'FILESYSTEM_DRIVER' => $request->input('storage.driver') ?? null,
'DO_SPACES_KEY' => $request->input('storage.key') ?? null,
'DO_SPACES_SECRET' => $request->input('storage.secret') ?? null,
'DO_SPACES_ENDPOINT' => $request->input('storage.endpoint') ?? null,
'DO_SPACES_REGION' => $request->input('storage.region') ?? null,
'DO_SPACES_BUCKET' => $request->input('storage.bucket') ?? null,
],
'wasabi' => [
'FILESYSTEM_DRIVER' => $request->input('storage.driver') ?? null,
'WASABI_KEY' => $request->input('storage.key') ?? null,
'WASABI_SECRET' => $request->input('storage.secret') ?? null,
'WASABI_ENDPOINT' => $request->input('storage.endpoint') ?? null,
'WASABI_REGION' => $request->input('storage.region') ?? null,
'WASABI_BUCKET' => $request->input('storage.bucket') ?? null,
],
'backblaze' => [
'FILESYSTEM_DRIVER' => $request->input('storage.driver') ?? null,
'BACKBLAZE_KEY' => $request->input('storage.key') ?? null,
'BACKBLAZE_SECRET' => $request->input('storage.secret') ?? null,
'BACKBLAZE_ENDPOINT' => $request->input('storage.endpoint') ?? null,
'BACKBLAZE_REGION' => $request->input('storage.region') ?? null,
'BACKBLAZE_BUCKET' => $request->input('storage.bucket') ?? null,
],
'oss' => [
'FILESYSTEM_DRIVER' => $request->input('storage.driver') ?? null,
'OSS_ACCESS_KEY_ID' => $request->input('storage.key') ?? null,
'OSS_SECRET_ACCESS_KEY' => $request->input('storage.secret') ?? null,
'OSS_ENDPOINT' => $request->input('storage.endpoint') ?? null,
'OSS_REGION' => $request->input('storage.region') ?? null,
'OSS_BUCKET' => $request->input('storage.bucket') ?? null,
'FILESYSTEM_DRIVER' => 's3',
'S3_ACCESS_KEY_ID' => $request->input('storage.key') ?? null,
'S3_SECRET_ACCESS_KEY' => $request->input('storage.secret') ?? null,
'S3_DEFAULT_REGION' => $request->input('storage.region') ?? null,
'S3_BUCKET' => $request->input('storage.bucket') ?? null,
'S3_URL' => $request->input('storage.endpoint') ?? null,
],
];
// Get storage driver from request
$driver = 'local' === $request->input('storage.driver') ? 'local' : 's3';
// Storage credentials for storage
setEnvironmentValue(
$drivers[$request->input('storage.driver')]
$drivers[$driver]
);
// Store credentials for mail
@@ -5,14 +5,14 @@ use Domain\Sharing\Models\Share;
class ProtectShareRecordAction
{
private string $message = "Sorry, you don't have permission";
public function __invoke(
Share $shared
): void {
if ($shared->is_protected) {
$abort_message = "Sorry, you don't have permission";
if (! request()->hasCookie('share_session')) {
abort(403, $abort_message);
abort(403, $this->message);
}
// Get shared session
@@ -22,12 +22,12 @@ class ProtectShareRecordAction
// Check if is requested same share record
if ($share_session->token !== $shared->token) {
abort(403, $abort_message);
abort(403, $this->message);
}
// Check if share record was authenticated previously via ShareController@authenticate
if (! $share_session->authenticated) {
abort(403, $abort_message);
abort(403, $this->message);
}
}
}
@@ -1,7 +1,6 @@
<?php
namespace Domain\Sharing\Controllers;
use Domain\Zip\Models\Zip;
use Illuminate\Http\Response;
use Domain\Sharing\Models\Share;
use App\Http\Controllers\Controller;
@@ -83,15 +82,6 @@ class ShareController extends Controller
->where('user_id', Auth::id())
->firstOrFail()
->delete();
// Get zip record if exist
$zip = Zip::where('shared_token', $token)
->where('user_id', Auth::id())
->first();
if ($zip) {
$zip->delete();
}
}
return response('Done!', 204);
@@ -46,6 +46,7 @@ class SharePublicIndexController extends Controller
}
return view('index')
->with('status_check', [])
->with('installation', 'setup-done')
->with('settings', get_settings_in_json() ?? null);
}
@@ -0,0 +1,42 @@
<?php
namespace Domain\Zip\Actions;
use Domain\Files\Models\File;
use Domain\Folders\Models\Folder;
class GetItemsListFromUrlParamAction
{
public function __invoke(
string $user_id
): array {
$list = explode(',', request()->get('items'));
$itemList = collect($list)
->map(function ($chunk) {
$items = explode('|', $chunk);
return [
'id' => $items[0],
'type' => $items[1],
];
});
$folderIds = $itemList
->where('type', 'folder')
->pluck('id');
$fileIds = $itemList
->where('type', 'file')
->pluck('id');
$folders = Folder::whereUserId($user_id)
->whereIn('id', $folderIds)
->get();
$files = File::whereUserId($user_id)
->whereIn('id', $fileIds)
->get();
return [$folders, $files];
}
}
+88
View File
@@ -0,0 +1,88 @@
<?php
namespace Domain\Zip\Actions;
use ZipStream\ZipStream;
use Illuminate\Support\Str;
use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use STS\ZipStream\ZipStreamFacade as Zip;
class ZipAction
{
public function __invoke(
Collection $folders,
Collection $files,
?Share $shared = null
): ZipStream {
// Get user id
$user_id = Auth::id() ?? $shared->user_id;
// Get zip name from single requested folder
if ($files->isEmpty() && $folders->count() === 1) {
$zipName = Str::slug($folders->first()->name) . '.zip';
}
// Create zip
$zip = Zip::create($zipName ?? 'files.zip');
// Zip Files
$files->map(function ($file) use ($zip) {
// get file path
$filePath = "files/$file->user_id/$file->basename";
// Add file into zip
if (Storage::exists($filePath)) {
// local disk
if (is_storage_driver('local')) {
$zip->add(Storage::path($filePath), $file->name);
}
// s3 client
if (is_storage_driver('s3')) {
$bucketName = config('filesystems.disks.s3.bucket');
$zip->add("s3://$bucketName/$filePath", $file->name);
}
}
});
// Zip Folders
$folders->map(function ($folder) use ($zip, $user_id) {
// Get folder
$requested_folder = Folder::with(['folders.files', 'files'])
->where('id', $folder->id)
->where('user_id', $user_id)
->with('folders')
->first();
$folderFiles = get_files_for_zip($requested_folder, collect([]));
foreach ($folderFiles as $file) {
// get file path
$filePath = "files/$user_id/{$file['basename']}";
// Add file into zip
if (Storage::exists($filePath)) {
$zipDestination = "{$file['folder_path']}/{$file['name']}";
// local disk
if (is_storage_driver('local')) {
$zip->add(Storage::path($filePath), $zipDestination);
}
// s3 client
if (is_storage_driver('s3')) {
$bucketName = config('filesystems.disks.s3.bucket');
$zip->add("s3://$bucketName/$filePath", $zipDestination);
}
}
}
});
return $zip;
}
}
-70
View File
@@ -1,70 +0,0 @@
<?php
namespace Domain\Zip\Actions;
use Domain\Zip\Models\Zip;
use Illuminate\Support\Str;
use Domain\Sharing\Models\Share;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\FileNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
class ZipFilesAction
{
/**
* Zip selected files, store it in /zip folder and retrieve zip record
*/
public function __invoke(
File | Collection $files,
?Share $shared = null,
): Zip {
// Local storage instance
$disk_local = Storage::disk('local');
// Move file to local storage from external storage service
if (! is_storage_driver('local')) {
$files->each(function ($file) use ($disk_local) {
try {
$disk_local->put("temp/$file->basename", Storage::get("files/$file->user_id/$file->basename"));
} catch (FileNotFoundException $e) {
throw new HttpException(404, 'File not found');
}
});
}
// Get zip path
$zip_name = Str::random() . '.zip';
// Create zip
$zipper = new \Madnest\Madzipper\Madzipper;
$zip = $zipper->make($disk_local->path("zip/$zip_name"));
// Add files to zip
$files->each(function ($file) use ($zip, $disk_local) {
$file_path = is_storage_driver('local')
? $disk_local->path("files/$file->user_id/$file->basename")
: $disk_local->path("temp/$file->basename");
$zip->addString("$file->name.$file->mimetype", File::get($file_path));
});
// Close zip
//$zip->close();
// Delete temporary files
if (! is_storage_driver('local')) {
$files->each(function ($file) use ($disk_local) {
$disk_local->delete("temp/$file->basename");
});
}
// Store zip record
return Zip::create([
'user_id' => $shared->user_id ?? Auth::id(),
'shared_token' => $shared->token ?? null,
'basename' => $zip_name,
]);
}
}
@@ -1,81 +0,0 @@
<?php
namespace Domain\Zip\Actions;
use Domain\Zip\Models\Zip;
use Illuminate\Support\Str;
use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\FileNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
class ZipFolderAction
{
/**
* Zip requested folder
*/
public function __invoke(
$id,
?Share $shared = null
): Zip {
// Get folder
$requested_folder = Folder::with(['folders.files', 'files'])
->where('id', $id)
->where('user_id', Auth::id() ?? $shared->user_id)
->with('folders')
->first();
$files = get_files_for_zip($requested_folder, collect([]));
// Local storage instance
$disk_local = Storage::disk('local');
// Move file to local storage from external storage service
if (! is_storage_driver('local')) {
foreach ($files as $file) {
try {
$disk_local->put("temp/{$file['basename']}", Storage::get("files/$requested_folder->user_id/{$file['basename']}"));
} catch (FileNotFoundException $e) {
throw new HttpException(404, 'File not found');
}
}
}
// Get zip path
$zip_name = Str::random(16) . '-' . Str::slug($requested_folder->name) . '.zip';
// Create zip
$zipper = new \Madnest\Madzipper\Madzipper;
$zip = $zipper->make($disk_local->path("zip/$zip_name"));
// Add files to zip
foreach ($files as $file) {
$file_path = is_storage_driver('local')
? $disk_local->path("files/$requested_folder->user_id/{$file['basename']}")
: $disk_local->path("temp/{$file['basename']}");
$zip
->folder($file['folder_path'])
->addString("{$file['name']}.{$file['mimetype']}", File::get($file_path));
}
// Close zip
//$zip->close();
// Delete temporary files
if (! is_storage_driver('local')) {
foreach ($files as $file) {
$disk_local->delete('temp/' . $file['basename']);
}
}
// Store zip record
return Zip::create([
'user_id' => $shared->user_id ?? Auth::id(),
'shared_token' => $shared->token ?? null,
'basename' => $zip_name,
]);
}
}
@@ -1,44 +0,0 @@
<?php
namespace Domain\Zip\Controllers;
use Domain\Zip\Models\Zip;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Domain\Traffic\Actions\RecordDownloadAction;
use Symfony\Component\HttpFoundation\StreamedResponse;
class GetZipController extends Controller
{
public function __construct(
private RecordDownloadAction $recordDownload,
) {
}
/**
* Get generated zip for user
*/
public function __invoke(
string $id,
): StreamedResponse {
$disk = Storage::disk('local');
$zip = Zip::whereId($id)
->where('user_id', Auth::id())
->firstOrFail();
// Store user download size
($this->recordDownload)(
file_size: $disk->size("zip/$zip->basename"),
user_id: $zip->user_id,
);
return $disk->download("zip/$zip->basename", $zip->basename, [
'Content-Type' => 'application/zip',
'Content-Length' => $disk->size("zip/$zip->basename"),
'Accept-Ranges' => 'bytes',
'Content-Range' => 'bytes 0-600/' . $disk->size("zip/$zip->basename"),
'Content-Disposition' => "attachment; filename=$zip->basename",
]);
}
}
@@ -1,44 +0,0 @@
<?php
namespace Domain\Zip\Controllers;
use Domain\Zip\Models\Zip;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Storage;
use Domain\Traffic\Actions\RecordDownloadAction;
use Symfony\Component\HttpFoundation\StreamedResponse;
class VisitorGetZipController extends Controller
{
public function __construct(
private RecordDownloadAction $recordDownload,
) {
}
/**
* Get generated zip for visitor
*/
public function __invoke(
$id,
$token,
): StreamedResponse {
$disk = Storage::disk('local');
$zip = Zip::where('id', $id)
->where('shared_token', $token)
->first();
// Store user download size
($this->recordDownload)(
file_size: $disk->size("zip/$zip->basename"),
user_id: $zip->user_id,
);
return $disk->download("zip/$zip->basename", $zip->basename, [
'Content-Type' => 'application/zip',
'Content-Length' => $disk->size("zip/$zip->basename"),
'Accept-Ranges' => 'bytes',
'Content-Range' => 'bytes 0-600/' . $disk->size("zip/$zip->basename"),
'Content-Disposition' => 'attachment; filename=' . $zip->basename,
]);
}
}
@@ -0,0 +1,64 @@
<?php
namespace Domain\Zip\Controllers;
use ZipStream\ZipStream;
use Illuminate\Http\Request;
use Domain\Files\Models\File;
use Domain\Sharing\Models\Share;
use Domain\Zip\Actions\ZipAction;
use App\Http\Controllers\Controller;
use Domain\Traffic\Actions\RecordDownloadAction;
use Domain\Sharing\Actions\ProtectShareRecordAction;
use Domain\Sharing\Actions\VerifyAccessToItemAction;
use Domain\Zip\Actions\GetItemsListFromUrlParamAction;
class VisitorZipController extends Controller
{
public function __construct(
public GetItemsListFromUrlParamAction $getItemsListFromUrlParam,
public ProtectShareRecordAction $protectShareRecord,
public VerifyAccessToItemAction $verifyAccessToItem,
public RecordDownloadAction $recordDownload,
public ZipAction $zip,
) {
}
public function __invoke(
Request $request,
Share $shared,
): ZipStream {
// Check ability to access protected share record
($this->protectShareRecord)($shared);
list($folders, $files) = ($this->getItemsListFromUrlParam)($shared->user_id);
// Check access to requested folders
if ($folders->isNotEmpty()) {
$folders->each(
fn ($folder) => ($this->verifyAccessToItem)($folder->id, $shared)
);
}
// Check access to requested files
if ($files->isNotEmpty()) {
$file_parent_folders = File::whereUserId($shared->user_id)
->whereIn('id', $files->pluck('id'))
->get()
->pluck('folder_id')
->toArray();
// Check access to requested directory
($this->verifyAccessToItem)($file_parent_folders, $shared);
}
// Zip items
$zip = ($this->zip)($folders, $files, $shared);
($this->recordDownload)(
file_size: $zip->predictZipSize(),
user_id: $shared->user_id,
);
return $zip;
}
}
@@ -1,55 +0,0 @@
<?php
namespace Domain\Zip\Controllers;
use Illuminate\Http\Request;
use Domain\Files\Models\File;
use Illuminate\Http\Response;
use Domain\Sharing\Models\Share;
use App\Http\Controllers\Controller;
use Domain\Zip\Actions\ZipFilesAction;
use Domain\Sharing\Actions\ProtectShareRecordAction;
use Domain\Sharing\Actions\VerifyAccessToItemAction;
/**
* Guest download multiple files via zip
*/
class VisitorZipFilesController extends Controller
{
public function __construct(
private ProtectShareRecordAction $protectShareRecord,
private VerifyAccessToItemAction $verifyAccessToItem,
private ZipFilesAction $zipFiles,
) {
}
public function __invoke(
Request $request,
Share $shared,
): Response {
// Check ability to access protected share record
($this->protectShareRecord)($shared);
$file_parent_folders = File::whereUserId($shared->user_id)
->whereIn('id', $request->items)
->get()
->pluck('folder_id')
->toArray();
// Check access to requested directory
($this->verifyAccessToItem)($file_parent_folders, $shared);
// Get requested files
$files = File::whereUserId($shared->user_id)
->whereIn('id', $request->items)
->get();
// Create zip
$zip = ($this->zipFiles)($files, $shared);
// Get file
return response([
'url' => url("/zip/{$zip->id}/public/{$shared->token}"),
'name' => $zip->basename,
], 201);
}
}
@@ -1,51 +0,0 @@
<?php
namespace Domain\Zip\Controllers;
use Illuminate\Http\Response;
use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder;
use App\Http\Controllers\Controller;
use Domain\Zip\Actions\ZipFolderAction;
use Domain\Sharing\Actions\ProtectShareRecordAction;
use Domain\Sharing\Actions\VerifyAccessToItemAction;
/**
* Guest download folder via zip
*/
class VisitorZipFolderController extends Controller
{
public function __construct(
private ProtectShareRecordAction $protectShareRecord,
private VerifyAccessToItemAction $verifyAccessToItem,
private ZipFolderAction $zipFolder,
) {
}
public function __invoke(
string $id,
Share $shared,
): Response {
// Check ability to access protected share record
($this->protectShareRecord)($shared);
// Check access to requested folder
($this->verifyAccessToItem)($id, $shared);
// Get folder
$folder = Folder::whereUserId($shared->user_id)
->where('id', $id);
if (! $folder->exists()) {
abort(404, 'Requested folder doesn\'t exists.');
}
// Create zip
$zip = ($this->zipFolder)($id, $shared);
// Get file
return response([
'url' => url("/zip/{$zip->id}/public/{$shared->token}"),
'name' => $zip->basename,
], 201);
}
}
@@ -0,0 +1,39 @@
<?php
namespace Domain\Zip\Controllers;
use Illuminate\Http\Request;
use STS\ZipStream\ZipStream;
use Domain\Zip\Actions\ZipAction;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Domain\Traffic\Actions\RecordDownloadAction;
use Domain\Zip\Actions\GetItemsListFromUrlParamAction;
class ZipController extends Controller
{
public function __construct(
public ZipAction $zip,
public RecordDownloadAction $recordDownload,
public GetItemsListFromUrlParamAction $getItemsListFromUrlParam,
) {
}
public function __invoke(
Request $request,
): ZipStream {
$user_id = Auth::id();
// Get list of folders and files from requested url parameter
list($folders, $files) = ($this->getItemsListFromUrlParam)($user_id);
// Zip items
$zip = ($this->zip)($folders, $files);
($this->recordDownload)(
file_size: $zip->predictZipSize(),
user_id: $user_id,
);
return $zip;
}
}
@@ -1,32 +0,0 @@
<?php
namespace Domain\Zip\Controllers;
use Illuminate\Http\Request;
use Domain\Files\Models\File;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Domain\Zip\Actions\ZipFilesAction;
class ZipFilesController extends Controller
{
public function __construct(
private ZipFilesAction $zipFiles,
) {
}
public function __invoke(
Request $request,
): Response {
$files = File::whereUserId(Auth::id())
->whereIn('id', $request->input('items'))
->get();
$zip = ($this->zipFiles)($files);
return response([
'url' => route('zip', $zip->id),
'name' => $zip->basename,
], 201);
}
}
@@ -1,34 +0,0 @@
<?php
namespace Domain\Zip\Controllers;
use Illuminate\Http\Response;
use Domain\Folders\Models\Folder;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Domain\Zip\Actions\ZipFolderAction;
class ZipFolderController extends Controller
{
public function __construct(
private ZipFolderAction $zipFolder,
) {
}
public function __invoke(
string $id,
): Response {
$folder = Folder::whereUserId(Auth::id())
->where('id', $id);
if (! $folder->exists()) {
abort(404, "Requested folder doesn't exists.");
}
$zip = ($this->zipFolder)($id);
return response([
'url' => route('zip', $zip->id),
'name' => $zip->basename,
], 201);
}
}
-48
View File
@@ -1,48 +0,0 @@
<?php
namespace Domain\Zip\Models;
use App\Users\Models\User;
use Illuminate\Support\Str;
use Database\Factories\ZipFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Factories\HasFactory;
/**
* @property string basename
* @property string shared_token
* @property string id
* @property string user_id
* @property string created_at
* @property string updated_at
* @method static where(string $string, string $string1, string $toDateTimeString)
*/
class Zip extends Model
{
use HasFactory;
protected $guarded = ['id'];
public $incrementing = false;
protected $keyType = 'string';
protected static function newFactory(): ZipFactory
{
return ZipFactory::new();
}
public function user(): HasOne
{
return $this->hasOne(User::class, 'id', 'user_id');
}
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->id = (string) Str::uuid();
});
}
}