921 lines
33 KiB
PHP
921 lines
33 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
use App\Http\Requests\NewFolder;
|
|
use App\Http\Requests\UploadFiles;
|
|
use App\Http\Requests\SelectedFiles;
|
|
use App\Http\Requests\RecycledFiles;
|
|
use App\Http\Requests\ShareFiles;
|
|
use App\Http\Requests\SharedFiles;
|
|
|
|
use App\Http\Resources\FileResource;
|
|
|
|
use App\Jobs\UploadToS3;
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Illuminate\Support\Str;
|
|
|
|
use Inertia\Inertia;
|
|
|
|
use App\Models\File;
|
|
use App\Models\User;
|
|
use App\Models\FileShare;
|
|
|
|
use Carbon\Carbon;
|
|
|
|
use Kalnoy\Nestedset\Collection;
|
|
|
|
use ZipArchive;
|
|
|
|
use App\Mail\ShareFilesNotification;
|
|
|
|
class FileController extends Controller
|
|
{
|
|
// render user's files
|
|
public function userFiles(Request $request, string $folder = null) {
|
|
// validate passed in $folder param
|
|
// if passed in,
|
|
if ($folder) {
|
|
$folder = File::query()
|
|
->where('created_by', Auth::id()) // ensure matching user for access
|
|
->where('path', $folder) // ensure that the specified folder exists in the database
|
|
->firstOrFail(); // if none found, fail
|
|
}
|
|
else {
|
|
// use root folder if $folder not passed in
|
|
$folder = $this->getRoot();
|
|
}
|
|
|
|
// get all files and folders created by current user
|
|
$files = File::query()->where('created_by', Auth::id())
|
|
// that have not been deleted
|
|
->whereNull('deleted_at')
|
|
// order by folders first
|
|
->orderByDesc('is_folder')
|
|
// then order by creation date
|
|
->orderByDesc('created_at');
|
|
|
|
$search = $request->get('search');
|
|
|
|
if ($search) {
|
|
$files->where('name', 'like', $search);
|
|
} else { // return all files filtered by parent_id
|
|
$files->where('parent_id', $folder->id);
|
|
}
|
|
|
|
$files = $files->get();
|
|
|
|
$files = FileResource::collection($files);
|
|
|
|
$ancestors = FileResource::collection([...$folder->ancestors, $folder]);
|
|
|
|
$folder = new FileResource($folder);
|
|
|
|
return Inertia::render('UserFiles', compact('files', 'folder', 'ancestors'));
|
|
}
|
|
|
|
// render files shared with user
|
|
public function sharedWithMe(Request $request, $folder = null) {
|
|
// validate passed in $folder param
|
|
if ($folder) {
|
|
// get ancestors
|
|
$firstQuery = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
->where('file_shares.user_id', Auth::id())
|
|
->whereNull('files.deleted_at')
|
|
->find(intval($folder)); // ensure that the specified id exists in the database
|
|
if ($firstQuery) {
|
|
$ancestors = $firstQuery->ancestors;
|
|
}
|
|
|
|
// folder found in the shares db
|
|
$folder = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
->where('file_shares.user_id', Auth::id())
|
|
->whereNull('files.deleted_at')
|
|
->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'parent_id')
|
|
->find(intval($folder)); // ensure that the specified id exists in the database
|
|
}
|
|
// if still exists,
|
|
if ($folder) {
|
|
// files are those found in the shares db
|
|
$files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
// that are shared with the current user
|
|
->where('file_shares.user_id', Auth::id())
|
|
// that have not been deleted
|
|
->whereNull('files.deleted_at')
|
|
// order by folders first
|
|
->orderByDesc('files.is_folder')
|
|
// then order by creation date
|
|
->orderByDesc('files.id')
|
|
// then select to reference file_id
|
|
->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'mimetype', 'is_folder', 'parent_id');
|
|
|
|
$search = $request->get('search');
|
|
|
|
if ($search) {
|
|
$files->where('name', 'like', $search);
|
|
} else { // return all files filtered by $folder
|
|
$files->where('parent_id', $folder->id);
|
|
}
|
|
|
|
$files = $files->get();
|
|
|
|
$files = FileResource::collection($files);
|
|
|
|
// ancestors
|
|
$ancestors = FileResource::collection($ancestors);
|
|
|
|
$folder = new FileResource($folder);
|
|
|
|
// pass everything into SharedWith
|
|
return Inertia::render('SharedWith', compact('files', 'folder', 'ancestors'));
|
|
}
|
|
else { // no folder
|
|
// files are those found in the shares db
|
|
$files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
// that are shared with the current user
|
|
->where('file_shares.user_id', Auth::id())
|
|
// that have not been deleted
|
|
->whereNull('files.deleted_at')
|
|
// order by folders first
|
|
->orderByDesc('files.is_folder')
|
|
// then order by creation date
|
|
->orderByDesc('files.id')
|
|
->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'mimetype', 'is_folder', 'parent_id');
|
|
|
|
$search = $request->get('search');
|
|
|
|
if ($search) {
|
|
$files->where('name', 'like', $search);
|
|
}
|
|
|
|
$files = $files->get();
|
|
|
|
// make into collection
|
|
$files = FileResource::collection($files);
|
|
|
|
$allIds = array();
|
|
|
|
// get $parentIds of each file
|
|
foreach($files as $file) {
|
|
array_push($allIds, intval($file->id));
|
|
}
|
|
|
|
// run through and filter the $files array to not have any files which are children of the displayed files
|
|
foreach($files as $key => $value) {
|
|
foreach($allIds as $allId) {
|
|
if ($value->parent_id == $allId) {
|
|
unset($files[$key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// pass only files into SharedWith
|
|
return Inertia::render('SharedWith', compact('files'));
|
|
}
|
|
}
|
|
|
|
// render files shared by user
|
|
public function sharedByMe(Request $request, $folder = null) {
|
|
// validate passed in $folder param
|
|
if ($folder) {
|
|
// run a query just for ancestors
|
|
$firstQuery = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
->where('files.created_by', Auth::id())
|
|
->whereNull('files.deleted_at')
|
|
->find(intval($folder)); // ensure that the specified id exists in the database
|
|
if ($firstQuery) {
|
|
$ancestors = $firstQuery->ancestors;
|
|
}
|
|
|
|
// folder found in the shares db
|
|
$folder = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
->where('files.created_by', Auth::id())
|
|
->whereNull('files.deleted_at')
|
|
->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'parent_id')
|
|
->find(intval($folder)); // ensure that the specified id exists in the database
|
|
}
|
|
// if still exists,
|
|
if ($folder) {
|
|
// files are those found in the shares db
|
|
$files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
// that are made by the current user
|
|
->where('files.created_by', Auth::id())
|
|
// that have not been deleted
|
|
->whereNull('files.deleted_at')
|
|
// order by folders first
|
|
->orderByDesc('files.is_folder')
|
|
// then order by creation date
|
|
->orderByDesc('files.id')
|
|
// then select to reference file_id
|
|
->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'mimetype', 'is_folder', 'parent_id', 'file_shares.user_id as user_id');
|
|
|
|
$search = $request->get('search');
|
|
|
|
if ($search) {
|
|
$files->where('name', 'like', $search);
|
|
} else { // return all files filtered by $folder
|
|
$files->where('parent_id', $folder->id);
|
|
}
|
|
|
|
$files = $files->get();
|
|
|
|
$files = FileResource::collection($files);
|
|
|
|
// get shared_with name for each file
|
|
foreach($files as $file) {
|
|
$user = User::query()->where('id', $file->user_id)->first();
|
|
$file->shared_with = $user->name;
|
|
}
|
|
|
|
// ancestors
|
|
$ancestors = FileResource::collection($ancestors);
|
|
|
|
$folder = new FileResource($folder);
|
|
|
|
// pass everything into SharedBy
|
|
return Inertia::render('SharedBy', compact('files', 'folder', 'ancestors'));
|
|
}
|
|
else { // no folder
|
|
// files are those found in the shares db
|
|
$files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
// that are made by the current user
|
|
->where('files.created_by', Auth::id())
|
|
// that have not been deleted
|
|
->whereNull('files.deleted_at')
|
|
// order by folders first
|
|
->orderByDesc('files.is_folder')
|
|
// then order by creation date
|
|
->orderByDesc('files.id')
|
|
->select('files.id as id', 'name', 'size', 'created_by', 'file_shares.created_at as created_at', 'file_shares.updated_at as updated_at', 'mimetype', 'is_folder', 'parent_id', 'file_shares.user_id as user_id');
|
|
|
|
$search = $request->get('search');
|
|
|
|
if ($search) {
|
|
$files->where('name', 'like', $search);
|
|
}
|
|
|
|
$files = $files->get();
|
|
|
|
// get shared_with name for each file
|
|
foreach($files as $file) {
|
|
$user = User::query()->where('id', $file->user_id)->first();
|
|
$file->shared_with = $user->name;
|
|
}
|
|
|
|
// make into collection
|
|
$files = FileResource::collection($files);
|
|
|
|
$allIds = array();
|
|
|
|
// get $parentIds of each file
|
|
foreach($files as $file) {
|
|
array_push($allIds, intval($file->id));
|
|
}
|
|
|
|
// run through and filter the $files array to not have any files which are children of the displayed files
|
|
foreach($files as $key => $value) {
|
|
foreach($allIds as $allId) {
|
|
if ($value->parent_id == $allId) {
|
|
unset($files[$key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// pass only files into SharedBy
|
|
return Inertia::render('SharedBy', compact('files'));
|
|
}
|
|
}
|
|
|
|
// render recycle bin
|
|
public function recycleBin(Request $request, $folder = null) {
|
|
// validate passed in $folder param
|
|
if ($folder) {
|
|
// find folder
|
|
$folder = File::onlyTrashed()
|
|
// made by current user
|
|
->where('created_by', Auth::id())
|
|
->find(intval($folder));
|
|
}
|
|
// if still exists,
|
|
if ($folder) {
|
|
// files are those that are trashed
|
|
$files = File::onlyTrashed()
|
|
// made by current user
|
|
->where('created_by', Auth::id())
|
|
->orderBy('is_folder', 'desc')
|
|
->orderBy('deleted_at', 'desc')
|
|
->orderBy('files.id', 'desc');
|
|
|
|
$search = $request->get('search');
|
|
|
|
if ($search) {
|
|
$files->where('name', 'like', $search);
|
|
} else { // return all files filtered by $folder
|
|
$files->where('parent_id', $folder->id);
|
|
}
|
|
|
|
$files = $files->get();
|
|
|
|
$files = FileResource::collection($files);
|
|
|
|
function recursiveAncestors($file, &$ancestors) {
|
|
$parentFile = File::onlyTrashed()
|
|
->where('created_by', Auth::id())
|
|
->find($file->parent_id);
|
|
|
|
if ($parentFile) {
|
|
array_unshift($ancestors, $parentFile);
|
|
if ($parentFile->parent_id) {
|
|
recursiveAncestors($parentFile, $ancestors);
|
|
}
|
|
}
|
|
}
|
|
$ancestors = [];
|
|
recursiveAncestors($folder, $ancestors);
|
|
// ancestors
|
|
$ancestors = FileResource::collection([...$ancestors, $folder]);
|
|
|
|
$folder = new FileResource($folder);
|
|
|
|
// pass everything into RecycleBin
|
|
return Inertia::render('RecycleBin', compact('files', 'folder', 'ancestors'));
|
|
}
|
|
else { // no folder
|
|
// files are those that are trashed
|
|
$files = File::onlyTrashed()
|
|
// made by current user
|
|
->where('created_by', Auth::id())
|
|
->orderBy('is_folder', 'desc')
|
|
->orderBy('deleted_at', 'desc')
|
|
->orderBy('files.id', 'desc');
|
|
|
|
$search = $request->get('search');
|
|
|
|
if ($search) {
|
|
$files->where('name', 'like', $search);
|
|
}
|
|
|
|
$files = $files->get();
|
|
|
|
// make into collection
|
|
$files = FileResource::collection($files);
|
|
|
|
$allIds = array();
|
|
|
|
// get $parentIds of each file
|
|
foreach($files as $file) {
|
|
array_push($allIds, intval($file->id));
|
|
}
|
|
|
|
// run through and filter the $files array to not have any files which are children of the displayed files
|
|
foreach($files as $key => $value) {
|
|
foreach($allIds as $allId) {
|
|
if ($value->parent_id == $allId) {
|
|
unset($files[$key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// pass only files into SharedBy
|
|
return Inertia::render('RecycleBin', compact('files'));
|
|
}
|
|
}
|
|
|
|
// create new folder based on passed in NewFolder request
|
|
public function newFolder(NewFolder $request) {
|
|
// get validated data
|
|
$data = $request->validated();
|
|
// get parent folder from NewFolder request
|
|
$parent = $request->parent;
|
|
// make new folder object based on File() object
|
|
$folder = new File();
|
|
$folder->is_folder = 1;
|
|
$folder->name = $data['name'];
|
|
|
|
$parent->appendNode($folder);
|
|
}
|
|
|
|
// upload files
|
|
public function upload(UploadFiles $request) {
|
|
// get validated data
|
|
$data = $request->validated();
|
|
// get parent folder from UploadFiles request
|
|
$parent = $request->parent;
|
|
// get file tree structure from UploadFiles request
|
|
$tree = $request->file_tree;
|
|
// if the tree is empty, then files were uploaded without any folder structure - each file needs to be uploaded
|
|
// otherwise, the entire folder structure needs to be uploaded
|
|
empty($tree) ? $this->uploadFiles($data['files'], $parent) : $this->uploadTree($tree, $parent);
|
|
}
|
|
|
|
// get download link for selected files
|
|
public function download(SelectedFiles $request) {
|
|
$data = $request->validated();
|
|
// get parent folder from DeleteFiles request
|
|
$parent = $request->parent;
|
|
// get selected Id's otherwise empty array
|
|
$Ids = $data['Ids'] ?? [];
|
|
|
|
// if no files selected
|
|
if (!$data['all'] == false && empty($Ids)) {
|
|
return [
|
|
'message' => 'No files selected!'
|
|
];
|
|
}
|
|
|
|
// if all selected, download all
|
|
if ($data['all']) {
|
|
$downloadURL = $this->makeArchive($parent->children);
|
|
// make filename for file
|
|
$filename = $parent->name . ".zip";
|
|
}
|
|
// else download the selected IDs
|
|
else {
|
|
// if there is only one ID selected
|
|
if (count($Ids) === 1) {
|
|
// get file
|
|
$file = File::find($Ids[0]);
|
|
// if file is a folder
|
|
if ($file->is_folder) {
|
|
// and folder is empty
|
|
if($file->children->isEmpty()) {
|
|
// return message
|
|
return [
|
|
"message" => "This folder is empty"
|
|
];
|
|
}
|
|
// else folder is populated
|
|
$files = $file->children;
|
|
$downloadURL = $this->makeArchive($files);
|
|
$filename = $file->name . ".zip";
|
|
}
|
|
// otherwise
|
|
else {
|
|
// create a new path off "public/"
|
|
$path = "public/" . pathinfo($file->stored_at, PATHINFO_BASENAME);
|
|
// copy file to path
|
|
Storage::copy($file->stored_at, $path);
|
|
// define download path
|
|
$downloadURL = asset(Storage::url($path));
|
|
// define filename
|
|
$filename = $file->name;
|
|
}
|
|
}
|
|
// otherwise there are many IDs selected
|
|
else {
|
|
$files = File::query()->whereIn('id', $Ids)->get();
|
|
$downloadURL = $this->makeArchive($files);
|
|
$filename = $parent->name . ".zip";
|
|
}
|
|
}
|
|
|
|
// return URL and filename
|
|
return [
|
|
'url' => $downloadURL,
|
|
'filename' => $filename,
|
|
];
|
|
}
|
|
|
|
// get download link for files that are shared
|
|
public function downloadShared(SharedFiles $request) {
|
|
$data = $request->validated();
|
|
// get parent folder from DeleteFiles request
|
|
$parent = $request->parent;
|
|
// get selected Id's otherwise empty array
|
|
$Ids = $data['Ids'] ?? [];
|
|
// if no files selected
|
|
if (!$data['all'] == false && empty($Ids)) {
|
|
return [
|
|
'message' => 'No files selected!'
|
|
];
|
|
}
|
|
|
|
if ($parent) {
|
|
// if all selected, download all
|
|
if ($data['all']) {
|
|
$downloadURL = $this->makeArchive($parent->children);
|
|
// make filename for file
|
|
$filename = $parent->name . ".zip";
|
|
}
|
|
|
|
// else download the selected IDs
|
|
else {
|
|
// if there is only one ID selected
|
|
if (count($Ids) === 1) {
|
|
// get file
|
|
$file = File::find($Ids[0]);
|
|
// if file is a folder
|
|
if ($file->is_folder) {
|
|
// and folder is empty
|
|
if ($file->children->isEmpty()) {
|
|
// return message
|
|
return [
|
|
"message" => "This folder is empty"
|
|
];
|
|
}
|
|
// else folder is populated
|
|
$files = $file->children;
|
|
$downloadURL = $this->makeArchive($files);
|
|
$filename = $file->name . ".zip";
|
|
}
|
|
// otherwise
|
|
else {
|
|
// create a new path off "public/"
|
|
$path = "public/" . pathinfo($file->stored_at, PATHINFO_BASENAME);
|
|
// copy file to path
|
|
Storage::copy($file->stored_at, $path);
|
|
// define download path
|
|
$downloadURL = asset(Storage::url($path));
|
|
// define filename
|
|
$filename = $file->name;
|
|
}
|
|
}
|
|
// otherwise there are many IDs selected
|
|
else {
|
|
$files = File::query()->whereIn('id', $Ids)->get();
|
|
$downloadURL = $this->makeArchive($files);
|
|
$filename = $parent->name . ".zip";
|
|
}
|
|
}
|
|
}
|
|
// else there is no $parent
|
|
else {
|
|
// if all selected, download all
|
|
if ($data['all']) {
|
|
// files are those found in the shares db
|
|
$files = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
// that are shared with the current user
|
|
->where('file_shares.user_id', Auth::id())
|
|
// that have not been deleted
|
|
->whereNull('files.deleted_at')
|
|
// order by folders first
|
|
->orderByDesc('files.is_folder')
|
|
// then order by creation date
|
|
->orderByDesc('files.id')
|
|
->get();
|
|
$downloadURL = $this->makeArchive($files);
|
|
// make filename for file
|
|
$filename = "shared-" . Str::random(10) . ".zip";
|
|
}
|
|
|
|
// else download the selected IDs
|
|
else {
|
|
// if there is only one ID selected
|
|
if (count($Ids) === 1) {
|
|
// get file
|
|
$file = File::find($Ids[0]);
|
|
// if file is a folder
|
|
if ($file->is_folder) {
|
|
// and folder is empty
|
|
if ($file->children->isEmpty()) {
|
|
// return message
|
|
return [
|
|
"message" => "This folder is empty"
|
|
];
|
|
}
|
|
// else folder is populated
|
|
$files = $file->children;
|
|
$downloadURL = $this->makeArchive($files);
|
|
$filename = $file->name . ".zip";
|
|
}
|
|
// otherwise
|
|
else {
|
|
// create a new path off "public/"
|
|
$path = "public/" . pathinfo($file->stored_at, PATHINFO_BASENAME);
|
|
// copy file to path
|
|
Storage::copy($file->stored_at, $path);
|
|
// define download path
|
|
$downloadURL = asset(Storage::url($path));
|
|
// define filename
|
|
$filename = $file->name;
|
|
}
|
|
}
|
|
// otherwise there are many IDs selected
|
|
else {
|
|
$files = File::query()->whereIn('id', $Ids)->get();
|
|
$downloadURL = $this->makeArchive($files);
|
|
$filename = "shared-" . Str::random(10) . ".zip";
|
|
}
|
|
}
|
|
}
|
|
|
|
// return URL and filename
|
|
return [
|
|
'url' => $downloadURL,
|
|
'filename' => $filename,
|
|
];
|
|
}
|
|
|
|
// recycle selected files
|
|
public function recycle(SelectedFiles $request) {
|
|
// get validated data
|
|
$data = $request->validated();
|
|
// get parent folder from DeleteFiles request
|
|
$parent = $request->parent;
|
|
|
|
// if all files were selected
|
|
if ($data['all']) {
|
|
foreach ($parent->children as $file) {
|
|
$file->recycle();
|
|
}
|
|
}
|
|
// otherwise specific IDs were selected
|
|
else {
|
|
foreach($data['Ids'] ?? [] as $fileId) {
|
|
$targetFile = File::find($fileId);
|
|
if ($targetFile) $targetFile->delete();
|
|
}
|
|
}
|
|
|
|
return to_route('userFiles', [
|
|
'folder' => $parent->path
|
|
]);
|
|
}
|
|
|
|
// restores selected files
|
|
public function restore(RecycledFiles $request) {
|
|
// get validated data
|
|
$data = $request->validated();
|
|
|
|
// if all files were selected
|
|
if ($data['all']) {
|
|
$files = File::onlyTrashed()->get();
|
|
foreach ($files as $file) {
|
|
$file->restore();
|
|
}
|
|
}
|
|
// otherwise specific IDs were selected
|
|
else {
|
|
// get Id's unless empty
|
|
$Ids = $data['Ids'] ?? [];
|
|
|
|
// get files
|
|
$files = File::onlyTrashed()
|
|
->whereIn('id', $Ids)
|
|
->get();
|
|
|
|
foreach ($files as $file) {
|
|
$file->restore();
|
|
}
|
|
}
|
|
|
|
return to_route('recycleBin');
|
|
}
|
|
|
|
// deletes selected files (permanent delete)
|
|
public function delete(RecycledFiles $request) {
|
|
// get validated data
|
|
$data = $request->validated();
|
|
|
|
// if all files were selected
|
|
if ($data['all']) {
|
|
$files = File::onlyTrashed()->get();
|
|
foreach ($files as $file) {
|
|
$file->shred();
|
|
}
|
|
}
|
|
// otherwise specific IDs were selected
|
|
else {
|
|
// get Id's unless empty
|
|
$Ids = $data['Ids'] ?? [];
|
|
|
|
// get files
|
|
$files = File::onlyTrashed()
|
|
->whereIn('id', $Ids)
|
|
->get();
|
|
|
|
foreach ($files as $file) {
|
|
$file->shred();
|
|
}
|
|
}
|
|
|
|
return to_route('recycleBin');
|
|
}
|
|
|
|
// shares selected files
|
|
public function share(ShareFiles $request) {
|
|
// get data
|
|
$data = $request->validated();
|
|
// get parent folder
|
|
$parent = $request->parent;
|
|
// get selected Id's otherwise empty array
|
|
$Ids = $data['Ids'] ?? [];
|
|
// get user by email
|
|
$user = User::query()->where('email', $data['email'])->first();
|
|
|
|
// if no files selected
|
|
if (!$data['all'] == false && empty($Ids)) {
|
|
return [
|
|
'message' => 'No files selected!'
|
|
];
|
|
}
|
|
|
|
// if user doesn't exist
|
|
if (!$user->id) {
|
|
return [
|
|
'message' => 'Email does not belong to user!'
|
|
];
|
|
}
|
|
|
|
// otherwise, if all is passed, get current children. else find files by passed Id's
|
|
$files = $data['all'] ? $parent->children : File::find($Ids);
|
|
|
|
// define recursive function to add files to share
|
|
function recursiveShare($queued, $recipient) {
|
|
// get children of parent and determine whether recursive function needs to be called
|
|
foreach ($queued as $file) {
|
|
// check if file already exists in shared DB
|
|
$exists = FileShare::query()->where('file_id', $file->id)->where('user_id', $recipient->id)->first();
|
|
if ($exists) {
|
|
continue;
|
|
}
|
|
// else
|
|
// create new entry
|
|
$entry = [
|
|
'file_id' => $file->id,
|
|
'user_id' => $recipient->id,
|
|
'created_at' => $file->created_at,
|
|
'updated_at' => Carbon::now(),
|
|
];
|
|
FileShare::insert($entry);
|
|
|
|
// recurse on children, if any
|
|
if ($file->children) {
|
|
recursiveShare($file->children, $recipient);
|
|
}
|
|
}
|
|
}
|
|
|
|
// begin recursion on files
|
|
recursiveShare($files, $user);
|
|
|
|
// send email to recipient
|
|
Mail::to($user)->send(new ShareFilesNotification($user, Auth::user(), $files));
|
|
|
|
return redirect()->back();
|
|
}
|
|
|
|
|
|
// unshares selected files
|
|
public function unshare(SharedFiles $request) {
|
|
// get data
|
|
$data = $request->validated();
|
|
// get parent folder
|
|
$parent = $request->parent;
|
|
|
|
// get selected Id's otherwise empty array
|
|
$Ids = $data['Ids'] ?? [];
|
|
|
|
// if no files selected
|
|
if (!$data['all'] == false && empty($Ids)) {
|
|
return [
|
|
'message' => 'No files selected!'
|
|
];
|
|
}
|
|
|
|
// if parent exists
|
|
if ($parent) {
|
|
// if all is passed, get current children. else find files by passed Id's
|
|
$files = $data['all'] ? $parent->children : File::find($Ids);
|
|
}
|
|
// else
|
|
else {
|
|
// find all files that are created by current user and shared with others
|
|
$all = File::query()->join('file_shares', 'file_shares.file_id', 'files.id')
|
|
->where('files.created_by', Auth::id())
|
|
->whereNull('files.deleted_at')
|
|
->get();
|
|
|
|
$files = $data['all'] ? $all : File::find($Ids);
|
|
}
|
|
|
|
// define recursive function to remove files to share
|
|
function recursiveUnshare($queued) {
|
|
// get children of parent and determine whether recursive function needs to be called
|
|
foreach ($queued as $file) {
|
|
// check if file already exists in shared DB
|
|
$dbRecord = FileShare::query()->where('file_id', $file->id)->first();
|
|
if ($dbRecord) {
|
|
// get regular db file
|
|
$file = File::query()->where('created_by', Auth::id())->find($file->id);
|
|
$dbRecord->forceDelete();
|
|
|
|
// recurse on children, if any
|
|
if ($file->children) {
|
|
recursiveUnshare($file->children);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// begin recursion on files
|
|
recursiveUnshare($files);
|
|
|
|
return redirect()->back();
|
|
}
|
|
|
|
// gets user's root folder - called from userFiles
|
|
private function getRoot() {
|
|
return File::query()->whereIsRoot()->where('created_by', Auth::id())->firstOrFail();
|
|
}
|
|
|
|
// upload files - called from upload
|
|
private function uploadFiles($files, $parent) {
|
|
// loop over files, make and upload each one
|
|
foreach ($files as $userFile) {
|
|
$file = new File();
|
|
$file->stored_at = $userFile->store('/files/' . Auth::id(), 'local');
|
|
$file->is_folder = false;
|
|
$file->name = $userFile->getClientOriginalName();
|
|
$file->mimetype = $userFile->getMimeType();
|
|
$file->size = $userFile->getSize();
|
|
$file->s3 = 0; // file has NOT been uploaded to s3
|
|
$parent->appendNode($file);
|
|
|
|
// upload file to S3
|
|
UploadToS3::dispatch($file);
|
|
}
|
|
}
|
|
|
|
// upload tree - called from upload
|
|
private function uploadTree($tree, $parent) {
|
|
// loop over files in file tree
|
|
foreach($tree as $name => $file) {
|
|
// if current node in $tree is an array (that means, a folder)
|
|
if (is_array($file)) {
|
|
// make folder
|
|
$folder = new File();
|
|
$folder->is_folder = 1;
|
|
$folder->name = $name;
|
|
// append folder to parent
|
|
$parent->appendNode($folder);
|
|
// call function recursively until if condition is false
|
|
// each call has the newly-created $folder as $parent
|
|
$this->uploadTree($file, $folder);
|
|
}
|
|
// otherwise the node is a file; use uploadFiles() with file
|
|
else {
|
|
$this->uploadFiles([$file], $parent);
|
|
}
|
|
}
|
|
}
|
|
|
|
// makes archive - called from download
|
|
private function makeArchive(Collection $files): string
|
|
{
|
|
// make name for archive
|
|
$archiveName = Str::random() . ".zip";
|
|
// create public path
|
|
$path = "public/$archiveName";
|
|
|
|
// if the current $path is NOT already being used
|
|
if (!is_dir(dirname($path))) {
|
|
Storage::makeDirectory(dirname($path));
|
|
}
|
|
|
|
// get the absolute path of $path
|
|
$path = Storage::path($path);
|
|
// create new ZipArchive
|
|
$archive = new ZipArchive();
|
|
// see if a archive can be created or overwritten at $path
|
|
$res = $archive->open($path, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
|
// if so
|
|
if ($res === true) {
|
|
// define recursive function to add files to archive
|
|
function recursiveAdd($queued, $archive, $parent = "") {
|
|
// get children of parent and determine whether recursive function needs to be called
|
|
foreach ($queued as $file) {
|
|
// if there are no children, delete file
|
|
if ($file->children->isEmpty()) {
|
|
// set $internalPath to reflect file
|
|
$internalPath = $parent . $file->name;
|
|
// add file to archive
|
|
$archive->addFile(Storage::path($file->stored_at), $internalPath);
|
|
// continue loop
|
|
continue;
|
|
}
|
|
// else
|
|
// set $internalPath to reflect a directory
|
|
$internalPath = $parent . $file->name . "/";
|
|
// recurse
|
|
recursiveAdd($file->children, $archive, $internalPath);
|
|
}
|
|
}
|
|
|
|
// add all $files to $archive
|
|
recursiveAdd($files, $archive);
|
|
}
|
|
|
|
// close archive
|
|
$archive->close();
|
|
|
|
// return archive
|
|
return asset(Storage::url($archiveName));
|
|
}
|
|
|
|
}
|