Cleaned up project. Moved backend logic to FastAPI. Changed login/register routes to use FastAPI
This commit is contained in:
@ -1,7 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { login } from '../../../../../src/controllers/authController'; // Import the login function from authController
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
// Delegate the request to the login function in the controller
|
||||
return login(req);
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import bcrypt from 'bcrypt';
|
||||
import prisma from '../../../models/prismaClient';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.json();
|
||||
console.log('Request Body:', body); // Log the request body
|
||||
|
||||
const { name, username, email, password, role, company, address, phone, privatePhone, cvr } = body;
|
||||
|
||||
// Check if the username already exists
|
||||
const existingUserByUsername = await prisma.user.findUnique({
|
||||
where: { username },
|
||||
});
|
||||
if (existingUserByUsername) {
|
||||
console.log('Username already exists');
|
||||
return NextResponse.json({ error: 'Username already exists' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Check if the email already exists
|
||||
const existingUserByEmail = await prisma.user.findUnique({
|
||||
where: { email },
|
||||
});
|
||||
if (existingUserByEmail) {
|
||||
console.log('Email already exists');
|
||||
return NextResponse.json({ error: 'Email already exists' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Hash the password
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
// Create the user
|
||||
const newUser = await prisma.user.create({
|
||||
data: {
|
||||
name,
|
||||
username,
|
||||
email,
|
||||
password: hashedPassword,
|
||||
role,
|
||||
address,
|
||||
phone,
|
||||
company: role === 'BUSINESS' ? company : null,
|
||||
privatePhone: role === 'BUSINESS' ? privatePhone : null,
|
||||
cvr: role === 'BUSINESS' ? cvr : null,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('User created successfully:', newUser);
|
||||
return NextResponse.json({ user: newUser }, { status: 201 });
|
||||
|
||||
} catch (error) {
|
||||
// Check if the error is an instance of Error and log the details
|
||||
if (error instanceof Error) {
|
||||
console.error('Error message:', error.message);
|
||||
console.error('Full error stack:', error.stack);
|
||||
} else {
|
||||
console.error('Unknown error:', error); // Log if the error is not of type `Error`
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
26
src/app/api/login/route.ts
Normal file
26
src/app/api/login/route.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.json();
|
||||
|
||||
// Forward request to FastAPI login endpoint
|
||||
const res = await fetch(`${process.env.API_URL}/api/v1/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const error = await res.json();
|
||||
return NextResponse.json({ error: error.detail }, { status: res.status });
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
return NextResponse.json(data);
|
||||
} catch (error) {
|
||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
27
src/app/api/register/route.ts
Normal file
27
src/app/api/register/route.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.json(); // Extract the request body
|
||||
|
||||
// Forward the registration request to your FastAPI backend
|
||||
const response = await fetch(`${process.env.API_URL}/api/v1/register`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
return NextResponse.json({ error: data.detail || 'Failed to register' }, { status: response.status });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: 'User registered successfully', user: data }, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Error during registration:', error);
|
||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@ -1,91 +1,62 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useRouter } from 'next/navigation'; // Use next/navigation for App Router
|
||||
|
||||
const LoginPage = () => {
|
||||
const [username, setUsername] = useState('');
|
||||
export default function LoginPage() {
|
||||
const [userInput, setUserInput] = useState(''); // Accept either username or email
|
||||
const [password, setPassword] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const router = useRouter();
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError('');
|
||||
|
||||
const res = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
|
||||
// Check if the response has a body to parse
|
||||
let data = null;
|
||||
|
||||
try {
|
||||
data = await res.json();
|
||||
} catch (error) {
|
||||
// If the response body is empty or not valid JSON, handle it gracefully
|
||||
console.error('Error parsing response JSON:', error);
|
||||
}
|
||||
|
||||
// Handle successful login
|
||||
if (res.ok && data?.token) {
|
||||
localStorage.setItem('token', data.token); // Store JWT token in localStorage
|
||||
router.push('/'); // Redirect to a protected page (e.g., dashboard)
|
||||
} else {
|
||||
// Handle login errors, ensuring data is valid
|
||||
setError(data?.error || 'Failed to log in');
|
||||
const res = await fetch('/api/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user_input: userInput,
|
||||
password,
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
localStorage.setItem('access_token', data.access_token); // Store the access token
|
||||
router.push('/'); // Redirect on successful login
|
||||
} else {
|
||||
const errorData = await res.json();
|
||||
setError(errorData.detail || 'Login failed');
|
||||
}
|
||||
} catch (err) {
|
||||
setError('An unexpected error occurred.');
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex justify-center items-center h-screen bg-gray-100">
|
||||
<div className="bg-white p-6 rounded-lg shadow-md w-96">
|
||||
<h2 className="text-2xl font-bold mb-4">Login</h2>
|
||||
|
||||
{error && <p className="text-red-500 mb-4">{error}</p>}
|
||||
|
||||
<form onSubmit={handleLogin}>
|
||||
<div className="mb-4">
|
||||
<label htmlFor="username" className="block text-sm font-medium text-gray-700">
|
||||
Username
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
className="mt-1 p-2 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="mt-1 p-2 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Login</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input
|
||||
type="text"
|
||||
value={userInput}
|
||||
onChange={(e) => setUserInput(e.target.value)}
|
||||
placeholder="Username or Email"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder="Password"
|
||||
/>
|
||||
{error && <p>{error}</p>}
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
}
|
||||
@ -38,7 +38,7 @@ const RegisterPage = () => {
|
||||
|
||||
console.log('Submitting user data:', userData); // Log form data before submission
|
||||
|
||||
const res = await fetch('/api/auth/register', {
|
||||
const res = await fetch('/api/register', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import bcrypt from 'bcrypt';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import prisma from '../app/models/prismaClient';
|
||||
import { SECRET_KEY } from '../config/config'; // Load from config.ts or directly from process.env
|
||||
|
||||
export async function login(req: NextRequest) {
|
||||
try {
|
||||
// Parse the request body
|
||||
const body = await req.json();
|
||||
const { username, password } = body;
|
||||
|
||||
// Find the user by username
|
||||
const user = await prisma.user.findUnique({ where: { username } });
|
||||
|
||||
// If user not found or password is incorrect, return an error
|
||||
if (!user || !(await bcrypt.compare(password, user.password))) {
|
||||
return NextResponse.json({ error: 'Invalid credentials' }, { status: 401 });
|
||||
}
|
||||
|
||||
// Ensure SECRET_KEY is defined
|
||||
if (!SECRET_KEY) {
|
||||
console.error('SECRET_KEY is missing');
|
||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
|
||||
// Generate JWT token with user ID
|
||||
const token = jwt.sign({ userId: user.id }, SECRET_KEY, { expiresIn: '1h' });
|
||||
|
||||
// Return the token in the response
|
||||
return NextResponse.json({ token }, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
import { NextApiRequest, NextApiResponse, NextApiHandler } from 'next';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { SECRET_KEY } from '../config/config';
|
||||
|
||||
const authMiddleware = (handler: NextApiHandler) => {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const token = req.headers.authorization?.split(' ')[1];
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({ error: 'No token provided' });
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, SECRET_KEY);
|
||||
(req as any).user = decoded;
|
||||
return handler(req, res);
|
||||
} catch (error) {
|
||||
return res.status(401).json({ error: 'Invalid token' });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default authMiddleware;
|
||||
Reference in New Issue
Block a user