diff --git a/database/connection.js b/database/connection.js index a96ff52412e99c91be59977af147cf99f1ce2a08..c1c6259e9903a893cde2be78662f6f10837b89a6 100644 --- a/database/connection.js +++ b/database/connection.js @@ -2,7 +2,7 @@ const mongoose = require('mongoose'); require('dotenv').config(); const dbName = process.env.DB_NAME; -const url = `mongodb://monogodb:27017/${dbName}`; +const url = `mongodb://mongodb:27017/${dbName}`; const connectToDatabase = async () => { try { diff --git a/public/backup_uploads/1696775788500-image3.jpg b/public/backup_uploads/1696775788500-image3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/routes/announcement.js b/routes/announcement.js index cfbb2dfceb0949665a913c44c2c4a9f03de061ed..ea083d84f79d1a806d607a3d27089c5ab6e729fa 100644 --- a/routes/announcement.js +++ b/routes/announcement.js @@ -226,9 +226,11 @@ router.get('/delete/:id', isAuthenticated, isAgent, async (req, res) => { const deletedAnnouncement = await Announcement.findByIdAndRemove(announcementId); if (!deletedAnnouncement) { + console.log('404') return res.status(404).json({ message: 'annonce non trouvée' }); } if (user.username !== deletedAnnouncement.userName) { + console.log('403') return res.status(403).json({ message: 'User non autorisé' }); } @@ -250,16 +252,19 @@ router.get('/delete/:id', isAuthenticated, isAgent, async (req, res) => { // Route to delete a photo router.delete('/delete-photo/:announcementId/:filename', isAuthenticated, isAgent, async (req, res) => { try { + console.log('here ') const filename = req.params.filename; const announcementId = req.params.announcementId; const user = req.user; const announcement = await Announcement.findById(announcementId); if (!announcement) { + console.log('Annonce non trouvée') return res.status(404).json({ message: 'Annonce non trouvée' }); } if (!announcement.photos.includes(filename)) { + console.log('Photo non trouvée') return res.status(404).json({ message: 'Photo non trouvée' }); } @@ -280,6 +285,7 @@ router.delete('/delete-photo/:announcementId/:filename', isAuthenticated, isAgen return res.status(200).json({ message: 'Photo supprimée avec succès' }); } else { + console.log('Fichier non trouvé') return res.status(404).json({ message: 'Fichier introuvable' }); } } catch (error) { diff --git a/test/routes.test.js b/test/routes.test.js index aa72fa4f46488bfd36fb5f0f278da07cbbc8b7a4..b808d3001f0e96ac7220911f3deebaa3f71054c3 100644 --- a/test/routes.test.js +++ b/test/routes.test.js @@ -4,7 +4,7 @@ const app = require('../app'); const models = require("../schemas/models"); // Import your Express app const expect = chai.expect; const fs = require('fs'); - +const path = require('path'); chai.use(chaiHttp); describe('Authentication Routes', () => { @@ -511,7 +511,7 @@ describe('POST /add-announcement', () => { availabilityDate: '2023-10-15', }; - const filePath = '/home/firdaous/Téléchargements/img1.jpeg'; + const filePath = 'public/uploads/1696775788500-image2.jpg'; const stats = fs.statSync(filePath); const fileSizeInBytes = stats.size; @@ -526,19 +526,19 @@ describe('POST /add-announcement', () => { .field('availabilityDate', announcementData.availabilityDate) .attach('photos[]', filePath, { filename: 'image.jpg', - contentType: 'image/jpeg', + contentType: 'image/jpg', knownLength: fileSizeInBytes }); expect(res).to.have.status(200); - await new Promise(resolve => setTimeout(resolve, 1500)); + /*await new Promise(resolve => setTimeout(resolve, 1500)); const announcementId = res.body._id; await Announcement.deleteOne({ _id: announcementId }); const uploadedFilePath = `/public/uploads/${res.body.photos[0]}`; if (fs.existsSync(uploadedFilePath)) { fs.unlinkSync(uploadedFilePath); - } + }*/ await agent.get('/logout'); }); @@ -559,7 +559,7 @@ describe('POST /add-announcement', () => { availabilityDate: '2023-10-15', }; - const filePath = '/home/firdaous/Téléchargements/img1.jpeg'; + const filePath = 'public/uploads/1696775788500-image2.jpg'; const stats = fs.statSync(filePath); const fileSizeInBytes = stats.size; @@ -574,7 +574,7 @@ describe('POST /add-announcement', () => { .field('availabilityDate', announcementData.availabilityDate) .attach('photos', filePath, { filename: 'image.jpg', - contentType: 'image/jpeg', + contentType: 'image/jpg', knownLength: fileSizeInBytes }); @@ -588,7 +588,7 @@ describe('POST /add-announcement', () => { }); describe('GET /announcements/delete/:id', () => { - it('should delete an announcement for an authenticated agent', async () => { + it('should delete an announcement for an authenticated agent who s not the owner of the announcement', async () => { const announcement = new Announcement({ title: 'Exemple de titre', propertyType: 'À la vente', @@ -644,6 +644,252 @@ describe('GET /announcements/delete/:id', () => { const deletedAnnouncement = await Announcement.findById(announcement._id); expect(deletedAnnouncement).to.be.null; }); + + it('should not delete an announcement for an authenticated consultant', async () => { + const announcement = new Announcement({ + title: 'Exemple de titre- 2', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Description de l\'annonce', + price: 200, + availabilityDate: new Date('2023-10-15'), + userName: 'rahmouni' + }); + + await announcement.save(); + + const consultant = chai.request.agent(app); + await consultant + .post('/login') + .send({ username: 'hajar', password: 'hajar' }); + + + const res = await consultant + .get(`/announcements/delete/${announcement._id}`) + + expect(res).to.have.status(403); + const deletedAnnouncement = await Announcement.findById(announcement._id); + expect(deletedAnnouncement).not.to.be.null; + }); + + describe('POST /announcements/:id/update', () => { + it('should allow an agent to update its announcement', async function () { + + const announcement = new Announcement({ + title: 'Exemple de titre', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Description de l\'annonce', + price: 10000, + availabilityDate: new Date('2023-10-15'), + userName: 'elhalafi' + }); + + await announcement.save(); + + const agentAgent = chai.request.agent(app); + await agentAgent + .post('/login') + .send({ username: 'elhalafi', password: 'elhalafi' }); + + const updatedAnnouncementData = { + title: 'updated title', + description: 'Description de l\'annonce updated', + }; + const filePath = 'public/uploads/1696775788500-image2.jpg'; + const stats = fs.statSync(filePath); + const fileSizeInBytes = stats.size; + const res = await agentAgent + .post(`/announcements/update/${announcement._id}`) + .field('title', updatedAnnouncementData.title) + .field('description', updatedAnnouncementData.description) + .attach('photos[]', filePath, { + filename: '1696775788500-image2.jpg', + contentType: 'image/jpg', + knownLength: fileSizeInBytes + }); + + expect(res).to.have.status(200); + const updatedAnnouncement = await Announcement.findById(announcement._id); + expect(updatedAnnouncement.title).to.equal(updatedAnnouncementData.title); + expect(updatedAnnouncement.description).to.equal(updatedAnnouncementData.description); + }); + + it('should allow an agent who is not the owner of the ad to update it', async function () { + + const announcement = new Announcement({ + title: 'Exemple de titre', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Description de l\'annonce', + price: 10000, + availabilityDate: new Date('2023-10-15'), + userName: 'elhalafi' + }); + + await announcement.save(); + + const agentAgent = chai.request.agent(app); + await agentAgent + .post('/login') + .send({ username: 'rahmouni', password: 'rahmouni' }); + + const updatedAnnouncementData = { + title: 'updated title', + description: 'Description de l\'annonce updated', + }; + const filePath = 'public/uploads/1696775788500-image2.jpg'; + const stats = fs.statSync(filePath); + const fileSizeInBytes = stats.size; + const res = await agentAgent + .post(`/announcements/update/${announcement._id}`) + .field('title', updatedAnnouncementData.title) + .field('description', updatedAnnouncementData.description) + .attach('photos[]', filePath, { + filename: '1696775788500-image2.jpg', + contentType: 'image/jpg', + knownLength: fileSizeInBytes + }); + + expect(res).to.have.status(403); + const updatedAnnouncement = await Announcement.findById(announcement._id); + expect(updatedAnnouncement.title).to.equal(updatedAnnouncementData.title); + expect(updatedAnnouncement.description).to.equal(updatedAnnouncementData.description); + }); + + it('should not allow a consultant to update an announcement', async function () { + + const announcement = new Announcement({ + title: 'T1 meublé', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Description de l\'annonce', + price: 10000, + availabilityDate: new Date('2023-10-15'), + userName: 'elhalafi' + }); + + await announcement.save(); + + const consultantAgent = chai.request.agent(app); + await consultantAgent + .post('/login') + .send({ username: 'firdaous', password: 'firdaous' }); + + const updatedAnnouncementData = { + title: 'updated title', + description: 'Description de l\'annonce updated', + }; + const filePath = 'public/uploads/1696775788500-image2.jpg'; + const stats = fs.statSync(filePath); + const fileSizeInBytes = stats.size; + const res = await consultantAgent + .post(`/announcements/update/${announcement._id}`) + .field('title', updatedAnnouncementData.title) + .field('description', updatedAnnouncementData.description) + .attach('photos[]', filePath, { + filename: '1696775788500-image2.jpg', + contentType: 'image/jpg', + knownLength: fileSizeInBytes + }); + + expect(res).to.have.status(403); + + // ON s'assure que l'annonce n'a pas été mise à jour + const updatedAnnouncement = await Announcement.findById(announcement._id); + expect(updatedAnnouncement.title).to.equal(announcement.title); + expect(updatedAnnouncement.description).to.equal(announcement.description); + }); + + }); + + describe('DELETE /delete-photo/:announcementId/:filename', () => { + it('should allow an agent to delete a photo from an announcement', async () => { + const agentAgent = chai.request.agent(app); + await agentAgent + .post('/login') + .send({ username: 'elhalafi', password: 'elhalafi' }); + + const announcement = new Announcement({ + title: 'Exemple de titre', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Description de l\'annonce', + price: 10000, + availabilityDate: new Date('2023-10-15'), + userName: 'elhalafi', + photos: ['1696775788500-image3.jpg', '1696775788500-image2.jpg'] + }); + + await announcement.save(); + + const announcementId = announcement._id; + const filenameToDelete = '1696775788500-image2.jpg'; + + const uploads = 'public/backup_uploads'; + const originalFilePath = path.join('public', 'uploads', filenameToDelete); + const backupFilePath = path.join(uploads, filenameToDelete); + + // Copy the file to the backup folder before deleting + if (!fs.existsSync(uploads)) { + fs.mkdirSync(uploads); + } + fs.copyFileSync(originalFilePath, backupFilePath); + + const res = await agentAgent + .delete(`/announcements/delete-photo/${announcementId}/${filenameToDelete}`); + + expect(res).to.have.status(200); + expect(res.body.message).to.equal('Photo supprimée avec succès'); + + const updatedAnnouncement = await Announcement.findById(announcementId); + expect(updatedAnnouncement.photos).to.not.include(filenameToDelete); + + // Restore the file to the uploads folder after the test + fs.copyFileSync(backupFilePath, originalFilePath); + + // Cleanup: Delete the backup file + fs.unlinkSync(backupFilePath); + }); + it('should allow an agent to delete a photo from an announcement that is not its annoucement', async () => { + const agentAgent = chai.request.agent(app); + await agentAgent + .post('/login') + .send({ username: 'hajar', password: 'hajar' }); + + const announcement = new Announcement({ + title: 'Exemple de titre', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Description de l\'annonce', + price: 10000, + availabilityDate: new Date('2023-10-15'), + userName: 'elhalafi', + photos: ['1696775788500-image2.jpg', '1696775788500-image3.jpg'] + }); + + await announcement.save(); + + const announcementId = announcement._id; + const filenameToDelete = '1696775788500-image2.jpg'; + console.log(announcement); + const res = await agentAgent + .delete(`/announcements/delete-photo/${announcementId}/${filenameToDelete}`); + + expect(res).to.have.status(403); + expect(res.body.message).to.equal('Vous n\'êtes pas autorisé à effectuer cette action.'); + + const updatedAnnouncement = await Announcement.findById(announcementId); + expect(updatedAnnouncement.photos).to.include(filenameToDelete); + }); + }); + });