This commit is contained in:
Şahan Hasret
2025-11-21 17:46:30 +03:00
parent c0b7fb463e
commit 76c31274d5
46 changed files with 3675 additions and 1043 deletions

View File

@@ -0,0 +1,73 @@
import { NextRequest, NextResponse } from 'next/server';
import { compare } from 'bcryptjs';
import { prisma } from '@/lib/prisma';
import { encrypt } from '@/lib/auth';
export async function POST(request: NextRequest) {
try {
const { username, password } = await request.json();
if (!username || !password) {
return NextResponse.json(
{ error: 'Kullanıcı adı ve şifre gerekli' },
{ status: 400 }
);
}
// Kullanıcıyı bul
const user = await prisma.user.findUnique({
where: { username },
});
if (!user) {
return NextResponse.json(
{ error: 'Kullanıcı adı veya şifre hatalı' },
{ status: 401 }
);
}
// Şifreyi kontrol et
const isPasswordValid = await compare(password, user.password);
if (!isPasswordValid) {
return NextResponse.json(
{ error: 'Kullanıcı adı veya şifre hatalı' },
{ status: 401 }
);
}
// JWT token oluştur
const token = await encrypt({
userId: user.id.toString(),
username: user.username,
});
// Response oluştur
const response = NextResponse.json(
{
user: {
id: user.id,
username: user.username,
},
},
{ status: 200 }
);
// Cookie'ye token ekle
response.cookies.set('session', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 60 * 24, // 24 saat
path: '/',
});
return response;
} catch (error) {
console.error('Login error:', error);
return NextResponse.json(
{ error: 'Giriş yapılırken bir hata oluştu' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,13 @@
import { NextResponse } from 'next/server';
export async function POST() {
const response = NextResponse.json(
{ message: ıkış başarılı' },
{ status: 200 }
);
// Cookie'yi sil
response.cookies.delete('session');
return response;
}

View File

@@ -0,0 +1,18 @@
import { NextResponse } from 'next/server';
import { getSession } from '@/lib/auth';
export async function GET() {
const session = await getSession();
if (!session) {
return NextResponse.json({ authenticated: false }, { status: 401 });
}
return NextResponse.json({
authenticated: true,
user: {
id: session.userId,
username: session.username,
},
});
}

103
app/api/cameras/route.ts Normal file
View File

@@ -0,0 +1,103 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Tüm kameraları getir
export async function GET() {
try {
const cameras = await prisma.camera.findMany({
orderBy: { order: 'asc' },
});
return NextResponse.json(cameras);
} catch (error) {
console.error('Cameras fetch error:', error);
return NextResponse.json(
{ error: 'Kameralar alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Yeni kamera ekle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const camera = await prisma.camera.create({
data: {
name: data.name,
location: data.location,
videoUrl: data.videoUrl,
status: data.status,
viewers: data.viewers || 0,
order: data.order,
},
});
return NextResponse.json(camera, { status: 201 });
} catch (error) {
console.error('Camera create error:', error);
return NextResponse.json(
{ error: 'Kamera oluşturulurken hata oluştu' },
{ status: 500 }
);
}
});
}
// PUT - Kamera güncelle (Auth gerekli)
export async function PUT(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const camera = await prisma.camera.update({
where: { id: data.id },
data: {
name: data.name,
location: data.location,
videoUrl: data.videoUrl,
status: data.status,
viewers: data.viewers,
order: data.order,
},
});
return NextResponse.json(camera);
} catch (error) {
console.error('Camera update error:', error);
return NextResponse.json(
{ error: 'Kamera güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}
// DELETE - Kamera sil (Auth gerekli)
export async function DELETE(request: NextRequest) {
return withAuth(request, async () => {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
}
await prisma.camera.delete({
where: { id: parseInt(id) },
});
return NextResponse.json({ message: 'Kamera silindi' });
} catch (error) {
console.error('Camera delete error:', error);
return NextResponse.json(
{ error: 'Kamera silinirken hata oluştu' },
{ status: 500 }
);
}
});
}

116
app/api/documents/route.ts Normal file
View File

@@ -0,0 +1,116 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Tüm dokümanları getir
export async function GET() {
try {
const documents = await prisma.document.findMany({
orderBy: { createdAt: 'desc' },
});
return NextResponse.json(documents);
} catch (error) {
console.error('Documents fetch error:', error);
return NextResponse.json(
{ error: 'Dökümanlar alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Yeni döküman ekle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const document = await prisma.document.create({
data: {
title: data.title,
type: data.type,
category: data.category,
downloadUrl: data.fileUrl || data.downloadUrl,
size: data.fileSize || data.size || '0 MB',
description: data.description,
date: new Date().toISOString().split('T')[0],
},
});
return NextResponse.json(document, { status: 201 });
} catch (error) {
console.error('Document create error:', error);
return NextResponse.json(
{ error: 'Döküman oluşturulurken hata oluştu' },
{ status: 500 }
);
}
});
}
// PUT - Döküman güncelle (Auth gerekli)
export async function PUT(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const document = await prisma.document.update({
where: { id: data.id },
data: {
title: data.title,
type: data.type,
category: data.category,
downloadUrl: data.fileUrl || data.downloadUrl,
size: data.fileSize || data.size,
description: data.description,
},
});
return NextResponse.json(document);
} catch (error) {
console.error('Document update error:', error);
return NextResponse.json(
{ error: 'Döküman güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}
// DELETE - Döküman sil (Auth gerekli)
export async function DELETE(request: NextRequest) {
return withAuth(request, async () => {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
console.log('DELETE document - ID:', id);
if (!id) {
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
}
await prisma.document.delete({
where: { id: parseInt(id) },
});
return NextResponse.json({ message: 'Döküman silindi' });
} catch (error: unknown) {
console.error('Document delete error:', error);
// Prisma P2025: Record not found
if (error && typeof error === 'object' && 'code' in error && error.code === 'P2025') {
return NextResponse.json(
{ error: 'Döküman bulunamadı (zaten silinmiş olabilir)' },
{ status: 404 }
);
}
return NextResponse.json(
{ error: 'Döküman silinirken hata oluştu' },
{ status: 500 }
);
}
});
}

97
app/api/faqs/route.ts Normal file
View File

@@ -0,0 +1,97 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Tüm SSS'leri getir
export async function GET() {
try {
const faqs = await prisma.fAQ.findMany({
orderBy: { order: 'asc' },
});
return NextResponse.json(faqs);
} catch (error) {
console.error('FAQs fetch error:', error);
return NextResponse.json(
{ error: 'SSS alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Yeni SSS ekle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const faq = await prisma.fAQ.create({
data: {
question: data.question,
answer: data.answer,
order: data.order,
},
});
return NextResponse.json(faq, { status: 201 });
} catch (error) {
console.error('FAQ create error:', error);
return NextResponse.json(
{ error: 'SSS oluşturulurken hata oluştu' },
{ status: 500 }
);
}
});
}
// PUT - SSS güncelle (Auth gerekli)
export async function PUT(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const faq = await prisma.fAQ.update({
where: { id: data.id },
data: {
question: data.question,
answer: data.answer,
order: data.order,
},
});
return NextResponse.json(faq);
} catch (error) {
console.error('FAQ update error:', error);
return NextResponse.json(
{ error: 'SSS güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}
// DELETE - SSS sil (Auth gerekli)
export async function DELETE(request: NextRequest) {
return withAuth(request, async () => {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
}
await prisma.fAQ.delete({
where: { id: parseInt(id) },
});
return NextResponse.json({ message: 'SSS silindi' });
} catch (error) {
console.error('FAQ delete error:', error);
return NextResponse.json(
{ error: 'SSS silinirken hata oluştu' },
{ status: 500 }
);
}
});
}

View File

@@ -0,0 +1,57 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Aktif canlı yayın bilgisini getir
export async function GET() {
try {
const liveStream = await prisma.liveStream.findFirst({
where: { active: true },
});
return NextResponse.json(liveStream || { active: false, url: '', title: '' });
} catch (error) {
console.error('Live stream fetch error:', error);
return NextResponse.json(
{ error: 'Canlı yayın bilgisi alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Canlı yayın ayarlarını güncelle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
// Önce tüm canlı yayınları pasif yap
await prisma.liveStream.updateMany({
data: { active: false },
});
// Yeni ayarları oluştur veya güncelle
const liveStream = await prisma.liveStream.upsert({
where: { id: data.id || 0 },
update: {
url: data.url,
active: data.active,
title: data.title,
},
create: {
url: data.url,
active: data.active,
title: data.title,
},
});
return NextResponse.json(liveStream);
} catch (error) {
console.error('Live stream update error:', error);
return NextResponse.json(
{ error: 'Canlı yayın güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}

102
app/api/media/route.ts Normal file
View File

@@ -0,0 +1,102 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Tüm medya öğelerini getir
export async function GET() {
try {
const media = await prisma.media.findMany({
orderBy: { createdAt: 'desc' },
});
return NextResponse.json(media);
} catch (error) {
console.error('Media fetch error:', error);
return NextResponse.json(
{ error: 'Medya öğeleri alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Yeni medya öğesi ekle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const media = await prisma.media.create({
data: {
title: data.title,
type: data.type,
thumbnail: data.thumbnail,
videoUrl: data.videoUrl,
description: data.description,
date: new Date().toISOString().split('T')[0],
},
});
return NextResponse.json(media, { status: 201 });
} catch (error) {
console.error('Media create error:', error);
return NextResponse.json(
{ error: 'Medya öğesi oluşturulurken hata oluştu' },
{ status: 500 }
);
}
});
}
// PUT - Medya öğesi güncelle (Auth gerekli)
export async function PUT(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const media = await prisma.media.update({
where: { id: data.id },
data: {
title: data.title,
type: data.type,
thumbnail: data.thumbnail,
videoUrl: data.videoUrl,
description: data.description,
},
});
return NextResponse.json(media);
} catch (error) {
console.error('Media update error:', error);
return NextResponse.json(
{ error: 'Medya öğesi güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}
// DELETE - Medya öğesi sil (Auth gerekli)
export async function DELETE(request: NextRequest) {
return withAuth(request, async () => {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
}
await prisma.media.delete({
where: { id: parseInt(id) },
});
return NextResponse.json({ message: 'Medya öğesi silindi' });
} catch (error) {
console.error('Media delete error:', error);
return NextResponse.json(
{ error: 'Medya öğesi silinirken hata oluştu' },
{ status: 500 }
);
}
});
}

98
app/api/messages/route.ts Normal file
View File

@@ -0,0 +1,98 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Tüm mesajları getir (Auth gerekli)
export async function GET(request: NextRequest) {
return withAuth(request, async () => {
try {
const messages = await prisma.message.findMany({
orderBy: { createdAt: 'desc' },
});
return NextResponse.json(messages);
} catch (error) {
console.error('Messages fetch error:', error);
return NextResponse.json(
{ error: 'Mesajlar alınırken hata oluştu' },
{ status: 500 }
);
}
});
}
// POST - Yeni mesaj gönder (Public - iletişim formu)
export async function POST(request: NextRequest) {
try {
const data = await request.json();
const message = await prisma.message.create({
data: {
name: data.name,
email: data.email,
phone: data.phone || '',
subject: data.subject,
type: data.type || 'contact',
message: data.message,
read: false,
date: new Date().toISOString().split('T')[0],
},
});
return NextResponse.json(message, { status: 201 });
} catch (error) {
console.error('Message create error:', error);
return NextResponse.json(
{ error: 'Mesaj gönderilirken hata oluştu' },
{ status: 500 }
);
}
}
// PUT - Mesajı okundu olarak işaretle (Auth gerekli)
export async function PUT(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const message = await prisma.message.update({
where: { id: data.id },
data: { read: data.read },
});
return NextResponse.json(message);
} catch (error) {
console.error('Message update error:', error);
return NextResponse.json(
{ error: 'Mesaj güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}
// DELETE - Mesaj sil (Auth gerekli)
export async function DELETE(request: NextRequest) {
return withAuth(request, async () => {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
}
await prisma.message.delete({
where: { id: parseInt(id) },
});
return NextResponse.json({ message: 'Mesaj silindi' });
} catch (error) {
console.error('Message delete error:', error);
return NextResponse.json(
{ error: 'Mesaj silinirken hata oluştu' },
{ status: 500 }
);
}
});
}

107
app/api/news/route.ts Normal file
View File

@@ -0,0 +1,107 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Tüm haberleri getir
export async function GET() {
try {
const news = await prisma.news.findMany({
orderBy: { createdAt: 'desc' },
});
return NextResponse.json(news);
} catch (error) {
console.error('News fetch error:', error);
return NextResponse.json(
{ error: 'Haberler alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Yeni haber ekle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const news = await prisma.news.create({
data: {
title: data.title,
summary: data.summary || data.content.substring(0, 150) + '...',
content: data.content,
category: data.category,
image: data.image,
author: data.author,
tags: data.tags || '',
date: new Date().toISOString().split('T')[0],
featured: data.featured || false,
},
});
return NextResponse.json(news, { status: 201 });
} catch (error) {
console.error('News create error:', error);
return NextResponse.json(
{ error: 'Haber oluşturulurken hata oluştu' },
{ status: 500 }
);
}
});
}
// PUT - Haber güncelle (Auth gerekli)
export async function PUT(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const news = await prisma.news.update({
where: { id: data.id },
data: {
title: data.title,
summary: data.summary,
content: data.content,
category: data.category,
image: data.image,
author: data.author,
tags: data.tags,
},
});
return NextResponse.json(news);
} catch (error) {
console.error('News update error:', error);
return NextResponse.json(
{ error: 'Haber güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}
// DELETE - Haber sil (Auth gerekli)
export async function DELETE(request: NextRequest) {
return withAuth(request, async () => {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
}
await prisma.news.delete({
where: { id: parseInt(id) },
});
return NextResponse.json({ message: 'Haber silindi' });
} catch (error) {
console.error('News delete error:', error);
return NextResponse.json(
{ error: 'Haber silinirken hata oluştu' },
{ status: 500 }
);
}
});
}

52
app/api/settings/route.ts Normal file
View File

@@ -0,0 +1,52 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Site ayarlarını getir
export async function GET() {
try {
const settings = await prisma.siteSettings.findFirst({
where: { key: 'main' },
});
if (!settings) {
return NextResponse.json({ error: 'Ayarlar bulunamadı' }, { status: 404 });
}
return NextResponse.json(JSON.parse(settings.value));
} catch (error) {
console.error('Settings fetch error:', error);
return NextResponse.json(
{ error: 'Ayarlar alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Site ayarlarını güncelle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const settings = await prisma.siteSettings.upsert({
where: { key: 'main' },
update: {
value: JSON.stringify(data),
},
create: {
key: 'main',
value: JSON.stringify(data),
},
});
return NextResponse.json(JSON.parse(settings.value));
} catch (error) {
console.error('Settings update error:', error);
return NextResponse.json(
{ error: 'Ayarlar güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}

101
app/api/slider/route.ts Normal file
View File

@@ -0,0 +1,101 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Tüm slider item'ları getir
export async function GET() {
try {
const items = await prisma.sliderItem.findMany({
orderBy: { id: 'asc' },
});
return NextResponse.json(items);
} catch (error) {
console.error('Slider items fetch error:', error);
return NextResponse.json(
{ error: 'Slider items alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Yeni slider item ekle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const item = await prisma.sliderItem.create({
data: {
title: data.title,
description: data.description,
buttonText: data.buttonText,
buttonLink: data.buttonLink,
active: data.active ?? true,
},
});
return NextResponse.json(item, { status: 201 });
} catch (error) {
console.error('Slider item create error:', error);
return NextResponse.json(
{ error: 'Slider item oluşturulurken hata oluştu' },
{ status: 500 }
);
}
});
}
// PUT - Slider item güncelle (Auth gerekli)
export async function PUT(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const item = await prisma.sliderItem.update({
where: { id: data.id },
data: {
title: data.title,
description: data.description,
buttonText: data.buttonText,
buttonLink: data.buttonLink,
active: data.active,
},
});
return NextResponse.json(item);
} catch (error) {
console.error('Slider item update error:', error);
return NextResponse.json(
{ error: 'Slider item güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}
// DELETE - Slider item sil (Auth gerekli)
export async function DELETE(request: NextRequest) {
return withAuth(request, async () => {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
}
await prisma.sliderItem.delete({
where: { id: parseInt(id) },
});
return NextResponse.json({ message: 'Slider item silindi' });
} catch (error) {
console.error('Slider item delete error:', error);
return NextResponse.json(
{ error: 'Slider item silinirken hata oluştu' },
{ status: 500 }
);
}
});
}

101
app/api/stations/route.ts Normal file
View File

@@ -0,0 +1,101 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { withAuth } from '@/lib/auth';
// GET - Tüm metro istasyonlarını getir
export async function GET() {
try {
const stations = await prisma.metroStation.findMany({
orderBy: { order: 'asc' },
});
return NextResponse.json(stations);
} catch (error) {
console.error('Stations fetch error:', error);
return NextResponse.json(
{ error: 'İstasyonlar alınırken hata oluştu' },
{ status: 500 }
);
}
}
// POST - Yeni istasyon ekle (Auth gerekli)
export async function POST(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const station = await prisma.metroStation.create({
data: {
name: data.name,
status: data.status,
progress: data.progress,
order: data.order,
description: data.description || data.estimatedCompletion,
},
});
return NextResponse.json(station, { status: 201 });
} catch (error) {
console.error('Station create error:', error);
return NextResponse.json(
{ error: 'İstasyon oluşturulurken hata oluştu' },
{ status: 500 }
);
}
});
}
// PUT - İstasyon güncelle (Auth gerekli)
export async function PUT(request: NextRequest) {
return withAuth(request, async () => {
try {
const data = await request.json();
const station = await prisma.metroStation.update({
where: { id: data.id },
data: {
name: data.name,
status: data.status,
progress: data.progress,
order: data.order,
description: data.description || data.estimatedCompletion,
},
});
return NextResponse.json(station);
} catch (error) {
console.error('Station update error:', error);
return NextResponse.json(
{ error: 'İstasyon güncellenirken hata oluştu' },
{ status: 500 }
);
}
});
}
// DELETE - İstasyon sil (Auth gerekli)
export async function DELETE(request: NextRequest) {
return withAuth(request, async () => {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
}
await prisma.metroStation.delete({
where: { id: parseInt(id) },
});
return NextResponse.json({ message: 'İstasyon silindi' });
} catch (error) {
console.error('Station delete error:', error);
return NextResponse.json(
{ error: 'İstasyon silinirken hata oluştu' },
{ status: 500 }
);
}
});
}