code plus clean et gestion des amis
This commit is contained in:
@@ -6,6 +6,7 @@ import authRouter from './routes/auth.js';
|
||||
import chatRouter from './routes/global_chat.js';
|
||||
import gameRoomRouter from './routes/game_room.js';
|
||||
import avatarRouter from './routes/avatar.js';
|
||||
import friendsRouter from './routes/friends.js';
|
||||
import {waitForDb, createTables, ensureOauthClient} from './db.js';
|
||||
import setupSocketIO from './services/socket.js';
|
||||
import avatarService from './services/avatar.js';
|
||||
@@ -43,6 +44,7 @@ async function startServer()
|
||||
app.use('/api/global_chat', chatRouter);
|
||||
app.use('/api/rooms', gameRoomRouter);
|
||||
app.use('/api/avatar', avatarRouter);
|
||||
app.use('/api/friends', friendsRouter);
|
||||
app.get('/api', (req, res) => res.send('Backend running'));
|
||||
|
||||
server.listen(3001, () =>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import express from 'express';
|
||||
import friendsService from '../services/friends.js';
|
||||
import authenticateToken from '../middleware/auth.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Get friends list
|
||||
router.get('/', authenticateToken, async (req, res) => {
|
||||
const result = await friendsService.getFriends(req.user.userId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
// Get pending friend requests
|
||||
router.get('/requests', authenticateToken, async (req, res) => {
|
||||
const result = await friendsService.getPendingRequests(req.user.userId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
// Search users
|
||||
router.get('/search', authenticateToken, async (req, res) => {
|
||||
const { q } = req.query;
|
||||
if (!q || q.trim().length === 0) {
|
||||
return res.status(400).json({ error: 'Search query required' });
|
||||
}
|
||||
const result = await friendsService.searchUsers(req.user.userId, q.trim());
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
// Send friend request
|
||||
router.post('/request/:userId', authenticateToken, async (req, res) => {
|
||||
const toUserId = parseInt(req.params.userId);
|
||||
if (isNaN(toUserId)) {
|
||||
return res.status(400).json({ error: 'Invalid user ID' });
|
||||
}
|
||||
const result = await friendsService.sendFriendRequest(req.user.userId, toUserId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
// Accept friend request
|
||||
router.post('/accept/:userId', authenticateToken, async (req, res) => {
|
||||
const fromUserId = parseInt(req.params.userId);
|
||||
if (isNaN(fromUserId)) {
|
||||
return res.status(400).json({ error: 'Invalid user ID' });
|
||||
}
|
||||
const result = await friendsService.acceptFriendRequest(req.user.userId, fromUserId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
// Decline friend request
|
||||
router.post('/decline/:userId', authenticateToken, async (req, res) => {
|
||||
const fromUserId = parseInt(req.params.userId);
|
||||
if (isNaN(fromUserId)) {
|
||||
return res.status(400).json({ error: 'Invalid user ID' });
|
||||
}
|
||||
const result = await friendsService.declineFriendRequest(req.user.userId, fromUserId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
// Remove friend
|
||||
router.delete('/:userId', authenticateToken, async (req, res) => {
|
||||
const friendId = parseInt(req.params.userId);
|
||||
if (isNaN(friendId)) {
|
||||
return res.status(400).json({ error: 'Invalid user ID' });
|
||||
}
|
||||
const result = await friendsService.removeFriend(req.user.userId, friendId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,216 @@
|
||||
import { query } from '../db.js';
|
||||
|
||||
/**
|
||||
* Get list of friends for a user
|
||||
*/
|
||||
async function getFriends(userId) {
|
||||
try {
|
||||
const result = await query(
|
||||
`SELECT u.id, u.username, u.avatar_url
|
||||
FROM friendship f
|
||||
JOIN users u ON (
|
||||
CASE
|
||||
WHEN f.id_user1 = $1 THEN f.id_user2 = u.id
|
||||
ELSE f.id_user1 = u.id
|
||||
END
|
||||
)
|
||||
WHERE (f.id_user1 = $1 OR f.id_user2 = $1)
|
||||
AND f.status = 'accepted'`,
|
||||
[userId]
|
||||
);
|
||||
return { status: 200, data: { friends: result.rows } };
|
||||
} catch (err) {
|
||||
console.error('Get friends error:', err);
|
||||
return { status: 500, data: { error: 'Server error' } };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pending friend requests received by user
|
||||
*/
|
||||
async function getPendingRequests(userId) {
|
||||
try {
|
||||
const result = await query(
|
||||
`SELECT u.id, u.username, u.avatar_url, f.created_at
|
||||
FROM friendship f
|
||||
JOIN users u ON (
|
||||
CASE
|
||||
WHEN f.id_user1 = $1 THEN f.id_user2 = u.id
|
||||
ELSE f.id_user1 = u.id
|
||||
END
|
||||
)
|
||||
WHERE (f.id_user1 = $1 OR f.id_user2 = $1)
|
||||
AND f.status = 'pending_' || $1::text`,
|
||||
[userId]
|
||||
);
|
||||
return { status: 200, data: { requests: result.rows } };
|
||||
} catch (err) {
|
||||
console.error('Get pending requests error:', err);
|
||||
return { status: 500, data: { error: 'Server error' } };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search users by username
|
||||
*/
|
||||
async function searchUsers(userId, searchTerm) {
|
||||
try {
|
||||
const result = await query(
|
||||
`SELECT id, username, avatar_url
|
||||
FROM users
|
||||
WHERE username ILIKE $1
|
||||
AND id != $2
|
||||
LIMIT 20`,
|
||||
[`%${searchTerm}%`, userId]
|
||||
);
|
||||
return { status: 200, data: { users: result.rows } };
|
||||
} catch (err) {
|
||||
console.error('Search users error:', err);
|
||||
return { status: 500, data: { error: 'Server error' } };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a friend request
|
||||
*/
|
||||
async function sendFriendRequest(fromUserId, toUserId) {
|
||||
try {
|
||||
if (fromUserId === toUserId) {
|
||||
return { status: 400, data: { error: 'Cannot add yourself as friend' } };
|
||||
}
|
||||
|
||||
// Check if user exists
|
||||
const userCheck = await query('SELECT id FROM users WHERE id = $1', [toUserId]);
|
||||
if (userCheck.rows.length === 0) {
|
||||
return { status: 404, data: { error: 'User not found' } };
|
||||
}
|
||||
|
||||
// Ensure id_user1 < id_user2 for the constraint
|
||||
const id1 = Math.min(fromUserId, toUserId);
|
||||
const id2 = Math.max(fromUserId, toUserId);
|
||||
|
||||
// Check existing friendship
|
||||
const existing = await query(
|
||||
'SELECT status FROM friendship WHERE id_user1 = $1 AND id_user2 = $2',
|
||||
[id1, id2]
|
||||
);
|
||||
|
||||
if (existing.rows.length > 0) {
|
||||
const status = existing.rows[0].status;
|
||||
if (status === 'accepted') {
|
||||
return { status: 400, data: { error: 'Already friends' } };
|
||||
}
|
||||
if (status.startsWith('pending_')) {
|
||||
return { status: 400, data: { error: 'Friend request already exists' } };
|
||||
}
|
||||
}
|
||||
|
||||
// Status indicates who needs to accept: pending_<receiver_id>
|
||||
const status = `pending_${toUserId}`;
|
||||
|
||||
await query(
|
||||
`INSERT INTO friendship (id_user1, id_user2, status)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (id_user1, id_user2)
|
||||
DO UPDATE SET status = $3`,
|
||||
[id1, id2, status]
|
||||
);
|
||||
|
||||
return { status: 200, data: { message: 'Friend request sent' } };
|
||||
} catch (err) {
|
||||
console.error('Send friend request error:', err);
|
||||
return { status: 500, data: { error: 'Server error' } };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a friend request
|
||||
*/
|
||||
async function acceptFriendRequest(userId, fromUserId) {
|
||||
try {
|
||||
const id1 = Math.min(userId, fromUserId);
|
||||
const id2 = Math.max(userId, fromUserId);
|
||||
|
||||
const result = await query(
|
||||
`UPDATE friendship
|
||||
SET status = 'accepted'
|
||||
WHERE id_user1 = $1 AND id_user2 = $2
|
||||
AND status = $3
|
||||
RETURNING *`,
|
||||
[id1, id2, `pending_${userId}`]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return { status: 404, data: { error: 'Friend request not found' } };
|
||||
}
|
||||
|
||||
return { status: 200, data: { message: 'Friend request accepted' } };
|
||||
} catch (err) {
|
||||
console.error('Accept friend request error:', err);
|
||||
return { status: 500, data: { error: 'Server error' } };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decline a friend request
|
||||
*/
|
||||
async function declineFriendRequest(userId, fromUserId) {
|
||||
try {
|
||||
const id1 = Math.min(userId, fromUserId);
|
||||
const id2 = Math.max(userId, fromUserId);
|
||||
|
||||
const result = await query(
|
||||
`DELETE FROM friendship
|
||||
WHERE id_user1 = $1 AND id_user2 = $2
|
||||
AND status = $3
|
||||
RETURNING *`,
|
||||
[id1, id2, `pending_${userId}`]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return { status: 404, data: { error: 'Friend request not found' } };
|
||||
}
|
||||
|
||||
return { status: 200, data: { message: 'Friend request declined' } };
|
||||
} catch (err) {
|
||||
console.error('Decline friend request error:', err);
|
||||
return { status: 500, data: { error: 'Server error' } };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a friend
|
||||
*/
|
||||
async function removeFriend(userId, friendId) {
|
||||
try {
|
||||
const id1 = Math.min(userId, friendId);
|
||||
const id2 = Math.max(userId, friendId);
|
||||
|
||||
const result = await query(
|
||||
`DELETE FROM friendship
|
||||
WHERE id_user1 = $1 AND id_user2 = $2
|
||||
AND status = 'accepted'
|
||||
RETURNING *`,
|
||||
[id1, id2]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return { status: 404, data: { error: 'Friendship not found' } };
|
||||
}
|
||||
|
||||
return { status: 200, data: { message: 'Friend removed' } };
|
||||
} catch (err) {
|
||||
console.error('Remove friend error:', err);
|
||||
return { status: 500, data: { error: 'Server error' } };
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
getFriends,
|
||||
getPendingRequests,
|
||||
searchUsers,
|
||||
sendFriendRequest,
|
||||
acceptFriendRequest,
|
||||
declineFriendRequest,
|
||||
removeFriend
|
||||
};
|
||||
Reference in New Issue
Block a user