first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 22:04:35 +03:00
commit 763b147cc3
199 changed files with 29356 additions and 0 deletions

199
server/api/auth/[...].ts Normal file
View File

@@ -0,0 +1,199 @@
// file: ~/server/api/auth/[...].ts
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { NuxtAuthHandler } from '#auth'
import CredentialsProvider from 'next-auth/providers/credentials';
import GithubProvider from 'next-auth/providers/github'
import GoogleProvider from 'next-auth/providers/google';
export default NuxtAuthHandler({
// @ts-ignore
secret: useRuntimeConfig().authSecret,
providers: [
// @ts-expect-error
GithubProvider.default({
clientId: useRuntimeConfig().githubClientId,
clientSecret: useRuntimeConfig().githubClientSecret
}),
// @ts-expect-error
GoogleProvider.default({
clientId: useRuntimeConfig().googleClientId,
clientSecret: useRuntimeConfig().googleClientSecret
}),
// @ts-expect-error
CredentialsProvider.default({
name: 'credentials',
credentials: {
email: { label: 'email', type: 'email' },
password: { type: 'password', label: 'password' }
},
async authorize(credentials: { email: string; password: string } | undefined) {
if (!credentials) return null;
const config = useRuntimeConfig();
const apiUrl = config.public.BASE_API_URL || 'http://127.0.0.1:8000';
try {
const tokenResponse = await fetch(`${apiUrl}/api/v1/auth/jwt/create/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: credentials.email,
password: credentials.password
})
});
if (!tokenResponse.ok) {
return null;
}
const tokenData = await tokenResponse.json();
const { access, refresh } = tokenData;
const userResponse = await fetch(`${apiUrl}/api/v1/auth/users/me/`, {
headers: {
'Authorization': `Bearer ${access}`
}
});
if (!userResponse.ok) {
return null;
}
const userData = await userResponse.json();
// Return a user object with tokens and user data
return {
...userData,
accessToken: access,
refreshToken: refresh
};
} catch (error) {
console.error('Authorize error:', error);
return null;
}
}
})
],
callbacks: {
// @ts-ignore
jwt: async ({ token, user, account }) => {
// The `user` object is from the `authorize` callback.
if (user) {
// @ts-ignore
token.id = user.id;
// @ts-ignore
token.email = user.email;
// @ts-ignore
token.name = user.name;
// @ts-ignore
token.role = user.role;
// @ts-ignore
token.image = user.image;
// @ts-ignore
token.is_active = user.is_active;
// Persist the tokens in the JWT
// @ts-ignore
token.accessToken = user.accessToken;
// @ts-ignore
token.refreshToken = user.refreshToken;
}
// Social login: exchange provider access_token for backend JWT tokens
// This runs only on initial sign-in where `account` is present.
if (
account &&
(account.provider === 'google' || account.provider === 'github') &&
// @ts-ignore
account.access_token
) {
try {
const config = useRuntimeConfig();
const apiUrl = config.public.BASE_API_URL || 'http://127.0.0.1:8000';
const endpoint =
account.provider === 'google'
? `${apiUrl}/api/v1/auth/social/google-oauth2/`
: `${apiUrl}/api/v1/auth/social/github/`;
// @ts-ignore
const accessToken = account.access_token;
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ access_token: accessToken }),
});
if (response.ok) {
const data = await response.json();
// Expected shape (per docs): { access, refresh, user }
// Persist backend JWTs on token so client can call protected APIs.
// @ts-ignore
token.accessToken = data.access;
// @ts-ignore
token.refreshToken = data.refresh;
if (data.user) {
// @ts-ignore
token.id = data.user.id ?? token.id;
// @ts-ignore
token.email = data.user.email ?? token.email;
// @ts-ignore
token.name =
(data.user.name ??
[data.user.first_name, data.user.last_name].filter(Boolean).join(' ')) ||
token.name;
// @ts-ignore
token.image = data.user.image ?? token.image;
// @ts-ignore
token.role = data.user.role ?? token.role;
// @ts-ignore
token.is_active = data.user.is_active ?? token.is_active;
}
} else {
const text = await response.text().catch(() => '');
console.error('Social token exchange failed:', response.status, text);
}
} catch (e) {
console.error('Social token exchange error:', e);
}
}
return token;
},
// @ts-ignore
session: async ({ session, token }) => {
if (token && session.user) {
// @ts-ignore
session.user.id = token.id;
// @ts-ignore
session.user.name = token.name;
// @ts-ignore
session.user.role = token.role;
// @ts-ignore
session.user.email = token.email;
// @ts-ignore
session.user.image = token.image;
// @ts-ignore
session.user.is_active = token.is_active;
}
// Expose backend JWTs to the client session (optional but useful)
// @ts-ignore
session.accessToken = token.accessToken;
// @ts-ignore
session.refreshToken = token.refreshToken;
return session;
},
},
// Disable verbose NextAuth logs to avoid DEBUG_ENABLED warning
// @ts-ignore
debug: false,
pages: {
signIn: '/auth/login'
},
session: {
strategy: 'jwt'
}
})

View File

@@ -0,0 +1,120 @@
// http://127.0.0.1:8000/api/v1/contact/create/
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
const apiUrl = config.public.BASE_API_URL || 'http://127.0.0.1:8000';
// Backend credentials
const BACKEND_EMAIL = config.backendEmail || 'admin@example.com';
const BACKEND_PASSWORD = config.backendPassword || 'admin123';
try {
// Form verilerini al
const body = await readBody(event);
// Gerekli alanları kontrol et
const { name, email, subject, message } = body;
if (!name || !email || !subject || !message) {
throw createError({
statusCode: 400,
statusMessage: 'Tüm alanlar zorunludur'
});
}
// Client IP adresini al
const ip = getRequestIP(event, { xForwardedFor: true }) || 'unknown';
// 1. Önce backend'e login ol
let loginResponse;
try {
loginResponse = await $fetch(`${apiUrl}/api/v1/auth/jwt/create/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: {
email: BACKEND_EMAIL,
password: BACKEND_PASSWORD
}
});
} catch (loginError: any) {
// Detaylı hatayı sadece console'da göster
console.error('Backend login error:', {
status: loginError?.status,
statusText: loginError?.statusText,
message: loginError?.message
});
throw createError({
statusCode: 503,
statusMessage: 'Servis geçici olarak kullanılamıyor. Lütfen daha sonra tekrar deneyin.'
});
}
// @ts-expect-error - API response type
const accessToken = loginResponse?.access;
if (!accessToken) {
console.error('No access token received from backend');
throw createError({
statusCode: 503,
statusMessage: 'Servis geçici olarak kullanılamıyor. Lütfen daha sonra tekrar deneyin.'
});
}
// 2. Token ile contact form'u post et (IP adresi ile birlikte)
let contactResponse;
try {
contactResponse = await $fetch(`${apiUrl}/api/v1/contact/create/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
},
body: {
name,
email,
ip,
subject,
message
}
});
} catch (contactError: any) {
// Detaylı hatayı sadece console'da göster
console.error('Contact form submission error:', {
status: contactError?.status,
statusText: contactError?.statusText,
message: contactError?.message
});
throw createError({
statusCode: 500,
statusMessage: 'Mesaj gönderilemedi. Lütfen daha sonra tekrar deneyin.'
});
}
return {
success: true,
data: contactResponse,
message: 'Mesajınız başarıyla gönderildi'
};
} catch (error: any) {
// Eğer zaten createError ile oluşturulmuş bir hata ise, direkt fırlat
if (error.statusCode) {
throw error;
}
// Beklenmeyen hatalar için
console.error('Unexpected contact form error:', error);
throw createError({
statusCode: 500,
statusMessage: 'Bir hata oluştu. Lütfen daha sonra tekrar deneyin.'
});
}
});