Files
mugladijitalmedya/app/admin/actions.ts

423 lines
14 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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' };
}
}