GROS FIX + avatar
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -5,8 +5,10 @@ import {Server} from 'socket.io';
|
||||
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 {waitForDb, createTables, ensureOauthClient} from './db.js';
|
||||
import setupSocketIO from './services/socket.js';
|
||||
// import avatarService from './services/avatar.js';
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
@@ -36,9 +38,11 @@ async function startServer()
|
||||
console.warn('OAuth client might already exist or failed to register:', e.message);
|
||||
}
|
||||
|
||||
// app.use('/avatar', express.static(avatarService.AVATAR_DIR));
|
||||
app.use('/api/auth', authRouter);
|
||||
app.use('/api/global_chat', chatRouter);
|
||||
app.use('/api/rooms', gameRoomRouter);
|
||||
// app.use('/api/avatar', avatarRouter);
|
||||
app.get('/api', (req, res) => res.send('Backend running'));
|
||||
|
||||
server.listen(3001, () =>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
|
||||
//Check si le webtoken est valide
|
||||
// Check if the webtoken is valid
|
||||
export default function authMiddleware(req, res, next)
|
||||
{
|
||||
const header = req.headers.authorization;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
"cors": "^2.8.5",
|
||||
"passport": "0.7.0",
|
||||
"passport-github2": "0.1.12",
|
||||
"express-session": "1.18.0"
|
||||
"express-session": "1.18.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"file-type": "^19.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import express from 'express';
|
||||
import multer from 'multer';
|
||||
import avatarService from '../services/avatar.js';
|
||||
import {authenticateToken} from '../middleware/auth.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Configue multer to use RAM
|
||||
const storage = multer.memoryStorage();
|
||||
const upload = multer
|
||||
({
|
||||
storage: storage,
|
||||
limits:
|
||||
{
|
||||
fileSize: 5 * 1024 * 1024 // 5mb
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/upload', authenticateToken, upload.single('avatar'), async(req, res) =>
|
||||
{
|
||||
if (!req.file)
|
||||
return res.status(400).json({ error: 'No file uploaded' });
|
||||
|
||||
const result = await avatarService.uploadAvatar(req.user.userId, req.file);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
router.delete('/', authenticateToken, async(req, res) =>
|
||||
{
|
||||
const result = await avatarService.deleteAvatar(req.user.userId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
router.get('/me', authenticateToken, async(req, res) =>
|
||||
{
|
||||
const result = await avatarService.getAvatarUrl(req.user.userId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
router.get('/user/:userId', async(req, res) =>
|
||||
{
|
||||
const userId = parseInt(req.params.userId);
|
||||
if (isNaN(userId))
|
||||
return res.status(400).json({ error: 'Invalid user ID' });
|
||||
|
||||
const result = await avatarService.getAvatarUrl(userId);
|
||||
res.status(result.status).json(result.data);
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -54,7 +54,7 @@ router.post('/', authenticateToken, async(req, res) =>
|
||||
const {name} = req.body;
|
||||
if (!name)
|
||||
return (res.status(400).json({error: 'Room name required'}));
|
||||
const room = await gameRoomService.createRoom(name);
|
||||
const room = await gameRoomService.createRoom(name, req.user.userId);
|
||||
res.status(201).json(room);
|
||||
}
|
||||
catch(err)
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
import {query} from '../db.js';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import {fileURLToPath} from 'url';
|
||||
import {fileTypeFromBuffer} from 'file-type';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const AVATAR_DIR = path.join(__dirname, '../avatar');
|
||||
const DEFAULT_AVATAR = '/avatar/default.png';
|
||||
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5mb
|
||||
const ALLOWED_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
|
||||
|
||||
// Verify that the avatar folder already exists
|
||||
if (!fs.existsSync(AVATAR_DIR))
|
||||
{
|
||||
fs.mkdirSync(AVATAR_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
async function uploadAvatar(userId, file)
|
||||
{
|
||||
try
|
||||
{
|
||||
// File check (type and size)
|
||||
if (!file)
|
||||
return ({status: 400, data: {error: 'No file provided'}});
|
||||
|
||||
if (!ALLOWED_TYPES.includes(file.mimetype))
|
||||
return ({status: 400, data: { error: 'Invalid file type. Only JPEG, PNG, GIF, and WebP allowed'}});
|
||||
|
||||
const fileType = await fileTypeFromBuffer(file.buffer);
|
||||
if (!fileType || !['image/jpeg', 'image/png', 'image/gif', 'image/webp'].includes(fileType.mime))
|
||||
return ({status: 400, data: {error: 'Invalid file content. File does not match allowed image types'}});
|
||||
|
||||
if (file.size > MAX_FILE_SIZE)
|
||||
return ({status: 400, data: {error: 'File too large. Maximum size is 5MB'}});
|
||||
|
||||
|
||||
const currentAvatar = await getCurrentAvatar(userId);
|
||||
if (currentAvatar === null)
|
||||
return ({status: 404, data: {error: 'User not found'}});
|
||||
|
||||
// Create a unique name for the new avatar to avoid duplicates
|
||||
const fileExt = path.extname(file.originalname);
|
||||
const fileName = `user_${userId}_${Date.now()}${fileExt}`;
|
||||
const avatarPath = `/avatar/${fileName}`;
|
||||
|
||||
// Save the new avatar in the folder
|
||||
const filePath = path.join(AVATAR_DIR, fileName);
|
||||
fs.writeFileSync(filePath, file.buffer);
|
||||
|
||||
await setAvatar(avatarPath, userId);
|
||||
|
||||
deleteNonDefault(currentAvatar);
|
||||
return ({status: 200, data: {avatar_url: avatarPath}});
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
console.error('Avatar upload error:', err);
|
||||
return { status: 500, data: { error: 'Server error' } };
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteAvatar(userId) {
|
||||
try
|
||||
{
|
||||
const currentAvatar = await getCurrentAvatar(userId);
|
||||
if (currentAvatar === null)
|
||||
return ({status: 404, data: {error: 'User not found'}});
|
||||
|
||||
// Reset the avatar to the default one
|
||||
await setAvatar(DEFAULT_AVATAR, userId);
|
||||
|
||||
deleteNonDefault(currentAvatar);
|
||||
return ({status: 200, data: {avatar_url: DEFAULT_AVATAR}});
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
console.error('Avatar delete error:', err);
|
||||
return ({status: 500, data: {error: 'Server error'}});
|
||||
}
|
||||
}
|
||||
|
||||
async function setAvatar(newAvatar, userId)
|
||||
{
|
||||
await query
|
||||
(
|
||||
'UPDATE users SET avatar_url = $1 WHERE id = $2',
|
||||
[newAvatar, userId]
|
||||
);
|
||||
}
|
||||
|
||||
async function getCurrentAvatar(userId)
|
||||
{
|
||||
const res = await query
|
||||
(
|
||||
'SELECT avatar_url FROM users WHERE id = $1',
|
||||
[userId]
|
||||
);
|
||||
if (res.rows.length === 0)
|
||||
return (null);
|
||||
return (res.rows[0].avatar_url);
|
||||
}
|
||||
|
||||
function deleteNonDefault(curAvatar)
|
||||
{
|
||||
if (curAvatar && curAvatar !== DEFAULT_AVATAR)
|
||||
{
|
||||
const fileName = path.basename(curAvatar);
|
||||
const filePath = path.join(AVATAR_DIR, fileName);
|
||||
|
||||
if (fs.existsSync(filePath))
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
async function getAvatarUrl(userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
const result = await query
|
||||
(
|
||||
'SELECT avatar_url FROM users WHERE id = $1',
|
||||
[userId]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0)
|
||||
return ({status: 404, data: {error: 'User not found'}});
|
||||
|
||||
return ({status: 200, data: {avatar_url: result.rows[0].avatar_url}});
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
console.error('Get avatar error:', err);
|
||||
return ({status: 500, data: {error: 'Server error'}});
|
||||
}
|
||||
}
|
||||
|
||||
export default
|
||||
{
|
||||
uploadAvatar,
|
||||
deleteAvatar,
|
||||
getAvatarUrl,
|
||||
AVATAR_DIR,
|
||||
DEFAULT_AVATAR
|
||||
};
|
||||
@@ -1,15 +1,22 @@
|
||||
import {query} from '../db.js';
|
||||
|
||||
// Creer la room avec comme seul parametre le nom
|
||||
// max_players, status et ses autres variables sont aux valeurs definis dans db.js
|
||||
async function createRoom(name)
|
||||
// Create the room with name as the only parameter
|
||||
// max_players, status and the other variables have their default values defined in db.js
|
||||
async function createRoom(name, userId)
|
||||
{
|
||||
const result = await query
|
||||
(
|
||||
`INSERT INTO game_rooms (name) VALUES ($1) RETURNING *`,
|
||||
[name]
|
||||
);
|
||||
return (result.rows[0]);
|
||||
const room = result.rows[0];
|
||||
|
||||
await query
|
||||
(
|
||||
'INSERT INTO game_players (room_id, user_id) VALUES ($1, $2)',
|
||||
[room.id, userId]
|
||||
);
|
||||
return (room);
|
||||
}
|
||||
|
||||
async function getRoomById(roomId)
|
||||
@@ -22,9 +29,7 @@ async function getRoomById(roomId)
|
||||
return (result.rows[0]);
|
||||
}
|
||||
|
||||
//Liste toutes les rooms en attente
|
||||
//ainsi que le nombre de joueurs dans chaque room
|
||||
//utile pour montrer toutes les rooms joignables
|
||||
// List all the waiting rooms and the player amount in each of them
|
||||
async function listActiveRooms()
|
||||
{
|
||||
const result = await query
|
||||
@@ -87,9 +92,8 @@ async function leaveRoom(roomId, userId)
|
||||
}
|
||||
}
|
||||
|
||||
//Renvoie la liste des joueurs trie selon leur score
|
||||
//Cette liste donne egalement l'info sur qui dessine actuellement
|
||||
//Utile pour le jeu en lui meme et le scoreboard de la game
|
||||
// List the players in the room and their scores
|
||||
// Useful for the scoreboard and also tell which player is currently drawing
|
||||
async function getRoomPlayers(roomId)
|
||||
{
|
||||
const result = await query
|
||||
|
||||
Reference in New Issue
Block a user