first commit
This commit is contained in:
10
frontend/app/api/admin/heroes/[id]/route.ts
Normal file
10
frontend/app/api/admin/heroes/[id]/route.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { NextRequest } from "next/server"
|
||||
import { handleImageProxyRequest } from "@/lib/api-proxy"
|
||||
|
||||
export async function PUT(
|
||||
req: NextRequest,
|
||||
context: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await context.params
|
||||
return handleImageProxyRequest(req, `/admin/heroes/${id}`)
|
||||
}
|
||||
6
frontend/app/api/admin/heroes/route.ts
Normal file
6
frontend/app/api/admin/heroes/route.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { NextRequest } from "next/server"
|
||||
import { handleImageProxyRequest } from "@/lib/api-proxy"
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
return handleImageProxyRequest(req, "/admin/heroes")
|
||||
}
|
||||
11
frontend/app/api/admin/posts/[id]/route.ts
Normal file
11
frontend/app/api/admin/posts/[id]/route.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { NextRequest } from "next/server";
|
||||
import { handleImageProxyRequest } from "@/lib/api-proxy";
|
||||
|
||||
export async function PUT(
|
||||
req: NextRequest,
|
||||
context: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await context.params;
|
||||
console.log("API Route PUT called with id:", id);
|
||||
return handleImageProxyRequest(req, `/admin/posts/${id}`);
|
||||
}
|
||||
6
frontend/app/api/admin/posts/route.ts
Normal file
6
frontend/app/api/admin/posts/route.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { NextRequest } from "next/server";
|
||||
import { handleImageProxyRequest } from "@/lib/api-proxy";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
return handleImageProxyRequest(req, "/admin/posts");
|
||||
}
|
||||
10
frontend/app/api/admin/settings/[id]/route.ts
Normal file
10
frontend/app/api/admin/settings/[id]/route.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { NextRequest } from "next/server"
|
||||
import { handleImageProxyRequest } from "@/lib/api-proxy"
|
||||
|
||||
export async function PUT(
|
||||
req: NextRequest,
|
||||
context: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await context.params
|
||||
return handleImageProxyRequest(req, `/admin/settings/${id}`)
|
||||
}
|
||||
6
frontend/app/api/admin/settings/route.ts
Normal file
6
frontend/app/api/admin/settings/route.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { NextRequest } from "next/server"
|
||||
import { handleImageProxyRequest } from "@/lib/api-proxy"
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
return handleImageProxyRequest(req, "/admin/settings")
|
||||
}
|
||||
187
frontend/app/api/auth/[...nextauth]/route.ts
Normal file
187
frontend/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import NextAuth, { NextAuthOptions } from "next-auth";
|
||||
import CredentialsProvider from "next-auth/providers/credentials";
|
||||
import GitHubProvider from "next-auth/providers/github";
|
||||
import GoogleProvider from "next-auth/providers/google";
|
||||
import { JWT } from "next-auth/jwt";
|
||||
|
||||
// Helper to get API URL consistently
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || process.env.BASE_API_URL || "http://localhost:8080/api";
|
||||
|
||||
/**
|
||||
* Refresh token ile yeni access token al
|
||||
*/
|
||||
async function refreshAccessToken(token: JWT) {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/api/v1/auth/refresh`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
refresh_token: token.refreshToken,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to refresh token");
|
||||
}
|
||||
|
||||
const refreshedTokens = await response.json();
|
||||
|
||||
return {
|
||||
...token,
|
||||
accessToken: refreshedTokens.access_token,
|
||||
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken,
|
||||
accessTokenExpires: Date.now() + 15 * 60 * 1000, // 15 dakika (Time should ideally come from backend)
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error refreshing access token:", error);
|
||||
return {
|
||||
...token,
|
||||
error: "RefreshAccessTokenError",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const authOptions: NextAuthOptions = {
|
||||
providers: [
|
||||
CredentialsProvider({
|
||||
name: "Credentials",
|
||||
credentials: {
|
||||
email: { label: "Email", type: "email" },
|
||||
password: { label: "Password", type: "password" },
|
||||
// Optional: used if redirecting from a separate auth flow
|
||||
accessToken: { label: "Access Token", type: "text" },
|
||||
refreshToken: { label: "Refresh Token", type: "text" },
|
||||
},
|
||||
async authorize(credentials) {
|
||||
// 1. External Token Flow (if tokens are passed directly, e.g. from OAuth on backend)
|
||||
if (credentials?.accessToken && credentials?.refreshToken) {
|
||||
try {
|
||||
// Validate token and get user info
|
||||
const meResponse = await fetch(`${API_URL}/api/v1/auth/me`, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${credentials.accessToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!meResponse.ok) return null;
|
||||
|
||||
const userData = await meResponse.json();
|
||||
|
||||
return {
|
||||
id: userData.id?.toString(),
|
||||
email: userData.email,
|
||||
name: userData.username,
|
||||
username: userData.username, // Added to satisfy User interface
|
||||
is_admin: userData.is_admin, // Capture is_admin
|
||||
accessToken: credentials.accessToken,
|
||||
refreshToken: credentials.refreshToken,
|
||||
accessTokenExpires: Date.now() + 15 * 60 * 1000,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Standard Email/Password Flow
|
||||
if (!credentials?.email || !credentials?.password) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/api/v1/auth/login`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: credentials.email,
|
||||
password: credentials.password,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Structure matches user's provided JSON example
|
||||
return {
|
||||
id: data.user.id.toString(),
|
||||
email: data.user.email,
|
||||
name: data.user.username,
|
||||
username: data.user.username, // Added to satisfy User interface
|
||||
is_admin: data.user.is_admin, // Capture is_admin
|
||||
accessToken: data.access_token,
|
||||
refreshToken: data.refresh_token,
|
||||
accessTokenExpires: Date.now() + 15 * 60 * 1000,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Login error:", error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
}),
|
||||
// Keep existing providers if they are configured
|
||||
GitHubProvider({
|
||||
clientId: process.env.GITHUB_CLIENT_ID || "",
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET || "",
|
||||
}),
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID || "",
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
|
||||
}),
|
||||
],
|
||||
pages: {
|
||||
signIn: "/auth/login",
|
||||
signOut: "/auth/login",
|
||||
error: "/auth/login",
|
||||
},
|
||||
callbacks: {
|
||||
async jwt({ token, user }) {
|
||||
// Initial sign in
|
||||
if (user) {
|
||||
token.id = user.id;
|
||||
token.email = user.email;
|
||||
token.name = user.name || undefined;
|
||||
token.username = user.username;
|
||||
token.accessToken = user.accessToken;
|
||||
token.refreshToken = user.refreshToken;
|
||||
token.roles = user.roles;
|
||||
token.is_admin = user.is_admin;
|
||||
token.accessTokenExpires = user.accessTokenExpires;
|
||||
}
|
||||
|
||||
// Return previous token if the access token has not expired yet
|
||||
if (Date.now() < (token.accessTokenExpires as number)) {
|
||||
return token;
|
||||
}
|
||||
|
||||
// Access token has expired, try to update it
|
||||
return refreshAccessToken(token);
|
||||
},
|
||||
async session({ session, token }) {
|
||||
if (token) {
|
||||
session.user.id = token.id as string;
|
||||
session.user.email = token.email as string;
|
||||
session.user.name = token.name as string;
|
||||
session.user.username = token.username as string;
|
||||
session.user.is_admin = token.is_admin as boolean; // Expose is_admin to session
|
||||
session.accessToken = token.accessToken as string;
|
||||
session.user.accessToken = token.accessToken as string;
|
||||
session.error = token.error as string;
|
||||
}
|
||||
return session;
|
||||
},
|
||||
},
|
||||
session: {
|
||||
strategy: "jwt",
|
||||
},
|
||||
secret: process.env.NEXTAUTH_SECRET, // Ensure this matches .env
|
||||
};
|
||||
|
||||
const handler = NextAuth(authOptions);
|
||||
|
||||
export { handler as GET, handler as POST };
|
||||
Reference in New Issue
Block a user