523 lines
19 KiB
PHP
523 lines
19 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Models\CareerApplication;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Storage;
|
||
|
||
class CareerController extends Controller
|
||
{
|
||
public function index()
|
||
{
|
||
return view('front.career.index', [
|
||
'meta' => [
|
||
'title' => __('career.job_application_title', ['default' => 'İş Başvurusu']),
|
||
'description' => __('career.job_application_description', ['default' => 'Ekibimize katılmak için aşağıdaki formu doldurarak CV\'nizi iletebilirsiniz.']),
|
||
]
|
||
]);
|
||
}
|
||
|
||
public function internship()
|
||
{
|
||
return view('front.career.internship', [
|
||
'meta' => [
|
||
'title' => __('career.internship_title', ['default' => 'Staj Başvurusu']),
|
||
'description' => __('career.internship_description', ['default' => 'Uzaktan staj programımız hakkında bilgi alın ve başvurunuzu yapın.']),
|
||
]
|
||
]);
|
||
}
|
||
|
||
public function store(Request $request)
|
||
{
|
||
$rules = [
|
||
'name' => 'required|string|max:255',
|
||
'email' => 'required|email|max:255',
|
||
'phone' => 'nullable|string|max:20',
|
||
'cv' => 'required|file|mimes:pdf,doc,docx|max:5120', // Max 5MB
|
||
'message' => 'nullable|string',
|
||
];
|
||
|
||
if ($request->type === 'job') {
|
||
$rules['nda'] = 'required|file|mimes:pdf|max:5120';
|
||
$rules['contract'] = 'required|file|mimes:pdf|max:5120';
|
||
$rules['id_photocopy'] = 'required|file|mimes:pdf,jpg,jpeg,png|max:5120'; // Max 5MB
|
||
$rules['git_knowledge'] = 'accepted';
|
||
$rules['ai_usage'] = 'accepted';
|
||
}
|
||
|
||
$request->validate($rules);
|
||
|
||
$cvPath = $request->file('cv') ? $request->file('cv')->store('cvs', 'public') : null;
|
||
$ndaPath = $request->file('nda') ? $request->file('nda')->store('ndas', 'public') : null;
|
||
$contractPath = $request->file('contract') ? $request->file('contract')->store('contracts', 'public') : null;
|
||
$idPhotocopyPath = $request->file('id_photocopy') ? $request->file('id_photocopy')->store('id_photocopies', 'public') : null;
|
||
|
||
CareerApplication::create([
|
||
'name' => $request->name,
|
||
'email' => $request->email,
|
||
'phone' => $request->phone,
|
||
'type' => $request->type ?? 'job',
|
||
'cv_path' => $cvPath,
|
||
'nda_path' => $ndaPath,
|
||
'contract_path' => $contractPath,
|
||
'id_photocopy_path' => $idPhotocopyPath,
|
||
'git_knowledge' => $request->has('git_knowledge'),
|
||
'ai_usage' => $request->has('ai_usage'),
|
||
'message' => $request->message,
|
||
'status' => 'pending',
|
||
]);
|
||
|
||
if ($request->ajax()) {
|
||
return response()->json([
|
||
'success' => true,
|
||
'message' => __('career.success_message')
|
||
]);
|
||
}
|
||
|
||
return redirect()->back()->with('success', __('career.success_message'));
|
||
}
|
||
|
||
public function internLoginForm()
|
||
{
|
||
if (session()->has('intern_id')) {
|
||
return redirect()->route('intern.dashboard');
|
||
}
|
||
return view('front.career.intern_login', [
|
||
'meta' => [
|
||
'title' => 'Stajyer Girişi',
|
||
'description' => 'İmzalı staj belgelerinize erişmek için lütfen giriş yapın.',
|
||
]
|
||
]);
|
||
}
|
||
|
||
public function internLogin(Request $request)
|
||
{
|
||
$request->validate([
|
||
'username' => 'required|string',
|
||
'password' => 'required|string',
|
||
]);
|
||
|
||
$intern = CareerApplication::where('username', $request->username)
|
||
->where('type', 'internship')
|
||
->first();
|
||
|
||
if (!$intern || !\Illuminate\Support\Facades\Hash::check($request->password, $intern->password)) {
|
||
return redirect()->back()
|
||
->withInput($request->only('username'))
|
||
->withErrors([
|
||
'username' => 'Girdiğiniz kullanıcı adı veya şifre hatalı.',
|
||
]);
|
||
}
|
||
|
||
session(['intern_id' => $intern->id]);
|
||
|
||
return redirect()->route('intern.dashboard')->with('success', 'Başarıyla giriş yapıldı.');
|
||
}
|
||
|
||
public function internDashboard()
|
||
{
|
||
if (!session()->has('intern_id')) {
|
||
return redirect()->route('intern.login')->with('error', 'Lütfen giriş yapın.');
|
||
}
|
||
|
||
$intern = CareerApplication::findOrFail(session('intern_id'));
|
||
$days = self::getInternshipDates($intern->internship_start_date, $intern->internship_total_days);
|
||
$savedEntries = $intern->journalEntries()->get()->keyBy('day_number');
|
||
|
||
return view('front.career.intern_dashboard', [
|
||
'intern' => $intern,
|
||
'days' => $days,
|
||
'savedEntries' => $savedEntries,
|
||
'meta' => [
|
||
'title' => 'Stajyer Paneli',
|
||
'description' => 'Belgelerinizi buradan indirebilirsiniz.',
|
||
]
|
||
]);
|
||
}
|
||
|
||
public function uploadInternshipForm(Request $request)
|
||
{
|
||
if (!session()->has('intern_id')) {
|
||
return redirect()->route('intern.login')->with('error', 'Lütfen önce giriş yapın.');
|
||
}
|
||
|
||
$request->validate([
|
||
'internship_form' => 'required|file|mimes:pdf,docx,jpg,png,jpeg|max:51200',
|
||
'internship_start_date' => 'required|date',
|
||
'internship_total_days' => 'required|integer|min:1',
|
||
], [
|
||
'internship_form.required' => 'Lütfen bir dosya seçin.',
|
||
'internship_form.file' => 'Yüklenen öğe geçerli bir dosya olmalıdır.',
|
||
'internship_form.mimes' => 'Yalnızca PDF, DOCX, JPG ve PNG formatındaki dosyalar kabul edilir.',
|
||
'internship_form.max' => 'Dosya boyutu en fazla 50MB olabilir.',
|
||
'internship_start_date.required' => 'Lütfen staj başlangıç tarihini girin.',
|
||
'internship_start_date.date' => 'Geçerli bir başlangıç tarihi girin.',
|
||
'internship_total_days.required' => 'Lütfen staj süresini girin.',
|
||
'internship_total_days.integer' => 'Staj süresi geçerli bir tam sayı olmalıdır.',
|
||
'internship_total_days.min' => 'Staj süresi en az 1 gün olmalıdır.',
|
||
]);
|
||
|
||
$intern = CareerApplication::findOrFail(session('intern_id'));
|
||
|
||
if ($request->hasFile('internship_form')) {
|
||
// Delete old file if exists
|
||
if ($intern->to_be_signed_internship_form_path) {
|
||
Storage::disk('public')->delete($intern->to_be_signed_internship_form_path);
|
||
}
|
||
|
||
$path = $request->file('internship_form')->store('to_be_signed_interns', 'public');
|
||
|
||
// Calculate end date based on weekdays and duration
|
||
$startDate = \Carbon\Carbon::parse($request->internship_start_date);
|
||
$daysToAdd = intval($request->internship_total_days);
|
||
|
||
$endDate = $startDate->copy();
|
||
$count = 0;
|
||
$temp = $startDate->copy();
|
||
|
||
while ($count < $daysToAdd) {
|
||
if ($temp->isWeekend()) {
|
||
$temp->addDay();
|
||
continue;
|
||
}
|
||
$endDate = $temp->copy();
|
||
$temp->addDay();
|
||
$count++;
|
||
}
|
||
|
||
$intern->update([
|
||
'to_be_signed_internship_form_path' => $path,
|
||
'internship_start_date' => $request->internship_start_date,
|
||
'internship_end_date' => $endDate->format('Y-m-d'),
|
||
'internship_total_days' => $daysToAdd,
|
||
'status' => 'waiting_document',
|
||
]);
|
||
|
||
return redirect()->back()->with('success', 'İmzalanacak staj formunuz ve staj tarihleri başarıyla kaydedildi.');
|
||
}
|
||
|
||
return redirect()->back()->with('error', 'Dosya yüklenirken bir hata oluştu.');
|
||
}
|
||
|
||
public function saveGithubRepo(Request $request)
|
||
{
|
||
if (!session()->has('intern_id')) {
|
||
return redirect()->route('intern.login')->with('error', 'Lütfen önce giriş yapın.');
|
||
}
|
||
|
||
$request->validate([
|
||
'github_repo' => 'required|string|url|max:255',
|
||
], [
|
||
'github_repo.required' => 'Lütfen Github depo URL\'sini girin.',
|
||
'github_repo.url' => 'Geçerli bir URL girilmelidir.',
|
||
'github_repo.max' => 'Github depo URL\'si en fazla 255 karakter olabilir.',
|
||
]);
|
||
|
||
$intern = CareerApplication::findOrFail(session('intern_id'));
|
||
|
||
// Sanitize & format github URL
|
||
$repoUrl = trim($request->github_repo);
|
||
|
||
$intern->update([
|
||
'github_repo' => $repoUrl
|
||
]);
|
||
|
||
return redirect()->back()->with('success', 'Github deposu başarıyla güncellendi.');
|
||
}
|
||
|
||
public function downloadMarkdown()
|
||
{
|
||
if (request()->has('intern_id') && auth()->check() && auth()->user()->hasRole('super_admin')) {
|
||
$internId = request('intern_id');
|
||
} else {
|
||
if (!session()->has('intern_id')) {
|
||
return redirect()->route('intern.login')->with('error', 'Lütfen önce giriş yapın.');
|
||
}
|
||
$internId = session('intern_id');
|
||
}
|
||
|
||
$intern = CareerApplication::findOrFail($internId);
|
||
$repo = $intern->github_repo;
|
||
|
||
if (!$repo) {
|
||
return redirect()->back()->with('error', 'Lütfen önce Github deposunu tanımlayın.');
|
||
}
|
||
|
||
// Parse owner and repo
|
||
// E.g., https://github.com/owner/repo or owner/repo
|
||
$repoClean = str_replace(['https://github.com/', 'http://github.com/', 'https://www.github.com/', 'http://www.github.com/'], '', $repo);
|
||
$repoClean = trim($repoClean, '/');
|
||
$parts = explode('/', $repoClean);
|
||
if (count($parts) < 2) {
|
||
return redirect()->back()->with('error', 'Geçersiz Github depo formatı.');
|
||
}
|
||
$owner = $parts[0];
|
||
$repoName = explode('.', $parts[1])[0]; // Remove .git if exists
|
||
|
||
// Fetch commits
|
||
$url = "https://api.github.com/repos/{$owner}/{$repoName}/commits?per_page=100";
|
||
|
||
$opts = [
|
||
'http' => [
|
||
'method' => 'GET',
|
||
'header' => [
|
||
'User-Agent: PHP-Github-Client',
|
||
]
|
||
]
|
||
];
|
||
$context = stream_context_create($opts);
|
||
$response = @file_get_contents($url, false, $context);
|
||
|
||
if ($response === false) {
|
||
return redirect()->back()->with('error', 'Github API\'den commit bilgileri alınamadı. Deponuzun public olduğundan emin olun.');
|
||
}
|
||
|
||
$commits = json_decode($response, true);
|
||
if (!is_array($commits)) {
|
||
return redirect()->back()->with('error', 'Github API yanıtı çözümlenemedi.');
|
||
}
|
||
|
||
// Sort commits chronological (ascending)
|
||
$commits = array_reverse($commits);
|
||
|
||
// Group commits by date (YYYY-MM-DD)
|
||
$grouped = [];
|
||
foreach ($commits as $c) {
|
||
$dateStr = $c['commit']['author']['date'] ?? '';
|
||
if ($dateStr) {
|
||
$dateOnly = \Carbon\Carbon::parse($dateStr)->format('Y-m-d');
|
||
$grouped[$dateOnly][] = $c;
|
||
}
|
||
}
|
||
|
||
// Sort dates chronological (ascending)
|
||
ksort($grouped);
|
||
|
||
// Generate Markdown content
|
||
$md = "# Staj Günlüğü - " . $intern->name . "\n";
|
||
$md .= "Depo: https://github.com/{$owner}/{$repoName}\n\n";
|
||
|
||
$day = 1;
|
||
foreach ($grouped as $date => $dayCommits) {
|
||
$formattedDate = \Carbon\Carbon::parse($date)->format('d.m.Y');
|
||
$md .= "## {$day}. Gün ({$formattedDate})\n";
|
||
foreach ($dayCommits as $c) {
|
||
$message = trim($c['commit']['message'] ?? '');
|
||
$time = \Carbon\Carbon::parse($c['commit']['author']['date'] ?? '')->format('H:i');
|
||
$hash = substr($c['sha'] ?? '', 0, 7);
|
||
$md .= "- [{$time}] `{$hash}`: {$message}\n";
|
||
}
|
||
$md .= "\n";
|
||
$day++;
|
||
}
|
||
|
||
$fileName = str()->slug($intern->name) . "-staj-gunlugu.md";
|
||
|
||
return response($md, 200, [
|
||
'Content-Type' => 'text/markdown; charset=UTF-8',
|
||
'Content-Disposition' => 'attachment; filename="' . $fileName . '"',
|
||
]);
|
||
}
|
||
|
||
public function internLogout()
|
||
{
|
||
session()->forget('intern_id');
|
||
return redirect()->route('intern.login')->with('success', 'Başarıyla çıkış yapıldı.');
|
||
}
|
||
|
||
public function verifyCertificate($code)
|
||
{
|
||
$application = CareerApplication::where('certificate_code', $code)
|
||
->where('type', 'internship')
|
||
->firstOrFail();
|
||
|
||
$days = self::getInternshipDates($application->internship_start_date, $application->internship_total_days);
|
||
$savedEntries = $application->journalEntries()->get()->keyBy('day_number');
|
||
|
||
return view('front.career.verify', [
|
||
'application' => $application,
|
||
'days' => $days,
|
||
'savedEntries' => $savedEntries,
|
||
'meta' => [
|
||
'title' => 'Staj Bitirme Sertifikası Doğrulama - ' . $application->name,
|
||
'description' => $application->name . ' isimli stajyerimizin staj bitirme sertifikası ve performans raporu doğrulama sayfası.',
|
||
]
|
||
]);
|
||
}
|
||
|
||
public function internAdminLoginForm()
|
||
{
|
||
if (auth()->check() && auth()->user()->hasRole('super_admin')) {
|
||
return redirect()->route('intern.admin.dashboard');
|
||
}
|
||
return view('front.career.admin_login', [
|
||
'meta' => [
|
||
'title' => 'Yönetici Girişi - Staj Takip',
|
||
'description' => 'Stajyerleri yönetmek için giriş yapın.',
|
||
]
|
||
]);
|
||
}
|
||
|
||
public function internAdminLogin(Request $request)
|
||
{
|
||
$request->validate([
|
||
'email' => 'required|email',
|
||
'password' => 'required|string',
|
||
]);
|
||
|
||
if (auth()->attempt($request->only('email', 'password'))) {
|
||
if (auth()->user()->hasRole('super_admin')) {
|
||
return redirect()->route('intern.admin.dashboard')->with('success', 'Yönetici girişi başarıyla gerçekleştirildi.');
|
||
}
|
||
|
||
auth()->logout();
|
||
return redirect()->back()
|
||
->withInput($request->only('email'))
|
||
->withErrors([
|
||
'email' => 'Bu panele erişmek için super_admin yetkinizin olması gerekir.',
|
||
]);
|
||
}
|
||
|
||
return redirect()->back()
|
||
->withInput($request->only('email'))
|
||
->withErrors([
|
||
'email' => 'Girdiğiniz bilgiler eşleşmedi veya hatalı.',
|
||
]);
|
||
}
|
||
|
||
public function internAdminDashboard()
|
||
{
|
||
if (!auth()->check() || !auth()->user()->hasRole('super_admin')) {
|
||
return redirect()->route('intern.admin.login')->with('error', 'Lütfen önce yönetici olarak giriş yapın.');
|
||
}
|
||
|
||
$allInterns = CareerApplication::where('type', 'internship')
|
||
->orderBy('created_at', 'desc')
|
||
->get();
|
||
|
||
$ganttInterns = CareerApplication::where('type', 'internship')
|
||
->where('status', 'accepted')
|
||
->whereNotNull('internship_start_date')
|
||
->whereNotNull('internship_end_date')
|
||
->orderBy('internship_start_date', 'asc')
|
||
->get()
|
||
->map(function ($intern) {
|
||
return [
|
||
'id' => $intern->id,
|
||
'parentId' => null,
|
||
'title' => $intern->name,
|
||
'start' => $intern->internship_start_date,
|
||
'end' => $intern->internship_end_date,
|
||
'progress' => 100
|
||
];
|
||
});
|
||
|
||
return view('front.career.admin_dashboard', [
|
||
'allInterns' => $allInterns,
|
||
'ganttInterns' => $ganttInterns,
|
||
'meta' => [
|
||
'title' => 'Staj Yönetici Paneli',
|
||
'description' => 'Stajyer bilgilerini ve takvimlerini izleyin.',
|
||
]
|
||
]);
|
||
}
|
||
|
||
public function internAdminLogout()
|
||
{
|
||
auth()->logout();
|
||
return redirect()->route('intern.admin.login')->with('success', 'Yönetici oturumu sonlandırıldı.');
|
||
}
|
||
|
||
public static function getInternshipDates($startDate, $totalDays)
|
||
{
|
||
if (!$startDate || !$totalDays || $totalDays <= 0) {
|
||
return [];
|
||
}
|
||
|
||
$dates = [];
|
||
$temp = \Carbon\Carbon::parse($startDate);
|
||
$daysToAdd = intval($totalDays);
|
||
$count = 0;
|
||
|
||
while ($count < $daysToAdd) {
|
||
if ($temp->isWeekend()) {
|
||
$temp->addDay();
|
||
continue;
|
||
}
|
||
$dates[] = [
|
||
'day_number' => $count + 1,
|
||
'date' => $temp->format('Y-m-d'),
|
||
'formatted_date' => $temp->format('d.m.Y'),
|
||
];
|
||
$temp->addDay();
|
||
$count++;
|
||
}
|
||
|
||
return $dates;
|
||
}
|
||
|
||
public function saveJournalEntry(Request $request)
|
||
{
|
||
if (!session()->has('intern_id')) {
|
||
return response()->json(['success' => false, 'message' => 'Lütfen giriş yapın.'], 401);
|
||
}
|
||
|
||
$intern = CareerApplication::findOrFail(session('intern_id'));
|
||
|
||
$request->validate([
|
||
'day_number' => 'required|integer|min:1',
|
||
'date' => 'required|date',
|
||
'content' => 'nullable|string',
|
||
]);
|
||
|
||
$dateObj = \Carbon\Carbon::parse($request->date);
|
||
if ($dateObj->isWeekend()) {
|
||
return response()->json(['success' => false, 'message' => 'Hafta sonu günlerine staj günlüğü girilemez.'], 422);
|
||
}
|
||
|
||
$entry = \App\Models\InternshipJournalEntry::updateOrCreate([
|
||
'career_application_id' => $intern->id,
|
||
'day_number' => $request->day_number,
|
||
'date' => $request->date,
|
||
], [
|
||
'content' => $request->content,
|
||
]);
|
||
|
||
return response()->json([
|
||
'success' => true,
|
||
'message' => $request->day_number . '. Gün kaydı başarıyla kaydedildi.',
|
||
'entry' => $entry
|
||
]);
|
||
}
|
||
|
||
public function printJournal(Request $request)
|
||
{
|
||
if (request()->has('intern_id') && auth()->check() && auth()->user()->hasRole('super_admin')) {
|
||
$internId = request('intern_id');
|
||
} else {
|
||
if (!session()->has('intern_id')) {
|
||
return redirect()->route('intern.login')->with('error', 'Lütfen önce giriş yapın.');
|
||
}
|
||
$internId = session('intern_id');
|
||
}
|
||
|
||
$intern = CareerApplication::findOrFail($internId);
|
||
$size = $request->query('size', 'a4');
|
||
if (!in_array($size, ['a4', 'a5'])) {
|
||
$size = 'a4';
|
||
}
|
||
|
||
$days = self::getInternshipDates($intern->internship_start_date, $intern->internship_total_days);
|
||
$savedEntries = $intern->journalEntries()->get()->keyBy('day_number');
|
||
|
||
return view('front.career.print', [
|
||
'intern' => $intern,
|
||
'days' => $days,
|
||
'savedEntries' => $savedEntries,
|
||
'size' => $size,
|
||
]);
|
||
}
|
||
}
|
||
|