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
4 changes: 2 additions & 2 deletions app/Console/Commands/GenerateSitemap.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
class GenerateSitemap extends Command
{
protected $signature = 'sitemap:generate';

protected $description = 'Generate the SEO sitemap for public pages.';

public function handle(): void
Expand All @@ -30,4 +30,4 @@ public function handle(): void

$this->info('Sitemap generated successfully in the public folder.');
}
}
}
6 changes: 3 additions & 3 deletions app/Enums/ApplicationStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ enum ApplicationStatus: string
case Offered = 'offered';
case Rejected = 'rejected';

public function getLabel(): ?string
public function getLabel(): string
{
return match ($this) {
self::Saved => 'Wishlist',
Expand All @@ -21,7 +21,7 @@ public function getLabel(): ?string
};
}

public function getColor(): string | array | null
public function getColor(): string
{
return match ($this) {
self::Saved => 'gray',
Expand All @@ -32,7 +32,7 @@ public function getColor(): string | array | null
};
}

public function getIcon(): ?string
public function getIcon(): string
{
return match ($this) {
self::Saved => 'heroicon-m-bookmark',
Expand Down
8 changes: 3 additions & 5 deletions app/Events/MatchReportUpdated.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@ class MatchReportUpdated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public function __construct(public MatchReport $matchReport)
{
}
public function __construct(public MatchReport $matchReport) {}

public function broadcastOn(): array
{
return [
new Channel('match-reports.' . $this->matchReport->user_id),
new Channel('match-reports.'.$this->matchReport->user_id),
];
}
}
}
6 changes: 3 additions & 3 deletions app/Http/Controllers/ApplicationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\JobPosting;
use Illuminate\Http\Request;

class ApplicationController extends Controller
{
Expand Down Expand Up @@ -41,7 +41,7 @@ public function show(JobPosting $jobPosting)
{
// FIX: Pass the $jobPosting model to the view as 'application'
return view('applications.show', [
'application' => $jobPosting
'application' => $jobPosting,
]);
}

Expand Down Expand Up @@ -75,4 +75,4 @@ public function destroy(JobPosting $jobPosting)

return redirect()->route('applications.index')->with('success', 'Job posting deleted successfully.');
}
}
}
25 changes: 14 additions & 11 deletions app/Http/Controllers/Auth/GoogleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,36 @@
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;

class GoogleController extends Controller
{
public function login()
{
session(['google_auth_intent' => 'login']);

return Socialite::driver('google')->redirect();
}

public function register()
{
session(['google_auth_intent' => 'register']);

return Socialite::driver('google')->redirect();
}

public function callback(Request $request)
{
try {
// Using stateless() prevents the InvalidStateException caused by
// dropped cookies when routing through tunnels like Expose or Ngrok.
$googleUser = Socialite::driver('google')->stateless()->user();
/** @var \Laravel\Socialite\Two\GoogleProvider $driver */
$driver = Socialite::driver('google');
$googleUser = $driver->stateless()->user();
} catch (\Exception $e) {
\Log::error('Google Auth Failed: ' . $e->getMessage());
\Log::error('Google Auth Failed: '.$e->getMessage());

return redirect()->route('login')->withErrors([
'email' => 'Google authentication failed. Please try again.',
]);
Expand All @@ -44,7 +47,7 @@ public function callback(Request $request)
->first();

if ($intent === 'login') {
if (!$existingUser) {
if (! $existingUser) {
return redirect()->route('register')->withErrors([
'email' => 'No account found with this Google account. Please register first.',
]);
Expand All @@ -56,8 +59,8 @@ public function callback(Request $request)
]);

Auth::login($existingUser, true);
$request->session()->regenerate(); // CRITICAL: Persists the session state
$request->session()->regenerate();

return redirect()->intended(route('dashboard'));
}

Expand All @@ -77,8 +80,8 @@ public function callback(Request $request)
]);

Auth::login($newUser, true);
$request->session()->regenerate(); // CRITICAL: Persists the session state
$request->session()->regenerate();

return redirect()->intended(route('dashboard'));
}

Expand Down
4 changes: 2 additions & 2 deletions app/Http/Controllers/ContactController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace App\Http\Controllers;

use App\Mail\ContactSupportMessage;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Mail\ContactSupportMessage;

class ContactController extends Controller
{
Expand All @@ -25,4 +25,4 @@ public function submit(Request $request)

return back()->with('status', 'Your message has been sent successfully.');
}
}
}
43 changes: 21 additions & 22 deletions app/Http/Controllers/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Resume;
use App\Models\MatchReport;
use App\Models\Resume;
use Illuminate\Support\Str;

class DashboardController extends Controller
Expand All @@ -17,10 +16,10 @@ public function index()

