Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	package.json
#	pnpm-lock.yaml
This commit is contained in:
Nabil Ould Hamou 2024-12-01 22:50:25 +01:00
commit a52023e84f
15 changed files with 226 additions and 677 deletions

View file

@ -14,26 +14,22 @@ datasource db {
} }
model User { model User {
id String @id @default(auto()) @map("_id") @db.ObjectId id String @id @default(auto()) @map("_id") @db.ObjectId
username String @unique username String @unique
surname String surname String
name String name String
email String @unique email String @unique
password String password String
channels Channel[] @relation(fields: [channelIDs], references: [id]) messages Message[]
channelIDs String[] @db.ObjectId
messages Message[]
@@map("users") // Table name in DB @@map("users") // Table name in DB
} }
model Channel { model Channel {
id String @id @default(auto()) @map("_id") @db.ObjectId id String @id @default(auto()) @map("_id") @db.ObjectId
name String name String @unique
topic String messages Message[]
users User[] @relation(fields: [userIDs], references: [id]) createdAt DateTime @default(now())
userIDs String[] @db.ObjectId
messages Message[]
@@map("channels") // Table name in DB @@map("channels") // Table name in DB
} }

View file

@ -1,16 +1,17 @@
<script lang="ts"> <script lang="ts">
export let id: string; // ID du chat
export let title: string; // Nom ou titre du chat export let title: string; // Nom ou titre du chat
export let lastMessage: string; // Dernier message affiché export let lastMessage: string; // Dernier message affiché
export let time: string; // Heure du dernier message export let time: string; // Heure du dernier message
</script> </script>
<div class="chat-item p-4 border rounded-md hover:bg-gray-100 cursor-pointer flex justify-between items-center"> <a href={`/chat/${id}`} class="chat-item p-4 border rounded-md hover:bg-gray-100 cursor-pointer flex justify-between items-center">
<div> <div>
<p class="font-semibold text-lg">{title}</p> <p class="font-semibold text-lg">{title}</p>
<p class="text-sm text-gray-500 truncate">{lastMessage}</p> <p class="text-sm text-gray-500 truncate">{lastMessage}</p>
</div> </div>
<p class="text-xs text-gray-400">{time}</p> <p class="text-xs text-gray-400">{time}</p>
</div> </a>
<style> <style>
.chat-item { .chat-item {

View file

@ -11,12 +11,31 @@
let chatName = ""; let chatName = "";
const createChat = () => { const createChat = async () => {
if (chatName.trim()) { if (chatName.trim()) {
alertMessage = `Le chat "${chatName}" a été créé avec succès.`; try {
// Appel API pour créer le chat
const response = await fetch('/api/canals', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: chatName }),
});
if (response.ok) {
const data = await response.json();
alertMessage = `Le chat "${data.name}" a été créé avec succès.`;
chatName = ""; // Réinitialiser
onClose?.(); // Fermer le composant après création
} else {
alertMessage = "Une erreur est survenue lors de la création du chat.";
}
} catch (err) {
alertMessage = "Erreur réseau ou serveur.";
}
showAlert = true; showAlert = true;
chatName = ""; // Réinitialiser
onClose?.(); // Fermer le composant après création
} else { } else {
alertMessage = "Veuillez entrer un nom pour le chat."; alertMessage = "Veuillez entrer un nom pour le chat.";
showAlert = true; showAlert = true;

51
src/lib/utils/date.ts Normal file
View file

@ -0,0 +1,51 @@
export function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleString('fr-FR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: false, // format 24 heures
});
}
//fonction qui renvoie le temps depuis la créetion du message à maintenant en fonction du temps on affichera le temps en secondes, minutes, heures, jours, semaines, mois, années
export function formatDistanceToNow(dateString) {
const date = new Date(dateString);
const now = new Date();
const diff = now - date;
const seconds = Math.floor(diff / 1000);
if (seconds < 60) {
return `${seconds} s`;
}
const minutes = Math.floor(seconds / 60);
if (minutes < 60) {
return `${minutes} min`;
}
const hours = Math.floor(minutes / 60);
if (hours < 24) {
return `${hours} h`;
}
const days = Math.floor(hours / 24);
if (days < 7) {
return `${days} j`;
}
const weeks = Math.floor(days / 7);
if (weeks < 4) {
return `${weeks} sem`;
}
const months = Math.floor(days / 30);
if (months < 12) {
return `${months} mois`;
}
const years = Math.floor(months / 12);
return `${years} ans`;
}

View file

@ -1,123 +0,0 @@
import { json } from '@sveltejs/kit';
import prisma from '$lib/prismaClient';
import redisClient from '$lib/redisClient'; // Assurez-vous d'importer le client Redis
// Récupérer les informations du canal et le dernier message (avec cache Redis)
export async function GET({ params }) {
const canalId = parseInt(params.id);
// Clé cache pour les informations du canal et le dernier message
const canalCacheKey = `canal:${canalId}:info`;
try {
// Vérifier si les informations du canal et le dernier message sont dans le cache Redis
const cachedCanalData = await redisClient.get(canalCacheKey);
if (cachedCanalData) {
console.log('✅ Cache hit pour les informations du canal et le dernier message');
return json(JSON.parse(cachedCanalData));
}
console.log('❌ Cache miss');
// Si non, récupérer les informations du canal et le dernier message depuis Prisma
const canal = await prisma.canal.findUnique({
where: { id: canalId },
include: {
users: true, // Inclut les utilisateurs associés au canal
},
});
if (!canal) {
return json({ error: 'Canal non trouvé' }, { status: 404 });
}
// Récupérer le dernier message
const lastMessage = await prisma.message.findFirst({
where: { canalId },
include: {
user: { select: { id: true, pseudo: true } },
},
orderBy: { createdAt: 'desc' }, // Trie par date décroissante, donc le dernier message est récupéré en premier
});
// Créer un objet combiné pour le canal et le dernier message
const canalData = {
canal,
lastMessage, // Inclure uniquement le dernier message
};
// Mettre en cache les informations du canal et le dernier message pendant 5 minutes
await redisClient.set(canalCacheKey, JSON.stringify(canalData), 'EX', 300); // Cache pendant 5 minutes
console.log('❌ Cache miss - Mise en cache des résultats');
return json(canalData);
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la récupération du canal ou du dernier message' }, { status: 500 });
}
}
// Supprimer un canal et invalider le cache associé
export async function DELETE({ params }) {
const canalId = parseInt(params.id);
try {
// Supprimer le canal de la base de données
await prisma.canal.delete({
where: { id: canalId },
});
// Invalider le cache
await redisClient.del(`canal:${canalId}:info`);
return json({ message: 'Canal supprimé avec succès' });
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la suppression du canal' }, { status: 500 });
}
}
// Modifier un canal
export async function PUT({ params, request }) {
const canalId = parseInt(params.id);
const { nom, domaine } = await request.json(); // On suppose que ce sont les champs à mettre à jour
// Clé cache pour les informations du canal et le dernier message
const canalCacheKey = `canal:${canalId}:info`;
try {
// Mettre à jour les informations du canal dans la base de données
const updatedCanal = await prisma.canal.update({
where: { id: canalId },
data: {
nom, // Nom du canal
domaine, // Domaine du canal
},
include: {
users: true, // Inclut les utilisateurs associés au canal
},
});
// Récupérer le dernier message associé au canal après mise à jour
const lastMessage = await prisma.message.findFirst({
where: { canalId },
include: {
user: { select: { id: true, pseudo: true } },
},
orderBy: { createdAt: 'desc' },
});
// Créer un objet combiné pour les nouvelles informations du canal et le dernier message
const canalData = {
canal: updatedCanal,
lastMessage, // Inclure uniquement le dernier message
};
// Mettre en cache les nouvelles informations pendant 5 minutes
await redisClient.set(canalCacheKey, JSON.stringify(canalData), 'EX', 60 * 5); // Cache pendant 5 minutes
return json(canalData);
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la mise à jour du canal' }, { status: 500 });
}
}

View file

@ -1,149 +0,0 @@
import { json } from '@sveltejs/kit';
import prisma from '$lib/prismaClient';
import redisClient from '$lib/redisClient'; // Assure-toi d'importer ton client Redis
export async function GET({ params, url }) {
const canalId = parseInt(params.id);
// Gestion de la pagination avec des paramètres optionnels `page` et `limit`
const page = parseInt(url.searchParams.get('page')) || 1;
const limit = parseInt(url.searchParams.get('limit')) || 10;
const offset = (page - 1) * limit;
// Générer une clé cache Redis unique en fonction du canal et des paramètres de pagination
const cacheKey = `canal:${canalId}:messages:page:${page}:limit:${limit}`;
try {
// 1. Vérifier si les messages sont déjà dans le cache Redis
const cachedMessages = await redisClient.get(cacheKey);
if (cachedMessages) {
console.log('✅ Cache hit');
return json(JSON.parse(cachedMessages)); // Si les données sont en cache, les retourner
}
// 2. Si les messages ne sont pas en cache, récupérer depuis la base de données
const messages = await prisma.message.findMany({
where: { canalId },
include: {
user: {
select: { id: true, pseudo: true }, // Inclut uniquement lID et le pseudo de lutilisateur
},
},
orderBy: {
createdAt: 'asc', // Trie par date croissante
},
skip: offset,
take: limit,
});
// 3. Compter le nombre total de messages pour la pagination
const totalMessages = await prisma.message.count({
where: { canalId },
});
const response = {
messages,
pagination: {
page,
limit,
totalMessages,
totalPages: Math.ceil(totalMessages / limit),
},
};
// 4. Mettre en cache les messages avec une expiration (par exemple 5 minutes)
await redisClient.set(cacheKey, JSON.stringify(response), 'EX', 60 * 5); // Cache pendant 5 minutes
console.log('❌ Cache miss - Mise en cache des résultats');
return json(response); // Retourner les données récupérées
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la récupération des messages' }, { status: 500 });
}
}
export async function POST({ params, request }) {
const canalId = parseInt(params.id);
const { userId, text } = await request.json();
try {
// Créer un nouveau message dans la base de données
const newMessage = await prisma.message.create({
data: {
userId,
canalId,
text,
},
include: { user: { select: { id: true, pseudo: true } } },
});
updateCaches(); // Mettre à jour les caches après la création dun nouveau message
return json(newMessage, { status: 201 });
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la création du message' }, { status: 500 });
}
}
export async function DELETE({ params }) {
const messageId = parseInt(params.id);
try {
// Supprimer le message de la base de données
await prisma.message.delete({
where: { id: messageId },
});
updateCaches(); // Mettre à jour les caches après la suppression dun message
return json({ message: 'Message supprimé avec succès' });
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la suppression du message' }, { status: 500 });
}
}
// Fonction pour mettre à jour tous les caches des messages
function updateCaches(canalId) {
// Mettre à jour tous les caches
// Mettre à jour toutes les pages dans le cache
let page : number = 1;
let limit : number = 10;
let offset : number = (page - 1) * limit;
while (true) {
const cacheKey = `canal:${canalId}:messages:page:${page}:limit:${limit}`;
const cachedMessages = await redisClient.get(cacheKey);
if (!cachedMessages) {
break;
}
const totalMessages = await prisma.message.count({
where: { canalId },
});
const messages = await prisma.message.findMany({
where: { canalId },
include: {
user: {
select: { id: true, pseudo: true },
},
},
orderBy: {
createdAt: 'asc',
},
skip: offset,
take: limit,
});
const response = {
messages,
pagination: {
page,
limit,
totalMessages,
totalPages: Math.ceil(totalMessages / limit),
},
};
await redisClient.set(cacheKey, JSON.stringify(response), 'EX', 60 * 5);
page++;
offset = (page - 1) * limit;
}
}

View file

@ -1,47 +0,0 @@
import { json } from '@sveltejs/kit';
import prisma from '$lib/prismaClient';
import redisClient from '$lib/redisClient';
// GET: Liste tous les canaux
export async function GET() {
try {
const cachedCanaux = await redisClient.get('canaux');
if (cachedCanaux) {
console.log('✅ Cache hit');
return json(JSON.parse(cachedCanaux));
}
console.log('❌ Cache miss');
const canaux = await prisma.canal.findMany({
include: { users: true, messages: true }, // Inclut les relations
});
await redisClient.set('canaux', JSON.stringify(canaux), { EX: 600 }); // Met en cache
return json(canaux);
} catch (err) {
console.error(err);
return json({ error: 'Erreur serveur' }, { status: 500 });
}
}
export async function POST({ request }) {
const { nom, domaine, userIds } = await request.json();
try {
const canal = await prisma.canal.create({
data: {
nom,
domaine,
users: {
connect: userIds.map((id) => ({ id })), // Associe des utilisateurs au canal
},
},
});
return json(canal, { status: 201 });
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la création du canal' }, { status: 500 });
}
}

View file

@ -2,46 +2,89 @@ import { json } from '@sveltejs/kit';
import prisma from '$lib/prismaClient'; import prisma from '$lib/prismaClient';
import redisClient from '$lib/redisClient'; import redisClient from '$lib/redisClient';
// GET: Liste tous les canaux import { json } from '@sveltejs/kit';
import prisma from '$lib/prismaClient';
import redisClient from '$lib/redisClient';
// GET: Liste tous les canaux avec leur premier message
export async function GET() { export async function GET() {
try { try {
const cachedCanaux = await redisClient.get('canaux'); const cachedCanaux = await redisClient.get('canaux');
if (cachedCanaux) {
console.log('✅ Cache hit');
return json(JSON.parse(cachedCanaux));
}
console.log('❌ Cache miss'); console.log('❌ Cache miss');
const canaux = await prisma.canal.findMany({
include: { users: true, messages: true }, // Inclut les relations // Si le cache est invalide ou vide, on charge les données depuis la base de données
let canaux = await prisma.channel.findMany({
include: {
messages: {
take: 1, // Récupère le dernier message
orderBy: { createdAt: 'desc' }, // Trie par date décroissante
},
},
});
canaux = canaux.sort((a, b) => {
const lastMessageA = a.messages[0]?.createdAt || a.createdAt ? a.createdAt : new Date();
const lastMessageB = b.messages[0]?.createdAt || b.createdAt ? b.createdAt : new Date();
return new Date(lastMessageB).getTime() - new Date(lastMessageA).getTime();
}); });
await redisClient.set('canaux', JSON.stringify(canaux), { EX: 600 }); // Met en cache
return json(canaux); return json(canaux);
} catch (err) { } catch (err) {
console.error(err); console.error('Erreur lors de la récupération des canaux:', err);
return json({ error: 'Erreur serveur' }, { status: 500 }); return json({ error: 'Erreur serveur' }, { status: 500 });
} }
} }
export async function POST({ request }) { export async function POST({ request }) {
const { nom, domaine, userIds } = await request.json(); console.log('Création dun canal');
const { name } = await request.json(); // Récupère le nom du canal depuis la requête
try { try {
const canal = await prisma.canal.create({ // 1. Créer le canal dans la base de données MongoDB avec Prisma
const canal = await prisma.channel.create({
data: { data: {
nom, name,
domaine, createdAt: new Date(),
users: {
connect: userIds.map((id) => ({ id })), // Associe des utilisateurs au canal
},
}, },
}); });
console.log('Canal créé dans MongoDB:', canal);
// 2. Récupérer les canaux existants du cache Redis
let canaux = await redisClient.get('canaux');
// Si le cache est vide, initialiser un tableau vide
if (canaux) {
try {
canaux = JSON.parse(canaux); // Parser la liste existante dans Redis
} catch (parseError) {
console.error('Erreur lors du parsing du cache Redis:', parseError);
canaux = []; // Réinitialiser si parsing échoue
}
} else {
canaux = [];
}
// 3. Ajouter le nouveau canal à la liste des canaux en mémoire (Redis)
canaux.push(canal); // Ajoute le canal créé dans la base de données à la liste Redis
// 4. Mettre à jour le cache Redis avec la liste des canaux
await redisClient.set('canaux', JSON.stringify(canaux), { EX: 600 }); // Le cache expire dans 10 minutes
console.log('Liste des canaux mise à jour dans Redis');
// 5. Retourner le canal créé dans la réponse
return json(canal, { status: 201 }); return json(canal, { status: 201 });
} catch (err) { } catch (err) {
console.error(err); // Gérer les erreurs et les retourner
console.error('Erreur lors de la création du canal:', err);
return json({ error: 'Erreur lors de la création du canal' }, { status: 500 }); return json({ error: 'Erreur lors de la création du canal' }, { status: 500 });
} }
} }

View file

@ -1,200 +0,0 @@
import { json } from '@sveltejs/kit';
import redisClient from '$lib/redisClient';
import prisma from '$lib/prismaClient';
import multer from 'multer';
import path from 'path';
import fs from 'fs';
const destinationDir = '/uploads';
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, `.${destinationDir}'); // Dossier où les images sont stockées`
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`);
},
fileFilter(req, file, cb) {
const fileExtension = path.extname(file.originalname).toLowerCase();
if (fileExtension !== '.jpg' && fileExtension !== '.jpeg' && fileExtension !== '.png') {
return cb(new Error('Seules les images JPG, JPEG et PNG sont autorisées.'));
}
cb(null, true);
}
});
const upload = multer({ storage });
export async function GET({ params }) {
const userId = params.id;
try {
// Vérifier si l'utilisateur est dans le cache Redis
const cachedUser = await redisClient.get(`user:${userId}`);
if (cachedUser) {
console.log('✅ Cache hit');
return json(JSON.parse(cachedUser));
}
console.log('❌ Cache miss');
// Si non, récupérer depuis MongoDB via Prisma
const user = await prisma.user.findUnique({
where: { id: parseInt(userId) },
});
if (!user) {
return json({ error: 'Utilisateur non trouvé' }, { status: 404 });
}
// Mettre l'utilisateur en cache
await redisClient.set(`user:${userId}`, JSON.stringify(user), { EX: 3600 });
return json(user);
} catch (err) {
console.error(err);
return json({ error: 'Erreur serveur' }, { status: 500 });
}
}
// Mettre à jour un utilisateur avec PUT
export async function PUT({ params, request }) {
const userId = parseInt(params.id);
const cachedUser = await redisClient.get(`user:${userId}`);
// Récupérer l'utilisateur à partir de la base de données
let existingUser;
if (cachedUser) {
console.log('✅ Cache hit');
// Si l'utilisateur est dans le cache, on le parse
existingUser = JSON.parse(cachedUser);
} else {
// Si l'utilisateur n'est pas dans le cache, on le récupère de la base de données
console.log('❌ Cache miss');
existingUser = await prisma.user.findUnique({
where: { id: userId },
});
if (!existingUser) {
return json({ error: 'Utilisateur non trouvé' }, { status: 404 });
}
// Utilisation de multer pour récupérer l'image (si présente)
return new Promise((resolve, reject) => {
upload.single('profilePicture')(request.raw, request.raw, async (err) => {
if (err) {
console.error('Erreur de téléchargement:', err);
return reject(json({ error: 'Erreur lors du téléchargement du fichier' }, { status: 500 }));
}
// Extraire les autres données (pseudo, nom, etc.) du body de la requête
const { pseudo, nom, prenom, email, password } = await request.json();
let updatedUserData = {
pseudo,
nom,
prenom,
email,
password, // Assurez-vous de bien sécuriser les mots de passe
};
// Si une nouvelle image est envoyée
if (request.file) {
// Vérifiez si l'utilisateur a déjà une image
if (existingUser.profilePictureUrl) {
// Supprimer l'ancienne image
const oldImagePath = `.${destinationDir}/${path.basename(existingUser.profilePictureUrl)}`;
if (fs.existsSync(oldImagePath)) {
fs.unlinkSync(oldImagePath); // Suppression du fichier
}
}
// Ajouter la nouvelle image à la base de données
updatedUserData.profilePictureUrl = `${destinationDir}/${request.file.filename}`;
} else if (!request.file && existingUser.profilePictureUrl) {
// Si aucune image n'est envoyée, supprimer l'image actuelle
const oldImagePath = `.${destinationDir}/${path.basename(existingUser.profilePictureUrl)}`;
if (fs.existsSync(oldImagePath)) {
fs.unlinkSync(oldImagePath); // Supprimer l'ancienne image
}
// Mettre à jour l'URL de l'image en null
updatedUserData.profilePictureUrl = null;
}
try {
// Mettre à jour l'utilisateur dans la base de données
const updatedUser = await prisma.user.update({
where: { id: userId },
data: updatedUserData,
});
// Mettre à jour l'utilisateur dans le cache Redis
await redisClient.set(`user:${userId}`, JSON.stringify(updatedUser), 'EX', 3600); // Cache pendant 1 heure (3600 secondes)
// Réponse avec l'utilisateur mis à jour
return resolve(json(updatedUser));
} catch (error) {
console.error('Erreur lors de la mise à jour de l\'utilisateur:', error);
return reject(json({ error: 'Erreur lors de la mise à jour de l\'utilisateur' }, { status: 500 }));
}
});
});
}
export async function DELETE({ params }) {
const userId = parseInt(params.id);
try {
// Vérifier si l'utilisateur est dans le cache Redis
const cachedUser = await redisClient.get(`user:${userId}`);
let userToDelete;
if (cachedUser) {
console.log('✅ Cache hit');
// Si l'utilisateur est dans le cache, on le parse
userToDelete = JSON.parse(cachedUser);
} else {
// Si l'utilisateur n'est pas dans le cache, on le récupère de la base de données
console.log('❌ Cache miss');
userToDelete = await prisma.user.findUnique({
where: { id: userId },
});
if (!userToDelete) {
return json({ error: 'Utilisateur non trouvé' }, { status: 404 });
}
// Mettre l'utilisateur dans le cache Redis
await redisClient.set(`user:${userId}`, JSON.stringify(userToDelete), { EX: 3600 }); // Cache pendant 1 heure
}
// Si l'utilisateur a une image de profil, la supprimer
if (userToDelete.profilePictureUrl) {
// Calculer le chemin du fichier à supprimer
const imagePath = `.${destinationDir}/${path.basename(userToDelete.profilePictureUrl)}`;
if (fs.existsSync(imagePath)) {
fs.unlinkSync(imagePath); // Supprimer le fichier image
}
}
// Supprimer l'utilisateur de la base de données
await prisma.user.delete({
where: { id: userId },
});
// Supprimer l'utilisateur du cache Redis
await redisClient.del(`user:${userId}`);
// Réponse après suppression réussie
return json({ message: 'Utilisateur et image supprimés avec succès' });
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la suppression de lutilisateur' }, { status: 500 });
}
}

View file

@ -33,43 +33,19 @@ export async function GET({ params }) {
} }
} }
export async function POST({ request }) {
const { pseudo, nom, prenom, email, password } = await request.json();
try {
const user = await prisma.user.create({
data: {
pseudo,
nom,
prenom,
email,
password,
},
});
// Mettre le nouvel utilisateur dans le cache
await redisClient.set(`user:${user.id}`, JSON.stringify(user), { EX: 3600 });
return json(user, { status: 201 });
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la création de lutilisateur' }, { status: 500 });
}
}
// Mettre à jour un utilisateur avec PUT // Mettre à jour un utilisateur avec PUT
export async function PUT({ params, request }) { export async function PUT({ params, request }) {
const userId = parseInt(params.id); const userId = parseInt(params.id);
const { pseudo, nom, prenom, email, password } = await request.json(); // Assurez-vous d'envoyer tous les champs nécessaires dans le body const { username, surname, name, email, password } = await request.json(); // Assurez-vous d'envoyer tous les champs nécessaires dans le body
try { try {
// Mettre à jour l'utilisateur dans la base de données // Mettre à jour l'utilisateur dans la base de données
const updatedUser = await prisma.user.update({ const updatedUser = await prisma.user.update({
where: { id: userId }, where: { id: userId },
data: { data: {
pseudo, username,
nom, surname,
prenom, name,
email, email,
password, // Attention à ne pas oublier de sécuriser le mot de passe avec bcrypt ou une autre méthode password, // Attention à ne pas oublier de sécuriser le mot de passe avec bcrypt ou une autre méthode
}, },

View file

@ -1,87 +0,0 @@
// src/routes/api/users/+server.js
import { json } from '@sveltejs/kit';
import redisClient from '$lib/redisClient';
import prisma from '$lib/prismaClient';
import multer from 'multer';
const destinationDir = '/uploads';
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, `.${destinationDir}'); // Dossier où les images sont stockées`
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`);
},
fileFilter(req, file, cb) {
const fileExtension = path.extname(file.originalname).toLowerCase();
if (fileExtension !== '.jpg' && fileExtension !== '.jpeg' && fileExtension !== '.png') {
return cb(new Error('Seules les images JPG, JPEG et PNG sont autorisées.'));
}
cb(null, true);
}
});
export async function GET() {
try {
// Vérifier si les utilisateurs sont dans le cache Redis
const cachedUsers = await redisClient.get('users');
if (cachedUsers) {
console.log('✅ Cache hit');
return json(JSON.parse(cachedUsers));
}
console.log('❌ Cache miss');
// Sinon, récupérer les utilisateurs depuis MongoDB
const users = await prisma.user.findMany();
// Mettre les utilisateurs en cache
await redisClient.set('users', JSON.stringify(users), { EX: 600 });
return json(users);
} catch (err) {
console.error(err);
return json({ error: 'Erreur serveur' }, { status: 500 });
}
}
export async function POST({ request }) {
return new Promise((resolve, reject) => {
// Utilisation de multer pour récupérer le fichier
upload.single('profilePicture')(request.raw, request.raw, async (err) => {
if (err) {
console.error('Erreur de téléchargement:', err);
return reject(json({ error: 'Erreur lors du téléchargement du fichier' }, { status: 500 }));
}
// Récupérer les données du formulaire (sans le fichier)
const { pseudo, nom, prenom, email, password } = await request.json();
// L'URL de l'image sera le chemin relatif à partir du dossier uploads
const imageUrl = request.file ? `${destinationDir}/${request.file.filename}` : null;
try {
// Créer un nouvel utilisateur avec l'URL de l'image
const user = await prisma.user.create({
data: {
pseudo,
nom,
prenom,
email,
password,
profilePictureUrl: imageUrl, // Stocker l'URL de l'image
},
});
// Mettre l'utilisateur dans le cache Redis
await redisClient.set(`user:${user.id}`, JSON.stringify(user), { EX: 3600 });
// Réponse avec les données de l'utilisateur
return resolve(json(user, { status: 201 }));
} catch (error) {
console.error('Erreur lors de la création de l\'utilisateur:', error);
return reject(json({ error: 'Erreur lors de la création de l\'utilisateur' }, { status: 500 }));
}
});
});
}

View file

@ -25,3 +25,27 @@ export async function GET() {
return json({ error: 'Erreur serveur' }, { status: 500 }); return json({ error: 'Erreur serveur' }, { status: 500 });
} }
} }
export async function POST({ request }) {
const { username, surname, name, email, password } = await request.json();
try {
const user = await prisma.user.create({
data: {
username,
surname,
name,
email,
password,
},
});
// Mettre le nouvel utilisateur dans le cache
await redisClient.set(`user:${user.id}`, JSON.stringify(user), { EX: 3600 });
return json(user, { status: 201 });
} catch (err) {
console.error(err);
return json({ error: 'Erreur lors de la création de lutilisateur' }, { status: 500 });
}
}

View file

@ -5,6 +5,8 @@
import ChatItem from "$lib/components/ui/ChatItem.svelte"; import ChatItem from "$lib/components/ui/ChatItem.svelte";
import ProfileCard from "$lib/components/ui/ProfileCard.svelte"; // Importer le composant ProfileCard import ProfileCard from "$lib/components/ui/ProfileCard.svelte"; // Importer le composant ProfileCard
import CreateChat from "$lib/components/ui/CreateChat.svelte"; // Importer le composant CreateChat import CreateChat from "$lib/components/ui/CreateChat.svelte"; // Importer le composant CreateChat
import { formatDistanceToNow } from "$lib/utils/date.js";
import { io } from 'socket.io-client';
let showProfileCard = false; // État pour afficher ou masquer le ProfileCard let showProfileCard = false; // État pour afficher ou masquer le ProfileCard
let showCreateChat = false; // État pour afficher ou masquer CreateChat let showCreateChat = false; // État pour afficher ou masquer CreateChat
@ -35,6 +37,11 @@
console.log('closeCreateChat'); console.log('closeCreateChat');
showCreateChat = false; // Fermer le composant CreateChat showCreateChat = false; // Fermer le composant CreateChat
} }
export let data;
export let channels = data.channels;// Assurez-vous que 'lastMessage' est facultatif si nécessaire
console.log(channels);
</script> </script>
<div class="h-full flex flex-col gap-5 p-5"> <div class="h-full flex flex-col gap-5 p-5">
@ -67,8 +74,9 @@
</div> </div>
<div class="flex flex-col gap-4 overflow-y-auto"> <div class="flex flex-col gap-4 overflow-y-auto">
<ChatItem title="Discussion avec Yanax" lastMessage="Salut les amis !" time="12:34" /> {#each channels as channel}
<ChatItem title="Discussion avec Luxray" lastMessage="Salut Yanax" time="12:30" /> <ChatItem id={channel.id} title={channel.name} lastMessage={channel.lastMessage} time={formatDistanceToNow(channel.createdAt)} />
{/each}
</div> </div>
</div> </div>

22
src/routes/chats/+page.ts Normal file
View file

@ -0,0 +1,22 @@
export async function load({ fetch }) {
try {
// Appel API ou récupération de données
const res = await fetch('/api/canals', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
const channels = await res.json();
// Retourner les données à la page sous forme de props
return {
channels
};
} catch (error) {
console.error('Erreur lors du chargement des canaux:', error);
return {
channels: []
};
}
}

View file

@ -1,6 +1,21 @@
import { sveltekit } from '@sveltejs/kit/vite'; import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite'; import { type ViteDevServer, defineConfig } from 'vite';
import { Server } from 'socket.io'
const webSocketServer = {
name: 'webSocketServer',
configureServer(server: ViteDevServer) {
if (!server.httpServer) return
const io = new Server(server.httpServer)
io.on('connection', (socket) => {
socket.emit('eventFromServer', 'Hello, World 👋')
})
}
}
export default defineConfig({ export default defineConfig({
plugins: [sveltekit()] plugins: [sveltekit(), webSocketServer]
}); });