Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 9 additions & 56 deletions app/Http/Controllers/Files/AreaFilesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Mostafaznv\PdfOptimizer\Laravel\Facade\PdfOptimizer;
// Compression is handled client-side before upload — no server-side optimizer needed.


class AreaFilesController extends Controller
Expand All @@ -29,8 +28,11 @@ public function store(Request $request)
{
$validated = $request->validate(
[
'outline_id' => 'nullable|exists:parameter_outlines,parameter_outline_id',
'document' => 'required|file|mimes:pdf'
'outline_id' => 'required|integer|exists:parameter_outlines,parameter_outline_id',
'document' => 'required|file|mimes:pdf|max:10240',
'program_id' => 'required|integer|exists:programs,program_id',
'level_id' => 'required|integer|exists:accreditation_levels,accreditation_level_id',
'area_id' => 'required|integer|exists:areas,area_id',
],
[
'outline_id.exists' => 'The selected outline does not exist.',
Expand Down Expand Up @@ -88,57 +90,8 @@ public function store(Request $request)
$category_name = Str::slug($categoryName, '_');
$filePath = "documents/{$degree_type}_{$program_name}/{$level}/{$area_name}/{$parameter_name}/{$category_name}";

// Ensure temp directory exists
if (!Storage::disk('public')->exists('temp')) {
Storage::disk('public')->makeDirectory('temp');
}

// Store original file temporarily
$tempFileName = 'temp_' . Str::uuid() . '.pdf';
$tempFilePath = "temp/{$tempFileName}";
Storage::disk('public')->putFileAs('temp', $file, $tempFileName);

Log::info('Temp file created: ' . $tempFilePath);
Log::info('Temp file size: ' . Storage::disk('public')->size($tempFilePath) . ' bytes');

// Optimize PDF
try {
Log::info('Starting PDF optimization...');
$customTempPath = str_replace('/', '\\', storage_path('app/public/temp'));
putenv('TMP=' . $customTempPath);
putenv('TEMP=' . $customTempPath);

Log::info('Using custom TEMP/TMP path: ' . $customTempPath);

$result = PdfOptimizer::fromDisk('public')
->open($tempFilePath)
->toDisk('public')
->optimize("{$filePath}/{$fileName}");

Log::info('Optimization status: ' . ($result->status ? 'SUCCESS' : 'FAILED'));
Log::info('Optimization message: ' . $result->message);

if (Storage::disk('public')->exists("{$filePath}/{$fileName}")) {
Log::info('Optimized file created successfully');
Log::info('Optimized file size: ' . Storage::disk('public')->size("{$filePath}/{$fileName}") . ' bytes');
} else {
Log::error('Optimized file NOT found!');
}

// Delete temporary file
Storage::disk('public')->delete($tempFilePath);
Log::info('Temp file deleted');

if (!$result->status) {
Storage::disk('public')->putFileAs($filePath, $file, $fileName);
Log::warning('PDF optimization failed, using original file: ' . $result->message);
}
} catch (\Exception $e) {
Storage::disk('public')->delete($tempFilePath);
Storage::disk('public')->putFileAs($filePath, $file, $fileName);
Log::error('PDF optimization error: ' . $e->getMessage());
Log::error('Stack trace: ' . $e->getTraceAsString());
}
// PDF is already compressed by the client before upload — store directly.
Storage::disk('public')->putFileAs($filePath, $file, $fileName);

$areaFile = $parameterOutlines->AreaFiles()->create([
'file_name' => $fileName,
Expand Down Expand Up @@ -169,7 +122,7 @@ public function download(Request $request)
$areaFile = $parameterOutlines->AreaFiles;

if ($areaFile && Storage::disk('public')->exists($areaFile->file_path)) {
return Storage::disk('public')->download($areaFile->file_path, $areaFile->file_name);
return response()->download(storage_path("app/public/" . $areaFile->file_path), $areaFile->file_name);
} else {
return redirect()->back()
->with('type', 'error')
Expand Down
5 changes: 4 additions & 1 deletion app/Http/Controllers/Files/AreaFormsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ public function store(Request $request): RedirectResponse
$validated = $request->validate(
[
'area_form_category_id' => 'required|integer|exists:area_form_categories,area_form_category_id',
'document' => 'nullable|file|mimes:pdf',
'document' => 'nullable|file|mimes:pdf|max:10240',
'program_id' => 'required|integer|exists:programs,program_id',
'level_id' => 'required|integer|exists:accreditation_levels,accreditation_level_id',
'area_id' => 'required|integer|exists:areas,area_id',
],
[
'area_form_category_id.required' => 'Form category ID is required.',
Expand Down
64 changes: 0 additions & 64 deletions app/Http/Controllers/TestingShits.php

This file was deleted.

43 changes: 43 additions & 0 deletions app/Http/Middleware/SecurityHeaders.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class SecurityHeaders
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);

// Prevent clickjacking
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');

// Prevent MIME-type sniffing
$response->headers->set('X-Content-Type-Options', 'nosniff');

// Basic XSS protection (though modern browsers handle this better)
$response->headers->set('X-XSS-Protection', '1; mode=block');

// Referrer Policy
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');

// Content Security Policy (Liberalized for Development)
// We allow all origins (*) to ensure external resources like Facebook, YouTube, and Google Maps are not blocked.
$csp = "default-src 'self' * 'unsafe-inline' 'unsafe-eval' data: blob:; ";
$csp .= "frame-src 'self' *; ";
$csp .= "frame-ancestors 'self' *; ";
$csp .= "object-src 'none';";

$response->headers->set('Content-Security-Policy', $csp);

return $response;
}
}
3 changes: 3 additions & 0 deletions bootstrap/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use App\Http\Middleware\UserProgramPrivileges;
use App\Http\Middleware\UserAreaPrivileges;

use App\Http\Middleware\SecurityHeaders;

return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
Expand All @@ -25,6 +27,7 @@
$middleware->web(append: [
HandleInertiaRequests::class,
AddLinkHeadersForPreloadedAssets::class,
// SecurityHeaders::class,
]);
/* $middleware->api(prepend: [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
Expand Down
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"laravel/reverb": "^1.0",
"laravel/tinker": "^2.10.1",
"league/csv": "^9.27",
"mostafaznv/pdf-optimizer": "^1.2",
"tightenco/ziggy": "^2.4"
},
"require-dev": {
Expand Down
73 changes: 1 addition & 72 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions config/cors.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

return [

/*
|--------------------------------------------------------------------------
| Cross-Origin Resource Sharing (CORS) Configuration
|--------------------------------------------------------------------------
|
| Fully disabled for local development (as requested).
| This allows ANY origin, any method, any header.
| We will tighten this later before production.
|
*/

'paths' => ['*'],

'allowed_methods' => ['*'],

'allowed_origins' => ['*'], // ← FULLY OPEN

'allowed_origins_patterns' => [],

'allowed_headers' => ['*'],

'exposed_headers' => [],

'max_age' => 0,

'supports_credentials' => false, // ← changed to false (required when using *)
];
16 changes: 0 additions & 16 deletions config/pdf-optimizer.php

This file was deleted.

20 changes: 20 additions & 0 deletions knip.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"entry": [
"resources/js/app.tsx",
"resources/js/ssr.jsx",
"resources/scss/app.scss",
"resources/js/components/ui/**/*.{ts,tsx}",
"resources/js/echo.js"
],
"project": ["resources/js/**/*.{js,jsx,ts,tsx}", "resources/scss/**/*.scss", "resources/css/**/*.css"],
"ignoreDependencies": [
"concurrently",
"@inertiajs/core",
"zod",
"date-fns"
],
"rules": {
"exports": "off",
"types": "off"
}
}
Loading
Loading