// Calculate total reports and average score in one database trip
$reportStats = MatchReport::where('user_id', $user->id)
->selectRaw("
->selectRaw('
count(*) as total_reports,
avg(score) as average_score
")->first();
')->first();

$totalReports = (int) ($reportStats->total_reports ?? 0);
$averageScore = round((float) ($reportStats->average_score ?? 0));
Expand All @@ -35,36 +34,36 @@ public function index()
$recentReports = $baseReports->take(3);
$trendReports = $baseReports->reverse()->values();

$chartLabels = $trendReports->map(fn($r) => $r->created_at->format('M d'))->toArray();
$chartLabels = $trendReports->map(fn ($r) => $r->created_at->format('M d'))->toArray();
$chartData = $trendReports->pluck('score')->toArray();
$chartTooltips = $trendReports->map(fn($r) => Str::limit($r->jobPosting->title ?? 'Unknown Job', 30))->toArray();

$chartTooltips = $trendReports->map(fn ($r) => Str::limit($r->jobPosting->title ?? 'Unknown Job', 30))->toArray();

$readiness = 0;
$readinessMessage = "";
$readinessSubtext = "";
$readinessMessage = '';
$readinessSubtext = '';

if ($totalResumes === 0 && $totalReports === 0) {
$readiness = 0;
$readinessMessage = "Awaiting Data";
$readinessSubtext = "Upload your first resume to establish your baseline.";
$readinessMessage = 'Awaiting Data';
$readinessSubtext = 'Upload your first resume to establish your baseline.';
} elseif ($totalResumes > 0 && $totalReports === 0) {
$readiness = 20;
$readinessMessage = "Baseline Established";
$readinessSubtext = "Run your first match report to calibrate your true readiness score.";
$readinessMessage = 'Baseline Established';
$readinessSubtext = 'Run your first match report to calibrate your true readiness score.';
} else {
$readiness = 40 + ($averageScore * 0.6);
$readiness = 40 + ($averageScore * 0.6);
$readiness = min(100, round($readiness));

if ($readiness < 60) {
$readinessMessage = "Needs Optimization";
$readinessSubtext = "Your tailored resumes need more alignment with the jobs you are targeting.";
$readinessMessage = 'Needs Optimization';
$readinessSubtext = 'Your tailored resumes need more alignment with the jobs you are targeting.';
} elseif ($readiness < 85) {
$readinessMessage = "Strong Contender";
$readinessSubtext = "You are matching well. Keep refining your keywords to reach the top tier.";
$readinessMessage = 'Strong Contender';
$readinessSubtext = 'You are matching well. Keep refining your keywords to reach the top tier.';
} else {
$readinessMessage = "Highly Optimized";
$readinessSubtext = "Your application materials are exceptionally aligned. You are ready to apply.";
$readinessMessage = 'Highly Optimized';
$readinessSubtext = 'Your application materials are exceptionally aligned. You are ready to apply.';
}
}

Expand All @@ -81,4 +80,4 @@ public function index()
'chartTooltips'
));
}
}
}
6 changes: 3 additions & 3 deletions app/Http/Controllers/MatchReportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\MatchReport;
use App\Services\MatchAnalysisService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class MatchReportController extends Controller
Expand All @@ -24,7 +24,7 @@ public function create()
public function store(Request $request, MatchAnalysisService $matchService)
{
$request->validate([
'resume_id' => 'required|exists:resumes,id',
'resume_id' => 'required|exists:resumes,id',
'job_posting_id' => 'required|exists:job_postings,id',
]);

Expand Down Expand Up @@ -69,4 +69,4 @@ public function destroy(MatchReport $matchReport)

return redirect()->route('matches.index')->with('success', 'Report deleted successfully.');
}
}
}
11 changes: 6 additions & 5 deletions app/Http/Controllers/ProfileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Redirect;
use Illuminate\View\View;

class ProfileController extends Controller
Expand All @@ -21,11 +21,12 @@ public function edit(Request $request): View

public function update(ProfileUpdateRequest $request): RedirectResponse
{
$limitKey = 'update-profile:' . $request->user()->id;
$limitKey = 'update-profile:'.$request->user()->id;

if (RateLimiter::tooManyAttempts($limitKey, 5)) {
$seconds = RateLimiter::availableIn($limitKey);
return Redirect::route('profile.edit')->with('error', 'Please wait ' . $seconds . ' seconds before trying again.');

return Redirect::route('profile.edit')->with('error', 'Please wait '.$seconds.' seconds before trying again.');
}

RateLimiter::hit($limitKey, 60);
Expand All @@ -38,7 +39,7 @@ public function update(ProfileUpdateRequest $request): RedirectResponse

public function destroy(Request $request): RedirectResponse
{
$limitKey = 'delete-account:' . $request->user()->id;
$limitKey = 'delete-account:'.$request->user()->id;

if (RateLimiter::tooManyAttempts($limitKey, 5)) {
return Redirect::route('profile.edit')->with('error', 'Too many attempts. Please try again later.');
Expand All @@ -62,4 +63,4 @@ public function destroy(Request $request): RedirectResponse

return Redirect::to('/')->with('success', 'Your account has been permanently deleted.');
}
}
}
14 changes: 7 additions & 7 deletions app/Http/Controllers/ResumeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Resume;
use App\Services\ResumeParserService;
use Illuminate\Http\Request;

class ResumeController extends Controller
{
Expand All @@ -19,17 +19,17 @@ public function store(Request $request, ResumeParserService $parser)
{
$request->validate([
'label' => 'required|string|max:255',
'file' => 'required|file|mimes:pdf|max:5120',
'file' => 'required|file|mimes:pdf|max:5120',
]);

$uploadResult = $parser->processUpload($request->file('file'));

Resume::create([
'user_id' => auth()->id(),
'label' => $request->label,
'file_url' => $uploadResult['file_url'],
'user_id' => auth()->id(),
'label' => $request->label,
'file_url' => $uploadResult['file_url'],
'content_raw' => $uploadResult['content_raw'],
'is_active' => true,
'is_active' => true,
]);

return redirect()->route('resumes.index')->with('success', 'Resume uploaded and parsed successfully.');
Expand Down Expand Up @@ -59,4 +59,4 @@ public function destroy(Resume $resume)

return redirect()->route('resumes.index')->with('success', 'Resume deleted successfully.');
}
}
}
Loading
Loading