'use server'; import sql from '@/lib/db'; import { cookies } from 'next/headers'; import { redirect } from 'next/navigation'; import { uploadToCloudinary } from '@/lib/cloudinary'; import crypto from 'crypto'; function hashPassword(password: string): string { return crypto.createHash('sha256').update(password).digest('hex'); } export async function ensureAdminsTable() { try { await sql` CREATE TABLE IF NOT EXISTS admins ( id SERIAL PRIMARY KEY, username VARCHAR(100) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) `; const result = await sql`SELECT count(*) FROM admins`; if (Number(result[0].count) === 0) { const defaultPass = hashPassword(process.env.ADMIN_PASSWORD || 'admin123'); await sql` INSERT INTO admins (username, password) VALUES ('admin', ${defaultPass}) `; console.log("Admins table seeded with default user 'admin'"); } // Add is_featured column to partners table if it doesn't exist await sql` ALTER TABLE partners ADD COLUMN IF NOT EXISTS is_featured BOOLEAN DEFAULT false `; } catch (e) { console.error("Error ensuring admins table:", e); } } export async function login(prevState: any, formData: FormData) { try { await ensureAdminsTable(); const username = (formData.get('username') as string || 'admin').trim(); const password = formData.get('password') as string; const hashed = hashPassword(password); const users = await sql` SELECT * FROM admins WHERE username = ${username} AND password = ${hashed} `; if (users.length > 0) { const cookieStore = await cookies(); cookieStore.set('admin_session', 'authenticated', { httpOnly: true, secure: process.env.NODE_ENV === 'production', maxAge: 60 * 60 * 24 * 7, // 1 week path: '/', }); cookieStore.set('admin_user', username, { httpOnly: true, secure: process.env.NODE_ENV === 'production', maxAge: 60 * 60 * 24 * 7, path: '/', }); redirect('/admin'); } return { error: 'Hatalı kullanıcı adı veya şifre' }; } catch (e: any) { console.error("Login error:", e); return { error: 'Giriş sırasında hata oluştu: ' + (e.message || '') }; } } export async function logout() { const cookieStore = await cookies(); cookieStore.delete('admin_session'); cookieStore.delete('admin_user'); redirect('/admin/login'); } export async function getDashboardStats() { try { const [leadsCount] = await sql`SELECT count(*) FROM leads`; const [projectsCount] = await sql`SELECT count(*) FROM projects`; const [servicesCount] = await sql`SELECT count(*) FROM services`; return { leads: Number(leadsCount.count), projects: Number(projectsCount.count), services: Number(servicesCount.count), }; } catch (e) { return { leads: 0, projects: 0, services: 0 }; } } export async function getLeadsAdmin() { try { return await sql`SELECT * FROM leads ORDER BY created_at DESC`; } catch (e) { return []; } } export async function deleteLead(id: number) { try { await sql`DELETE FROM leads WHERE id = ${id}`; return { success: true }; } catch (e) { return { error: 'Silinemedi' }; } } export async function updateSettings(formData: FormData) { try { const data = { site_name: formData.get('site_name') as string, site_description: formData.get('site_description') as string, office_address: formData.get('office_address') as string, contact_email: formData.get('contact_email') as string, contact_phone: formData.get('contact_phone') as string, instagram_url: formData.get('instagram_url') as string, twitter_url: formData.get('twitter_url') as string, linkedin_url: formData.get('linkedin_url') as string, status_badge_text: formData.get('status_badge_text') as string, }; await sql` UPDATE settings SET site_name = ${data.site_name}, site_description = ${data.site_description}, office_address = ${data.office_address}, contact_email = ${data.contact_email}, contact_phone = ${data.contact_phone}, instagram_url = ${data.instagram_url}, twitter_url = ${data.twitter_url}, linkedin_url = ${data.linkedin_url}, status_badge_text = ${data.status_badge_text}, updated_at = CURRENT_TIMESTAMP WHERE id = 1 `; return { success: true }; } catch (e) { return { error: 'Güncellenemedi' }; } } export async function getProjectsAdmin() { try { return await sql`SELECT * FROM projects ORDER BY created_at DESC`; } catch (e) { return []; } } export async function getProjectByIdAdmin(id: number) { try { const result = await sql`SELECT * FROM projects WHERE id = ${id}`; return result[0]; } catch (e) { return null; } } export async function deleteProject(id: number) { try { await sql`DELETE FROM projects WHERE id = ${id}`; return { success: true }; } catch (e) { return { error: 'Silinemedi' }; } } export async function createProjectAdmin(formData: FormData) { try { const slug = formData.get('slug') as string; const title = formData.get('title') as string; const subtitle = formData.get('subtitle') as string; const year = formData.get('year') as string; const hero_image = formData.get('hero_image') as string; const client = formData.get('client') as string; const role = formData.get('role') as string; const location = formData.get('location') as string; const narrative_title = formData.get('narrative_title') as string; const narrative_desc = formData.get('narrative_desc') as string; const is_featured = formData.get('is_featured') === 'on'; const categoriesRaw = formData.getAll('category') as string[]; const techStackRaw = formData.get('tech_stack') as string; const galleryRaw = formData.get('gallery') as string; const category = JSON.stringify(categoriesRaw.filter(Boolean)); const tech_stack = JSON.stringify(techStackRaw ? techStackRaw.split(/[\n,]/).map(s => s.trim()).filter(Boolean) : []); const gallery = JSON.stringify(galleryRaw ? galleryRaw.split(/[\n,]/).map(s => s.trim()).filter(Boolean) : []); await sql` INSERT INTO projects ( slug, title, subtitle, category, year, hero_image, client, role, location, narrative_title, narrative_desc, is_featured, tech_stack, gallery ) VALUES ( ${slug}, ${title}, ${subtitle}, ${category}::jsonb, ${year}, ${hero_image}, ${client}, ${role}, ${location}, ${narrative_title}, ${narrative_desc}, ${is_featured}, ${tech_stack}::jsonb, ${gallery}::jsonb ) `; return { success: true }; } catch (e: any) { console.error('Error creating project:', e); return { error: 'Ekleme başarısız: ' + (e.message || 'Bilinmeyen hata') }; } } export async function updateProjectAdmin(id: number, formData: FormData) { try { const slug = formData.get('slug') as string; const title = formData.get('title') as string; const subtitle = formData.get('subtitle') as string; const year = formData.get('year') as string; const hero_image = formData.get('hero_image') as string; const client = formData.get('client') as string; const role = formData.get('role') as string; const location = formData.get('location') as string; const narrative_title = formData.get('narrative_title') as string; const narrative_desc = formData.get('narrative_desc') as string; const is_featured = formData.get('is_featured') === 'on'; const categoriesRaw = formData.getAll('category') as string[]; const techStackRaw = formData.get('tech_stack') as string; const galleryRaw = formData.get('gallery') as string; const category = JSON.stringify(categoriesRaw.filter(Boolean)); const tech_stack = JSON.stringify(techStackRaw ? techStackRaw.split(/[\n,]/).map(s => s.trim()).filter(Boolean) : []); const gallery = JSON.stringify(galleryRaw ? galleryRaw.split(/[\n,]/).map(s => s.trim()).filter(Boolean) : []); await sql` UPDATE projects SET slug = ${slug}, title = ${title}, subtitle = ${subtitle}, category = ${category}::jsonb, year = ${year}, hero_image = ${hero_image}, client = ${client}, role = ${role}, location = ${location}, narrative_title = ${narrative_title}, narrative_desc = ${narrative_desc}, is_featured = ${is_featured}, tech_stack = ${tech_stack}::jsonb, gallery = ${gallery}::jsonb WHERE id = ${id} `; return { success: true }; } catch (e: any) { console.error('Error updating project:', e); return { error: 'Güncelleme başarısız: ' + (e.message || 'Bilinmeyen hata') }; } } export async function getServicesAdmin() { try { return await sql`SELECT * FROM services ORDER BY display_order ASC`; } catch (e) { return []; } } export async function deleteService(id: number) { try { await sql`DELETE FROM services WHERE id = ${id}`; return { success: true }; } catch (e) { return { error: 'Silinemedi' }; } } export async function getPartnersAdmin() { try { return await sql`SELECT * FROM partners ORDER BY display_order ASC`; } catch (e) { return []; } } export async function deletePartner(id: number) { try { await sql`DELETE FROM partners WHERE id = ${id}`; return { success: true }; } catch (e) { return { error: 'Silinemedi' }; } } export async function createPartnerAdmin(formData: FormData) { try { const name = formData.get('name') as string; const logoFile = formData.get('logo') as File; let logoUrl = ''; if (logoFile && logoFile.size > 0) { logoUrl = await uploadToCloudinary(logoFile, 'partners'); } const display_order = Number(formData.get('display_order')) || 0; await sql` INSERT INTO partners (name, logo, display_order) VALUES (${name}, ${logoUrl}, ${display_order}) `; return { success: true }; } catch (e: any) { console.error('Error creating partner:', e); return { error: 'Ekleme başarısız: ' + (e.message || 'Bilinmeyen hata') }; } } export async function updatePartner(id: number, name: string, display_order: number) { try { await sql` UPDATE partners SET name = ${name}, display_order = ${display_order} WHERE id = ${id} `; return { success: true }; } catch (e) { return { error: 'Güncellenemedi' }; } } export async function getAdminsAdmin() { try { await ensureAdminsTable(); return await sql`SELECT id, username, created_at FROM admins ORDER BY id ASC`; } catch (e) { console.error("Error getting admins:", e); return []; } } export async function createAdminAdmin(formData: FormData) { try { await ensureAdminsTable(); const username = (formData.get('username') as string).trim(); const password = formData.get('password') as string; if (!username || !password) { return { error: 'Kullanıcı adı ve şifre gereklidir.' }; } const hashed = hashPassword(password); await sql` INSERT INTO admins (username, password) VALUES (${username}, ${hashed}) `; return { success: true }; } catch (e: any) { console.error('Error creating admin:', e); if (e.message?.includes('unique constraint')) { return { error: 'Bu kullanıcı adı zaten alınmış.' }; } return { error: 'Ekleme başarısız: ' + (e.message || 'Bilinmeyen hata') }; } } export async function updateAdminPassword(id: number, newPassword: string) { try { await ensureAdminsTable(); if (!newPassword || newPassword.length < 4) { return { error: 'Şifre en az 4 karakter olmalıdır.' }; } const hashed = hashPassword(newPassword); await sql` UPDATE admins SET password = ${hashed} WHERE id = ${id} `; return { success: true }; } catch (e: any) { console.error('Error updating admin password:', e); return { error: 'Şifre güncellenemedi.' }; } } export async function deleteAdminAdmin(id: number) { try { await ensureAdminsTable(); // Prevent deleting the last remaining admin const adminsCount = await sql`SELECT count(*) FROM admins`; if (Number(adminsCount[0].count) <= 1) { return { error: 'Sistemde en az bir yönetici bulunmalıdır. Son yönetici silinemez!' }; } await sql` DELETE FROM admins WHERE id = ${id} `; return { success: true }; } catch (e) { console.error('Error deleting admin:', e); return { error: 'Silinemedi.' }; } } export async function getCurrentAdmin() { const cookieStore = await cookies(); return cookieStore.get('admin_user')?.value || 'admin'; } export async function togglePartnerFeatured(id: number, isFeatured: boolean) { try { await sql` UPDATE partners SET is_featured = ${isFeatured} WHERE id = ${id} `; return { success: true }; } catch (e) { console.error('Error toggling partner featured:', e); return { error: 'Öne çıkarma durumu güncellenemedi' }; } }