Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions backend/auth-test-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import express from "express";
import cors from "cors";
import cookieParser from 'cookie-parser';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import "dotenv/config";

const app = express();
const port = 4000;

// Middleware
app.use(express.json());
app.use(cookieParser());
app.use(cors({
origin: ["http://localhost:5173", "http://localhost:3000"],
credentials: true
}));

// Simple in-memory user storage for testing (replace with DB later)
let users = [];

const generateToken = (id) => {
return jwt.sign({ id }, process.env.JWT_SECRET || "fallback-secret", { expiresIn: '7d' });
};

// Test registration endpoint
app.post('/api/auth/register', async (req, res) => {
try {
const { name, email, password } = req.body;

console.log('πŸ“ Registration attempt:', { name, email, passwordLength: password?.length });

// Validate required fields
if (!name || !email || !password) {
console.log('❌ Missing required fields');
return res.status(400).json({ message: 'All fields are required' });
}

// Check if user already exists (in memory)
const userExists = users.find(user => user.email === email);
if (userExists) {
console.log('❌ User already exists:', email);
return res.status(400).json({ message: 'User already exists' });
}

// Hash password
const hashedPassword = await bcrypt.hash(password, 10);

// Create user (in memory)
const newUser = {
_id: Date.now().toString(),
name,
email,
password: hashedPassword,
createdAt: new Date()
};

users.push(newUser);
console.log('βœ… User created successfully:', email);

// Generate JWT
const token = generateToken(newUser._id);

// Set cookie
res.cookie('token', token, {
httpOnly: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000,
});

// Return success
res.status(201).json({
user: { _id: newUser._id, name: newUser.name, email: newUser.email },
token: token,
message: 'Registration successful',
});

} catch (error) {
console.error('πŸ’₯ Registration error:', error);
res.status(500).json({
message: 'Server error during registration',
error: error.message
});
}
});

// Test login endpoint
app.post('/api/auth/login', async (req, res) => {
try {
const { email, password } = req.body;

console.log('πŸ“ Login attempt:', { email });

if (!email || !password) {
return res.status(400).json({ message: 'Email and password are required' });
}

// Find user (in memory)
const user = users.find(u => u.email === email);
if (!user) {
console.log('❌ User not found:', email);
return res.status(401).json({ message: 'Invalid email or password' });
}

// Compare password
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
console.log('❌ Invalid password for:', email);
return res.status(401).json({ message: 'Invalid email or password' });
}

// Generate JWT
const token = generateToken(user._id);

// Set cookie
res.cookie('token', token, {
httpOnly: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000,
});

console.log('βœ… Login successful:', email);

res.json({
user: { _id: user._id, name: user.name, email: user.email },
token: token,
message: 'Login successful',
});

} catch (error) {
console.error('πŸ’₯ Login error:', error);
res.status(500).json({
message: 'Server error during login',
error: error.message
});
}
});

// Test endpoint
app.get('/', (req, res) => {
res.json({
message: 'πŸš€ Test Auth Server is working!',
users: users.length,
timestamp: new Date().toISOString()
});
});

// Get all users (for testing)
app.get('/api/users', (req, res) => {
res.json({
users: users.map(u => ({ id: u._id, name: u.name, email: u.email })),
count: users.length
});
});

app.listen(port, () => {
console.log(`πŸ§ͺ Test server running on port ${port}`);
console.log(`πŸ“ Test at: http://localhost:${port}`);
console.log(`πŸ‘₯ Register at: http://localhost:${port}/api/auth/register`);
});
159 changes: 104 additions & 55 deletions backend/controllers/authController.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,65 +7,114 @@ const generateToken = (id) => {
};

