big update base struktur tahap 1
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\File;
|
||||
|
||||
use App\Models\StoredFile;
|
||||
use App\Models\User;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class StoredFileService
|
||||
{
|
||||
public function list(array $filters, User $user, ?int $tenantId): LengthAwarePaginator
|
||||
{
|
||||
return StoredFile::query()
|
||||
->when(! $user->isMasterAdmin(), function ($query) use ($user, $tenantId) {
|
||||
$query->where(function ($scope) use ($user, $tenantId) {
|
||||
$scope->where('uploaded_by', $user->id)
|
||||
->when($tenantId, fn ($tenantScope) => $tenantScope->orWhere('tenant_id', $tenantId));
|
||||
});
|
||||
})
|
||||
->when($filters['search'] ?? null, function ($query, $search) {
|
||||
$query->where('original_name', 'like', "%{$search}%");
|
||||
})
|
||||
->when($filters['category'] ?? null, fn ($query, $category) => $query->where('category', $category))
|
||||
->when($filters['mime_type'] ?? null, fn ($query, $mimeType) => $query->where('mime_type', $mimeType))
|
||||
->latest('id')
|
||||
->paginate($filters['per_page'] ?? 10);
|
||||
}
|
||||
|
||||
public function store(UploadedFile $upload, User $user, ?int $tenantId, string $category): StoredFile
|
||||
{
|
||||
$uuid = (string) Str::uuid();
|
||||
$extension = strtolower($upload->getClientOriginalExtension() ?: $upload->extension() ?: 'bin');
|
||||
$scope = $tenantId ? "tenants/{$tenantId}" : 'global';
|
||||
$objectKey = "{$scope}/{$category}/".now()->format('Y/m')."/{$uuid}.{$extension}";
|
||||
$disk = Storage::disk('minio');
|
||||
|
||||
$disk->putFileAs(dirname($objectKey), $upload, basename($objectKey), [
|
||||
'visibility' => 'private',
|
||||
'ContentType' => $upload->getMimeType() ?: 'application/octet-stream',
|
||||
]);
|
||||
|
||||
try {
|
||||
return DB::transaction(fn () => StoredFile::create([
|
||||
'uuid' => $uuid,
|
||||
'tenant_id' => $tenantId,
|
||||
'uploaded_by' => $user->id,
|
||||
'disk' => 'minio',
|
||||
'bucket' => (string) config('filesystems.disks.minio.bucket'),
|
||||
'object_key' => $objectKey,
|
||||
'original_name' => $upload->getClientOriginalName(),
|
||||
'extension' => $extension,
|
||||
'mime_type' => $upload->getMimeType(),
|
||||
'size' => $upload->getSize(),
|
||||
'category' => $category,
|
||||
'visibility' => 'private',
|
||||
]));
|
||||
} catch (\Throwable $exception) {
|
||||
$disk->delete($objectKey);
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
public function temporaryUrl(StoredFile $file, User $user): array
|
||||
{
|
||||
$this->authorizeAccess($file, $user);
|
||||
$expiresAt = now()->addMinutes(10);
|
||||
|
||||
return [
|
||||
'url' => Storage::disk($file->disk)->temporaryUrl(
|
||||
$file->object_key,
|
||||
$expiresAt,
|
||||
['ResponseContentDisposition' => 'inline; filename="'.addslashes($file->original_name).'"']
|
||||
),
|
||||
'expires_at' => $expiresAt->toIso8601String(),
|
||||
];
|
||||
}
|
||||
|
||||
public function delete(StoredFile $file, User $user): void
|
||||
{
|
||||
if (! $user->isMasterAdmin() && $file->uploaded_by !== $user->id) {
|
||||
abort(403, 'File hanya dapat dihapus oleh pengunggah atau Master Admin.');
|
||||
}
|
||||
|
||||
Storage::disk($file->disk)->delete($file->object_key);
|
||||
$file->delete();
|
||||
}
|
||||
|
||||
public function authorizeAccess(StoredFile $file, User $user): void
|
||||
{
|
||||
if ($user->isMasterAdmin() || $file->uploaded_by === $user->id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$canAccessTenant = $file->tenant_id && $user->userTenants()
|
||||
->where('tenant_id', $file->tenant_id)
|
||||
->exists();
|
||||
|
||||
abort_unless($canAccessTenant, 403, 'Anda tidak memiliki akses ke file ini.');
|
||||
}
|
||||
|
||||
public function validateProfilePhoto(StoredFile $file, User $user): void
|
||||
{
|
||||
if ($file->uploaded_by !== $user->id
|
||||
|| $file->category !== 'profile'
|
||||
|| ! str_starts_with((string) $file->mime_type, 'image/')
|
||||
|| $file->size > 5 * 1024 * 1024) {
|
||||
throw ValidationException::withMessages([
|
||||
'profile_photo_file_id' => 'Foto profil harus berupa file gambar kategori profile yang Anda unggah sendiri.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user