Feat: Upload Controller and Prune Commands Extraction from 3dealer
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Core\File\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Modules\Core\File\Services\FileService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic wrapper around FileService::pruneUnowned() — see that method's
|
||||||
|
* own docblock for what "unowned" means and why the grace period exists.
|
||||||
|
* Any caller (3dealer's product custom-field photo uploads today, some
|
||||||
|
* other future upload feature tomorrow, in this app or another consuming
|
||||||
|
* app) schedules this once per purpose string it stores files under; this
|
||||||
|
* command itself has no opinion about what any given purpose means.
|
||||||
|
*/
|
||||||
|
class PruneUnownedFilesCommand extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'boboko:file:prune-unowned {purpose} {--hours=24 : Only delete unowned files older than this}';
|
||||||
|
|
||||||
|
protected $description = 'Delete unowned files of a given purpose past their grace period';
|
||||||
|
|
||||||
|
public function handle(FileService $files): int
|
||||||
|
{
|
||||||
|
$purpose = $this->argument('purpose');
|
||||||
|
|
||||||
|
$deleted = $files->pruneUnowned($purpose, now()->subHours((int) $this->option('hours')));
|
||||||
|
|
||||||
|
$this->info("Deleted {$deleted} unowned file(s) of purpose \"{$purpose}\".");
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Core\File\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Modules\Core\File\Services\FileService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The generic "accept an upload, validate it, store it via FileService,
|
||||||
|
* return its id" flow — what varies per use case (which extensions/sizes
|
||||||
|
* are acceptable) is deliberately NOT configurable here, and NEVER trusts
|
||||||
|
* anything the request itself claims about its own limits: a client could
|
||||||
|
* simply lie about them. purpose()/validationRules() are protected hooks
|
||||||
|
* a concrete subclass overrides instead — an ordinary PHP method a caller
|
||||||
|
* writes once per upload policy, not request input, so the actual limit
|
||||||
|
* enforced is always whatever server-side code says it is. Different
|
||||||
|
* products can even need different limits (a 3D-print reference photo
|
||||||
|
* vs. a video upload, say) — that's still a subclass's own store()
|
||||||
|
* override deciding which rule set applies to a given request, not
|
||||||
|
* something this base class or a shared config file could express.
|
||||||
|
*/
|
||||||
|
abstract class UploadFileController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The File row's `purpose` tag (see Models\File) — also the storage
|
||||||
|
* directory it lands under (FileService::store()'s single $purpose
|
||||||
|
* param doubles as both).
|
||||||
|
*/
|
||||||
|
abstract protected function purpose(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Laravel validation rules for the incoming request, keyed exactly as
|
||||||
|
* $request->all() would be. Must include a 'file' rule accepting an
|
||||||
|
* uploaded file — this class always reads the file from that key.
|
||||||
|
*
|
||||||
|
* @return array<string, array<int, mixed>>
|
||||||
|
*/
|
||||||
|
abstract protected function validationRules(Request $request): array;
|
||||||
|
|
||||||
|
public function store(Request $request, FileService $files): JsonResponse
|
||||||
|
{
|
||||||
|
$validator = Validator::make(
|
||||||
|
$request->all(),
|
||||||
|
$this->validationRules($request),
|
||||||
|
$this->validationMessages($request),
|
||||||
|
$this->validationAttributes($request),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json(['error' => $validator->errors()->first('file')], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $files->store($request->file('file'), $this->purpose());
|
||||||
|
|
||||||
|
return response()->json(['file_id' => $file->id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
protected function validationMessages(Request $request): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
protected function validationAttributes(Request $request): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ use InvalidArgumentException;
|
|||||||
use Modules\Core\Cart\Events\CartLineAdded;
|
use Modules\Core\Cart\Events\CartLineAdded;
|
||||||
use Modules\Core\Checkout\Events\OrderPlaced;
|
use Modules\Core\Checkout\Events\OrderPlaced;
|
||||||
use Modules\Core\File\Adapters\LocalFileAdapter;
|
use Modules\Core\File\Adapters\LocalFileAdapter;
|
||||||
|
use Modules\Core\File\Commands\PruneUnownedFilesCommand;
|
||||||
use Modules\Core\File\Contracts\FileAdapterInterface;
|
use Modules\Core\File\Contracts\FileAdapterInterface;
|
||||||
use Modules\Core\File\Listeners\AttachCustomFieldFileToCartLine;
|
use Modules\Core\File\Listeners\AttachCustomFieldFileToCartLine;
|
||||||
use Modules\Core\File\Listeners\TransferCustomFieldFileOwnership;
|
use Modules\Core\File\Listeners\TransferCustomFieldFileOwnership;
|
||||||
@@ -42,5 +43,9 @@ class FileServiceProvider extends ServiceProvider
|
|||||||
|
|
||||||
Event::listen(CartLineAdded::class, AttachCustomFieldFileToCartLine::class);
|
Event::listen(CartLineAdded::class, AttachCustomFieldFileToCartLine::class);
|
||||||
Event::listen(OrderPlaced::class, TransferCustomFieldFileOwnership::class);
|
Event::listen(OrderPlaced::class, TransferCustomFieldFileOwnership::class);
|
||||||
|
|
||||||
|
if ($this->app->runningInConsole()) {
|
||||||
|
$this->commands([PruneUnownedFilesCommand::class]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user