init commit
This commit is contained in:
356
app/Http/Controllers/ResumeBuilderController.php
Normal file
356
app/Http/Controllers/ResumeBuilderController.php
Normal file
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Resume Builder Controller
|
||||
* Professional Resume Builder - Resume Creation and Management
|
||||
*
|
||||
* @author David Valera Melendez <david@valera-melendez.de>
|
||||
* @created 2025-08-08
|
||||
* @location Made in Germany 🇩🇪
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\Resume\StoreResumeRequest;
|
||||
use App\Http\Requests\Resume\UpdateResumeRequest;
|
||||
use App\Models\Resume;
|
||||
use App\Interfaces\ResumeRepositoryInterface;
|
||||
use App\Interfaces\UserRepositoryInterface;
|
||||
use App\Services\ResumeService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* Resume Builder Controller
|
||||
* Handles resume creation, editing, and management with repository pattern
|
||||
*/
|
||||
class ResumeBuilderController extends Controller
|
||||
{
|
||||
/**
|
||||
* Resume repository instance
|
||||
*/
|
||||
protected ResumeRepositoryInterface $resumeRepository;
|
||||
|
||||
/**
|
||||
* User repository instance
|
||||
*/
|
||||
protected UserRepositoryInterface $userRepository;
|
||||
|
||||
/**
|
||||
* ResumeService instance
|
||||
*/
|
||||
protected ResumeService $resumeService;
|
||||
|
||||
/**
|
||||
* Create a new controller instance with dependency injection
|
||||
*/
|
||||
public function __construct(
|
||||
ResumeRepositoryInterface $resumeRepository,
|
||||
UserRepositoryInterface $userRepository,
|
||||
ResumeService $resumeService
|
||||
) {
|
||||
$this->resumeRepository = $resumeRepository;
|
||||
$this->userRepository = $userRepository;
|
||||
$this->resumeService = $resumeService;
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of user's resumes
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$userId = Auth::id();
|
||||
|
||||
// Get paginated resumes using repository
|
||||
$resumes = $this->resumeRepository->getPaginatedUserResumes($userId, 12);
|
||||
|
||||
// Get resume statistics using repository
|
||||
$resumeStats = $this->resumeRepository->getResumeStatistics($userId);
|
||||
|
||||
return view('resume-builder.index', [
|
||||
'title' => 'My Resumes - Resume Builder',
|
||||
'resumes' => $resumes,
|
||||
'resumeStats' => $resumeStats
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resume
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
$userId = Auth::id();
|
||||
|
||||
// Check if user can create more resumes
|
||||
if (!$this->resumeRepository->canUserCreateMoreResumes($userId, 10)) {
|
||||
return redirect()->route('resume-builder.index')
|
||||
->with('error', 'You have reached the maximum number of resumes allowed.');
|
||||
}
|
||||
|
||||
$templates = $this->resumeService->getAvailableTemplates();
|
||||
|
||||
return view('resume-builder.create', [
|
||||
'title' => 'Create New Resume',
|
||||
'templates' => $templates
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resume
|
||||
*/
|
||||
public function store(StoreResumeRequest $request): RedirectResponse
|
||||
{
|
||||
try {
|
||||
$userId = Auth::id();
|
||||
|
||||
// Check if user can create more resumes
|
||||
if (!$this->resumeRepository->canUserCreateMoreResumes($userId, 10)) {
|
||||
return back()->withErrors([
|
||||
'title' => 'You have reached the maximum number of resumes allowed.'
|
||||
])->withInput();
|
||||
}
|
||||
|
||||
$resumeData = $request->validated();
|
||||
$resumeData['user_id'] = $userId;
|
||||
|
||||
// Create resume using repository
|
||||
$resume = $this->resumeRepository->create($resumeData);
|
||||
|
||||
// Update completion percentage
|
||||
$this->resumeRepository->updateCompletionPercentage($resume->id);
|
||||
|
||||
logger()->info('Resume created', [
|
||||
'user_id' => $userId,
|
||||
'resume_id' => $resume->id,
|
||||
'title' => $resume->title
|
||||
]);
|
||||
|
||||
return redirect()->route('resume-builder.edit', $resume)
|
||||
->with('success', 'Resume created successfully! Start building your professional CV.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
logger()->error('Resume creation error', [
|
||||
'error' => $e->getMessage(),
|
||||
'user_id' => Auth::id()
|
||||
]);
|
||||
|
||||
return back()->withErrors([
|
||||
'title' => 'Unable to create resume. Please try again.'
|
||||
])->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resume
|
||||
*/
|
||||
public function edit(Resume $resume): View
|
||||
{
|
||||
$this->authorize('update', $resume);
|
||||
|
||||
return view('resume-builder.edit', [
|
||||
'title' => 'Edit Resume - ' . $resume->title,
|
||||
'resume' => $resume,
|
||||
'templates' => $this->resumeService->getAvailableTemplates()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resume
|
||||
*/
|
||||
public function update(UpdateResumeRequest $request, Resume $resume): RedirectResponse
|
||||
{
|
||||
$this->authorize('update', $resume);
|
||||
|
||||
try {
|
||||
$resumeData = $request->validated();
|
||||
|
||||
// Update resume using repository
|
||||
$this->resumeRepository->update($resume->id, $resumeData);
|
||||
|
||||
// Update completion percentage
|
||||
$this->resumeRepository->updateCompletionPercentage($resume->id);
|
||||
|
||||
logger()->info('Resume updated', [
|
||||
'user_id' => Auth::id(),
|
||||
'resume_id' => $resume->id
|
||||
]);
|
||||
|
||||
return back()->with('success', 'Resume updated successfully!');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
logger()->error('Resume update error', [
|
||||
'error' => $e->getMessage(),
|
||||
'user_id' => Auth::id(),
|
||||
'resume_id' => $resume->id
|
||||
]);
|
||||
|
||||
return back()->withErrors([
|
||||
'title' => 'Unable to update resume. Please try again.'
|
||||
])->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resume preview
|
||||
*/
|
||||
public function preview(Resume $resume): View
|
||||
{
|
||||
$this->authorize('view', $resume);
|
||||
|
||||
// Increment view count using repository
|
||||
$this->resumeRepository->incrementViewCount($resume->id);
|
||||
|
||||
return view('resume-builder.preview', [
|
||||
'title' => 'Preview - ' . $resume->title,
|
||||
'resume' => $resume
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resume
|
||||
*/
|
||||
public function destroy(Resume $resume): RedirectResponse
|
||||
{
|
||||
$this->authorize('delete', $resume);
|
||||
|
||||
try {
|
||||
// Delete resume using repository
|
||||
$this->resumeRepository->delete($resume->id);
|
||||
|
||||
logger()->info('Resume deleted', [
|
||||
'user_id' => Auth::id(),
|
||||
'resume_id' => $resume->id,
|
||||
'title' => $resume->title
|
||||
]);
|
||||
|
||||
return redirect()->route('resume-builder.index')
|
||||
->with('success', 'Resume deleted successfully.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
logger()->error('Resume deletion error', [
|
||||
'error' => $e->getMessage(),
|
||||
'user_id' => Auth::id(),
|
||||
'resume_id' => $resume->id
|
||||
]);
|
||||
|
||||
return back()->withErrors([
|
||||
'error' => 'Unable to delete resume. Please try again.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download resume as PDF
|
||||
*/
|
||||
public function downloadPdf(Resume $resume)
|
||||
{
|
||||
$this->authorize('view', $resume);
|
||||
|
||||
try {
|
||||
// Increment download count using repository
|
||||
$this->resumeRepository->incrementDownloadCount($resume->id);
|
||||
|
||||
return $this->resumeService->generatePdf($resume);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
logger()->error('PDF generation error', [
|
||||
'error' => $e->getMessage(),
|
||||
'user_id' => Auth::id(),
|
||||
'resume_id' => $resume->id
|
||||
]);
|
||||
|
||||
return back()->withErrors([
|
||||
'error' => 'Unable to generate PDF. Please try again.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate an existing resume
|
||||
*/
|
||||
public function duplicate(Resume $resume): RedirectResponse
|
||||
{
|
||||
$this->authorize('view', $resume);
|
||||
|
||||
try {
|
||||
$userId = Auth::id();
|
||||
|
||||
// Check if user can create more resumes
|
||||
if (!$this->resumeRepository->canUserCreateMoreResumes($userId, 10)) {
|
||||
return back()->withErrors([
|
||||
'error' => 'You have reached the maximum number of resumes allowed.'
|
||||
]);
|
||||
}
|
||||
|
||||
$newTitle = $resume->title . ' (Copy)';
|
||||
$duplicatedResume = $this->resumeRepository->duplicateResume($resume->id, $userId, $newTitle);
|
||||
|
||||
logger()->info('Resume duplicated', [
|
||||
'user_id' => $userId,
|
||||
'original_resume_id' => $resume->id,
|
||||
'new_resume_id' => $duplicatedResume->id
|
||||
]);
|
||||
|
||||
return redirect()->route('resume-builder.edit', $duplicatedResume)
|
||||
->with('success', 'Resume duplicated successfully!');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
logger()->error('Resume duplication error', [
|
||||
'error' => $e->getMessage(),
|
||||
'user_id' => Auth::id(),
|
||||
'resume_id' => $resume->id
|
||||
]);
|
||||
|
||||
return back()->withErrors([
|
||||
'error' => 'Unable to duplicate resume. Please try again.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search user's resumes
|
||||
*/
|
||||
public function search(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$query = $request->input('query', '');
|
||||
$userId = Auth::id();
|
||||
|
||||
if (empty($query)) {
|
||||
return response()->json([]);
|
||||
}
|
||||
|
||||
$resumes = $this->resumeRepository
|
||||
->getUserResumes($userId)
|
||||
->filter(function ($resume) use ($query) {
|
||||
return stripos($resume->title, $query) !== false ||
|
||||
stripos($resume->description, $query) !== false;
|
||||
})
|
||||
->take(10)
|
||||
->values();
|
||||
|
||||
return response()->json($resumes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resume analytics
|
||||
*/
|
||||
public function analytics(Resume $resume): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$this->authorize('view', $resume);
|
||||
|
||||
$analytics = [
|
||||
'view_count' => $resume->view_count,
|
||||
'download_count' => $resume->download_count,
|
||||
'completion_percentage' => $resume->completion_percentage,
|
||||
'last_viewed_at' => $resume->last_viewed_at,
|
||||
'last_downloaded_at' => $resume->last_downloaded_at,
|
||||
'created_at' => $resume->created_at,
|
||||
'updated_at' => $resume->updated_at,
|
||||
];
|
||||
|
||||
return response()->json($analytics);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user