feat: add multi-user admin panel and featured partners toggle on home page
This commit is contained in:
@@ -3,25 +3,84 @@
|
||||
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) {
|
||||
const password = formData.get('password') as string;
|
||||
if (password === process.env.ADMIN_PASSWORD) {
|
||||
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: '/',
|
||||
});
|
||||
redirect('/admin');
|
||||
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 || '') };
|
||||
}
|
||||
return { error: 'Hatalı şifre' };
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete('admin_session');
|
||||
cookieStore.delete('admin_user');
|
||||
redirect('/admin/login');
|
||||
}
|
||||
|
||||
@@ -231,12 +290,18 @@ export async function deletePartner(id: number) {
|
||||
export async function createPartnerAdmin(formData: FormData) {
|
||||
try {
|
||||
const name = formData.get('name') as string;
|
||||
const logo = formData.get('logo') 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}, ${logo}, ${display_order})
|
||||
VALUES (${name}, ${logoUrl}, ${display_order})
|
||||
`;
|
||||
return { success: true };
|
||||
} catch (e: any) {
|
||||
@@ -258,3 +323,100 @@ export async function updatePartner(id: number, name: string, display_order: num
|
||||
}
|
||||
}
|
||||
|
||||
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' };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user