diff --git a/controllers/matchcontroller.js b/controllers/matchcontroller.js new file mode 100644 index 0000000..edf0f46 --- /dev/null +++ b/controllers/matchcontroller.js @@ -0,0 +1,74 @@ +const jwt = require('jsonwebtoken'); +const { Pool } = require('pg'); +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, +}); + +async function getUserIdFromToken(token) { + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET); + return decoded.id; + } catch (err) { + throw new Error('Invalid token'); + } +} + +async function createMatch(req, res) { + const token = req.headers['authorization']?.split(' ')[1]; + + if (!token) { + return res.status(403).json({ error: 'Token is required.' }); + } + + try { + const player1_uid = await getUserIdFromToken(token); + const client = await pool.connect(); + try { + const result = await client.query( + 'INSERT INTO matches (player1_uid) VALUES ($1) RETURNING match_id;', + [player1_uid] + ); + + const match_id = result.rows[0].match_id; + return res.status(200).json({ match_id }); + } finally { + client.release(); + } + } catch (error) { + console.error('Error creating match:', error); + return res.status(400).json({ error: error.message }); + } +} + +async function createMatch2v2(req, res) { + const token = req.headers['authorization']?.split(' ')[1]; + + if (!token) { + return res.status(403).json({ error: 'Token is required.' }); + } + + try { + const player1_uid = await getUserIdFromToken(token); + + const client = await pool.connect(); + try { + const result = await client.query( + 'INSERT INTO matches_2v2 (player1_team1_uid) VALUES ($1) RETURNING match_id;', + [player1_uid] + ); + + const match_id = result.rows[0].match_id; + return res.status(200).json({ match_id }); + } finally { + client.release(); + } + } catch (error) { + console.error('Error creating 2v2 match:', error); + return res.status(400).json({ error: error.message }); + } +} + +module.exports = { + createMatch, + createMatch2v2, +}; diff --git a/controllers/social.js b/controllers/social.js new file mode 100644 index 0000000..b702f80 --- /dev/null +++ b/controllers/social.js @@ -0,0 +1,104 @@ +const jwt = require('jsonwebtoken'); +const { Pool } = require('pg'); +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, +}); + +async function addFriend(req, res) { + const { friend_uid } = req.body; + const token = req.headers['authorization'] && req.headers['authorization'].split(' ')[1]; + + if (!token) { + return res.status(403).json({ error: 'Access denied. No token provided.' }); + } + + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const userUid = decoded.uid; + + const client = await pool.connect(); + try { + const result = await client.query( + 'SELECT friend_list FROM users WHERE uid = $1;', + [userUid] + ); + let friends = result.rows[0]?.friend_list || {}; + + if (Object.values(friends).includes(friend_uid)) { + return res.status(400).json({ error: 'Friend already in the list.' }); + } + + const friendKey = `friend${Object.keys(friends).length}`; + friends[friendKey] = friend_uid; + const friendsJson = JSON.stringify(friends); + + await client.query( + 'UPDATE users SET friend_list = $1 WHERE uid = $2;', + [friendsJson, userUid] + ); + + res.status(200).json({ message: 'Friend added successfully!' }); + } finally { + client.release(); + } + } catch (error) { + console.error('Error adding friend:', error); + res.status(500).json({ error: 'Server error' }); + } + } + + async function getFriendDetails(friendUid) { + const client = await pool.connect(); + try { + const result = await client.query('SELECT display_name, uid FROM users WHERE uid = $1', [friendUid]); + if (result.rows.length > 0) { + return result.rows[0]; + } + return null; + } finally { + client.release(); + } + } + + async function getFriendsList(req, res) { + const userId = req.user.id; + + try { + const client = await pool.connect(); + try { + const result = await client.query( + 'SELECT friend_list FROM users WHERE uid = $1;', + [userId] + ); + + const user = result.rows[0]; + if (!user || !user.friend_list) { + return res.status(404).json({ error: 'No friends found.' }); + } + + const friends = JSON.parse(user.friend_list); + const friendsDetails = []; + + for (const key in friends) { + const friendUid = friends[key]; + const friendDetails = await getFriendDetails(friendUid); + if (friendDetails) { + friendsDetails.push(friendDetails); + } + } + + return res.status(200).json({ friends: friendsDetails }); + } finally { + client.release(); + } + } catch (error) { + console.error('Error fetching friends:', error); + res.status(400).json({ error: error.message }); + } + } + + + module.exports = { + addFriend + }; + \ No newline at end of file diff --git a/controllers/users.js b/controllers/users.js new file mode 100644 index 0000000..5110e32 --- /dev/null +++ b/controllers/users.js @@ -0,0 +1,114 @@ +const bcrypt = require('bcrypt'); +const jwt = require('jsonwebtoken'); +const { Pool } = require('pg'); +const pool = new Pool({ + connectionString: process.env.DATABASE_URL, +}); + + +async function registerUser(req, res) { + const { email, display_name, password } = req.body; + const hashedPassword = await bcrypt.hash(password, 10); + + try { + const client = await pool.connect(); + try { + const result = await client.query( + `INSERT INTO users (email, display_name, password_hash) VALUES ($1, $2, $3) RETURNING uid;`, + [email, display_name, hashedPassword] + ); + const uid = result.rows[0].uid; + res.status(201).json({ uid }); + } finally { + client.release(); + } + } catch (error) { + console.error('Error registering user:', error); + res.status(500).json({ error: 'Server error' }); + } +} + +async function authenticateUser(req, res) { + const { email, password } = req.body; + + try { + const client = await pool.connect(); + try { + const result = await client.query('SELECT uid, password_hash FROM users WHERE email = $1;', [email]); + const user = result.rows[0]; + + if (user && bcrypt.compareSync(password, user.password_hash)) { + const token = jwt.sign( + { uid: user.uid, email: email }, + process.env.JWT_SECRET, + { expiresIn: '5d' } + ); + res.status(200).json({ token }); + } else { + res.status(401).json({ error: 'Invalid credentials' }); + } + } finally { + client.release(); + } + } catch (error) { + console.error('Error authenticating user:', error); + res.status(500).json({ error: 'Server error' }); + } +} + +async function resetPassword(req, res) { + const { uid, email, new_password } = req.body; + const hashedPassword = await bcrypt.hash(new_password, 10); + + try { + const client = await pool.connect(); + try { + const result = await client.query( + 'UPDATE users SET password_hash = $1 WHERE uid = $2 AND email = $3;', + [hashedPassword, uid, email] + ); + if (result.rowCount === 0) { + return res.status(400).json({ error: 'User not found' }); + } + res.status(200).json({ message: 'Password reset successfully' }); + } finally { + client.release(); + } + } catch (error) { + console.error('Error resetting password:', error); + res.status(500).json({ error: 'Server error' }); + } +} + +async function getLeaderboard(req, res) { + try { + const client = await pool.connect(); + try { + const result = await client.query( + 'SELECT display_name, openskill_mu, current_elo, uid FROM users WHERE current_elo IS NOT NULL ORDER BY current_elo DESC;' + ); + const players = result.rows; + + const playerEloList = players.map(player => ({ + player_name: player.display_name, + osk_mu: player.openskill_mu, + elo_rating: player.current_elo, + friend_code: player.uid + })); + + res.status(200).json(playerEloList); + } finally { + client.release(); + } + } catch (error) { + console.error('Error fetching leaderboard:', error); + res.status(500).json({ error: 'Server error' }); + } + } + +module.exports = { + registerUser, + authenticateUser, + resetPassword, + getLeaderboard, +};