You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

203 lines
6.8 KiB

<?php
namespace App\Http\Controllers;
use App\Models\File;
use App\Models\Project;
use App\Rules\MaxBound;
use App\Models\Business;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Auth;
use App\HiLib\Resources\FileResource;
use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\AllowedFilter;
use Illuminate\Support\Facades\Storage;
class FileController extends Controller
{
public function index(int $business, Request $request)
{
permit('businessAccess');
$this->indexValidation($request);
$per_page = $request->limit > 100 ? 10 : $request->limit;
return $this->indexFiltering($business)->paginate($per_page);
}
public function indexValidation($request)
{
$bound = 10;
$this->validate($request, [
'filter.project_id' => [new MaxBound($bound)] ,
'filter.user_id' => [new MaxBound($bound)] ,
]);
}
public function indexFiltering($business)
{
$query = File::where('business_id', $business);
$fileQ = QueryBuilder::for($query)
->allowedFilters([
AllowedFilter::exact('user_id'),
AllowedFilter::exact('project_id'),
AllowedFilter::exact('extension'),
]);
if (\request('_business_info')['info']['users'][\auth()->id()]['level'] != enum('levels.owner.id')) {
$requested_projects = isset(\request('filter')['project_id']) ?
array_unique(explode(',',\request('filter')['project_id'] ?? null )) :
null;
$requested_projects = collect($requested_projects)->keyBy(null)->toArray();
$project_ids = $this->myStateProjects($requested_projects);
$fileQ->where(function ($q) use ($project_ids) {
$q->whereIn('project_id', $project_ids['non_guest_ids'])
->orWhere(function ($q) use ($project_ids) {
$q->whereIn('project_id', $project_ids['guest_ids'])
->where('user_id', auth()->id());
});
});
}
if (request()->filled('group')) {
$fileQ->selectRaw("files.group, count(files.id) as file_count, sum(files.size) as file_size")->groupBy('group');
}
return $fileQ;
}
public function myStateProjects($requested_projects)
{
$non_guest_ids = [];
$guest_ids = [];
$is_empty = empty($requested_projects);
foreach (\request('_business_info')['info']['projects'] as $p_id => $p) {
$level = \request('_business_info')['info']['projects'][$p_id]['members'][\auth()->id()]['level'];
if (( $is_empty || isset($requested_projects[$p_id]))
&& $level > enum('levels.guest.id')) {
array_push($non_guest_ids, $p_id);
}
if (( $is_empty || isset($requested_projects[$p_id]))
&& $level == enum('levels.guest.id')) {
array_push($guest_ids, $p_id);
}
}
return ['non_guest_ids' => $non_guest_ids, 'guest_ids' => $guest_ids];
}
public function store(Request $request, int $business, int $project)
{
// different size and different validation
// validate
// validate the wallet is not so much in debt
// create record in the db
// put file in s3
// return file resource
$business = Business::findOrFail($business);
$project = Project::findOrFail($project);
$this->validate($request, ['file' => 'required|file',]);
$file = $request->file('file');
$file_extension = $file->getClientOriginalExtension();
$file_name = Str::random(40).'.'.$file_extension;
$file->storeAs(
$business->id.\DIRECTORY_SEPARATOR.$project->id,
$file_name,
's3'
);
$file_record = File::create([
'user_id' => Auth::id(),
'business_id' => $business->id,
'project_id' => $project->id,
'disk' => 's3', // default disk
'original_name' => $file->getClientOriginalName(),
'extension' => $file_extension,
'name' => $file_name,
'mime' => $file->getClientMimeType(),
'group' => $this->groupDetection($file),
'size' => $file->getSize(),
'description' => $request->description
]);
return new FileResource($file_record);
}
public function groupDetection(UploadedFile $file)
{
// Media files like mp4, mp3, wma and png or jpeg
[$type, $subtype] = Str::of($file->getMimeType())->explode("/",2)->pad(2, null);
if (in_array($type, ['audio', 'video', 'image'])) {
return $type;
}
// Covert string to \Illuminate\Support\Stringable object
$subtype = Str::of($subtype);
// PDF files
if ($subtype->contains(["pdf"])) {
return "pdf";
}
// Compressed files like zip, cab, rar, etc.
if ($subtype->contains(['compressed']) || in_array($file->getClientOriginalExtension(), ['zip', 'rar','7z','cab'])) {
return "compressed";
}
// Office files like xls, xlsx, doc, docx, etc.
if ($subtype->contains(['vnd.ms', 'vnd.sealed', 'officedocument', 'opendocument'])) {
return "office";
}
// Non of the above files
return "other";
}
public function download(int $business, int $project, int $file)
{
// requested file belongs to this project and this business
// check permisson
// create perma link or temp link
// return the file resource or stream it
return File::findOrFail($file)->getTemporaryLink();
}
public function rename(Request $request, int $business, int $project, int $file)
{
// requested file belongs to this project and this business
// check permisson
// update original name
// return the file resource
// sanitize the name for slashs and back slashes
$this->validate($request, [
'name' => 'required|string'
]);
$file = File::findOrFail($file);
$file->update(['original_name' => $request->name.".".$file->extension]);
return new FileResource($file);
}
public function delete(Request $request, int $business, int $project, int $file)
{
// requested file belongs to this project and this business
// check permisson
// check it's relations
// delete the file form File table
// delete file from s3
$file = File::findOrFail($file);
Storage::disk('s3')->delete($file->getPath());
return $file->delete();
}
}