GROS FIX + avatar

This commit is contained in:
gprunet
2026-01-21 16:11:28 +01:00
parent 825e53b554
commit 5bdf7f0442
8 changed files with 220 additions and 13 deletions
+147
View File
@@ -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
};
+14 -10
View File
@@ -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