first commit
This commit is contained in:
199
server/api/auth/[...].ts
Normal file
199
server/api/auth/[...].ts
Normal 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'
|
||||
}
|
||||
})
|
||||
120
server/api/contact/post.create.ts
Normal file
120
server/api/contact/post.create.ts
Normal 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.'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user