export const registerUser = async (req, res) => {
const { name, email, password } = req.body;

// Check if user already exists
const userExists = await User.findOne({ email });
if (userExists) {
return res.status(400).json({ message: 'User already exists' });
try {
const { name, email, password } = req.body;

// Validate required fields
if (!name || !email || !password) {
return res.status(400).json({ message: 'All fields are required' });
}

// Check if user already exists
const userExists = await User.findOne({ email });
if (userExists) {
return res.status(400).json({ message: 'User already exists' });
}

// Hash password
const hashedPassword = await bcrypt.hash(password, 10);

// Create user with initial loyalty points and welcome achievement
const user = await User.create({
name,
email,
password: hashedPassword,
loyaltyPoints: 500,
totalPointsEarned: 500,
achievements: [{
id: 'welcome',
name: 'Welcome to Foodie!',
unlockedAt: new Date()
}]
});

// Generate JWT
const token = generateToken(user._id);

// Set JWT in secure, HTTP-only cookie
res.cookie('token', token, {
httpOnly: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
});

res.status(201).json({
user: {
_id: user._id,
name: user.name,
email: user.email,
loyaltyPoints: user.loyaltyPoints,
totalPointsEarned: user.totalPointsEarned,
achievements: user.achievements,
rewardHistory: user.rewardHistory
},
token: token,
message: 'Registration successful! Welcome bonus: 500 loyalty points added! πŸŽ‰',
});
} catch (error) {
console.error('Registration error:', error);
res.status(500).json({ message: 'Server error during registration' });
}

// Hash password
const hashedPassword = await bcrypt.hash(password, 10);

// Create user
const user = await User.create({ name, email, password: hashedPassword });

// Generate JWT
const token = generateToken(user._id);

// Set JWT in secure, HTTP-only cookie
res.cookie('token', token, {
httpOnly: true, // Prevent JS access (XSS protection)
sameSite: 'strict', // CSRF protection
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
});

res.status(201).json({
user: { _id: user._id, name: user.name, email: user.email },
message: 'Registration successful',
});
};

export const loginUser = async (req, res) => {
const { email, password } = req.body;

// Find user
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ message: 'User not found' });
try {
const { email, password } = req.body;

// Validate required fields
if (!email || !password) {
return res.status(400).json({ message: 'Email and password are required' });
}

// Find user
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ message: 'Invalid email or password' });
}

// Compare password
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ message: 'Invalid email or password' });
}

// Generate JWT
const token = generateToken(user._id);

// Set JWT in secure, HTTP-only cookie
res.cookie('token', token, {
httpOnly: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000,
});

res.json({
user: {
_id: user._id,
name: user.name,
email: user.email,
loyaltyPoints: user.loyaltyPoints || 0,
totalPointsEarned: user.totalPointsEarned || 0,
achievements: user.achievements || [],
rewardHistory: user.rewardHistory || []
},
token: token,
message: 'Login successful',
});
} catch (error) {
console.error('Login error:', error);
res.status(500).json({ message: 'Server error during login' });
}

// Compare password
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ message: 'Invalid password' });
}

// Generate JWT
const token = generateToken(user._id);

// Set JWT in secure, HTTP-only cookie
res.cookie('token', token, {
httpOnly: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000,
});

res.json({
user: { _id: user._id, name: user.name, email: user.email },
message: 'Login successful',
});
};

export const logoutUser = async (req, res) => {
Expand All @@ -78,4 +127,4 @@ export const logoutUser = async (req, res) => {
});

res.status(200).json({ message: 'User logged out successfully' });
};
};
48 changes: 47 additions & 1 deletion backend/controllers/foodController.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const addFood = async (req, res) => {
price: body.price,
description: body.description,
category: body.category,
foodType: body.foodType || 'main', // Default to 'main' if not provided
restaurantId: body.restaurantId,
image: req.file?.filename,
});
Expand Down Expand Up @@ -52,5 +53,50 @@ const removeFood = async (req, res) => {
}
};

// Get all available food types/categories
const getFoodTypes = async (req, res) => {
try {
const foodTypes = ['appetizer', 'main', 'dessert', 'beverage', 'snack', 'side'];
res.status(200).json({ success: true, foodTypes });
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};

// Get foods by food type
const getFoodsByType = async (req, res) => {
try {
const { foodType } = req.params;
const { restaurantId } = req.query;

let query = { foodType };
if (restaurantId) {
query.restaurantId = restaurantId;
}

const foods = await Food.find(query).populate('restaurantId', 'name');
res.status(200).json({ success: true, foods });
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};

// Get all foods with optional filtering
const getAllFoods = async (req, res) => {
try {
const { foodType, category, restaurantId } = req.query;
let query = {};

if (foodType) query.foodType = foodType;
if (category) query.category = category;
if (restaurantId) query.restaurantId = restaurantId;

const foods = await Food.find(query).populate('restaurantId', 'name');
res.status(200).json({ success: true, foods });
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
};

// βœ… Export all at once (no duplicates)
export { addFood, getFoodByRestaurant, removeFood };
export { addFood, getFoodByRestaurant, removeFood, getFoodTypes, getFoodsByType, getAllFoods };
Loading