Cleaned up project. Moved backend logic to FastAPI. Changed login/register routes to use FastAPI

This commit is contained in:
2024-10-12 22:12:08 +00:00
parent eddd1d8ef7
commit 97bce587d2
154 changed files with 1389 additions and 2658 deletions

View File

@ -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);
}

View File

@ -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 });
}
}

View 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 });
}
}

View 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 });
}
}

View File

@ -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;
}

View File

@ -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',

View File

@ -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 });
}
}

View File

@ -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;