diff --git a/controllers/Ad.js b/controllers/Ad.js index 4864ff2fa179d02ea3e7f80b18a6bbdbc304f306..1c4c5b8538d5c177b7baff8e013e9e8fc9687f2b 100644 --- a/controllers/Ad.js +++ b/controllers/Ad.js @@ -81,9 +81,13 @@ router.delete('/:id', extractToken, async (req, res) => { router.get('/:id', extractToken, async (req, res) => { try { const response = await AdService.getAdById(req.params.id, req.token); - utils.writeJson(res, response); + if (response.status === 404) { + res.status(404).json(response); + } else { + utils.writeJson(res, response); + } } catch (error) { - res.status(500).json({message: error.message}); + res.status(500).json({ message: error.message }); } }); diff --git a/controllers/User.js b/controllers/User.js index 37b60759ac8666b84d84733d876527b94b6846ef..77ed0d4a78c4a6653646cbde63959a6a3afcade5 100644 --- a/controllers/User.js +++ b/controllers/User.js @@ -24,7 +24,6 @@ authRouter.post('/login', async (req, res, next) => { try { const {username, password} = req.body; const response = await User.authenticateLocal(username, password); - console.log(response); if (response.status === undefined) { res.json(response); } else { diff --git a/service/AdService.js b/service/AdService.js index b655784bf0bcf72b239ae776378cfb76ffdba7f5..931c68ed2fd17cc3c58fe09fdb9791a57685b6d9 100644 --- a/service/AdService.js +++ b/service/AdService.js @@ -108,11 +108,8 @@ exports.updateAd = async function (adId, reqBody, files, token) { const {title, propertyType, propertyStatus, publicationStatus, description, price, availabilityDate} = reqBody; - const photoPaths = []; - files.forEach(file => { - photoPaths.push(file.filename); - }); + const photoPaths = Array.isArray(files) ? files.map(file => file.filename) : []; const updateAd = await Ad.findByIdAndUpdate( adId, diff --git a/test/ad.test.js b/test/ad.test.js index bcba469d43690bb157c24583596192df6e0456f7..d709c181e914c3e820eb9e279e18279354a8f168 100644 --- a/test/ad.test.js +++ b/test/ad.test.js @@ -4,6 +4,7 @@ const fs = require('fs'); const path = require('path'); const app = require('../index'); const expect = chai.expect; +const mongoose = require('mongoose'); chai.use(chaiHttp); @@ -19,6 +20,23 @@ describe('Ad Routes', () => { .send({ username: 'hajar', password: 'hajar' }); authToken = loginResponse.body.token; + + // Create an ad to get the adId for some tests + const adResponse = await chai + .request(app) + .post('/ad') + .set('Authorization', `Bearer ${authToken}`) + .send({ + title: 'Test Ad', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Test description', + price: 80000, + availabilityDate: '2024-12-01', + }); + + adId = adResponse.body._id; } catch (error) { console.error('Error obtaining authentication token:', error); } @@ -40,7 +58,6 @@ describe('Ad Routes', () => { availabilityDate: '2024-12-01', }); expect(response.body).to.have.property('_id').to.be.a('string'); - adId = response.body._id; }); const backupFolderPath = path.join(__dirname, '..', 'backup'); @@ -64,9 +81,112 @@ describe('Ad Routes', () => { expect(response.body).to.have.property('_id').to.be.a('string'); adId = response.body._id; }); + + it('should not allow a non-authorized user (non-agent) to add a new ad', async () => { + // Log in as a non-agent user + const nonAgentLoginResponse = await chai + .request(app) + .post('/user/login') + .send({ username: 'manal', password: 'manal' }); + + const nonAgentAuthToken = nonAgentLoginResponse.body.token; + + // Attempt to add a new ad as a non-agent user + const response = await chai + .request(app) + .post('/ad') + .set('Authorization', `Bearer ${nonAgentAuthToken}`) + .send({ + title: 'Test Ad', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Test description', + price: 80000, + availabilityDate: '2024-12-01', + }); + + expect(response).to.have.status(403); + expect(response.body).to.have.property('message').to.equal('User non autorisé'); + + const logoutResponse = await chai + .request(app) + .post('/user/logout') + .set('Authorization', `Bearer ${nonAgentAuthToken}`); + + expect(logoutResponse).to.have.status(200); + }); + + }); + + describe('PUT /ads/:id', () => { + it('should update an existing ad with the agent user (hajar)', async () => { + // Log in as the agent user (hajar) + const agentLoginResponse = await chai + .request(app) + .post('/user/login') + .send({ username: 'hajar', password: 'hajar' }); + + const agentAuthToken = agentLoginResponse.body.token; + + // Create a new ad to update + const createResponse = await chai + .request(app) + .post('/ad') + .set('Authorization', `Bearer ${agentAuthToken}`) + .send({ + title: 'Test Ad to update', + propertyType: 'À la vente', + publicationStatus: 'Publiée', + propertyStatus: 'Disponible', + description: 'Test description', + price: 80000, + availabilityDate: '2024-12-01', + }); + + const adIdToUpdate = createResponse.body._id; + + // Update the ad with the agent user (hajar) + const updateResponse = await chai + .request(app) + .put(`/ad/${adIdToUpdate}`) + .set('Authorization', `Bearer ${agentAuthToken}`) + .send({ + title: 'Updated Test Ad', + description: 'Updated description', + price: 90000, + }); + expect(updateResponse).to.have.status(200); + expect(updateResponse.body).to.have.property('_id').to.equal(adIdToUpdate); + expect(updateResponse.body).to.have.property('title').to.equal('Updated Test Ad'); + expect(updateResponse.body).to.have.property('description').to.equal('Updated description'); + expect(updateResponse.body).to.have.property('price').to.equal(90000); + + // Log out the agent user (hajar) + const logoutResponse = await chai + .request(app) + .post('/user/logout') + .set('Authorization', `Bearer ${agentAuthToken}`); + + expect(logoutResponse).to.have.status(200); + }); }); + describe + ('POST /ad/:id/photos', () => { + it('should add photos to an existing ad', async () => { + const imagePath = path.join(__dirname, '..', 'backup', 'img3.jpg'); + const response = await chai + .request(app) + .post(`/ad/${adId}/photos`) + .set('Authorization', `Bearer ${authToken}`) + .attach('photos', fs.readFileSync(imagePath), 'img3.jpg'); + expect(response).to.have.status(200); + expect(response.body).to.have.property('_id'); + expect(response.body.photos).to.be.an('array'); + }); + }); describe('GET /ads', () => { it('should get all ads', async () => { @@ -78,39 +198,55 @@ describe('Ad Routes', () => { expect(response).to.have.status(200); expect(response.body).to.be.an('array'); }); + }); + describe('GET /ad/:id', () => { + it('should get an ad by ID', async () => { + const response = await chai + .request(app) + .get(`/ad/${adId}`) + .set('Authorization', `Bearer ${authToken}`); - // Cleanup after each test - after(async () => { - try { - // Add logic to delete all ads created during the tests - const allAdsResponse = await chai + expect(response).to.have.status(200); + expect(response.body).to.be.an('object'); + expect(response.body).to.have.property('_id').to.equal(adId); + }); + + it('should return 404 for non-existent ad ID', async () => { + const nonExistentAdId = new mongoose.Types.ObjectId(); + const response = await chai .request(app) - .get('/ad') + .get(`/ad/${nonExistentAdId}`) .set('Authorization', `Bearer ${authToken}`); + expect(response).to.have.status(404); + expect(response.body).to.have.property('message').to.equal('Cette annonce est introuvable ou non disponible.'); + }); + }); - if (allAdsResponse.body && allAdsResponse.body.length > 0) { - const deletePromises = allAdsResponse.body.map(async (ad) => { - await chai - .request(app) - .delete(`/ad/${ad._id}`) - .set('Authorization', `Bearer ${authToken}`); - }); + // Cleanup after tests + after(async () => { + try { + // Delete the ad if adId is defined + if (adId) { + await chai + .request(app) + .delete(`/ad/${adId}`) + .set('Authorization', `Bearer ${authToken}`); + } - await Promise.all(deletePromises); + const photo1Path = path.join(__dirname, 'uploads', 'img1.jpg'); + const photo2Path = path.join(__dirname, 'uploads', 'img2.jpg'); + + // Delete the photos + if (fs.existsSync(photo1Path)) { + fs.unlinkSync(photo1Path); } - // Add logic to delete all photos uploaded during the tests - const uploadedPhotosPath = path.join(__dirname, '..', 'uploads'); - if (fs.existsSync(uploadedPhotosPath)) { - fs.readdirSync(uploadedPhotosPath).forEach((file) => { - const filePath = path.join(uploadedPhotosPath, file); - fs.unlinkSync(filePath); - }); - fs.rmdirSync(uploadedPhotosPath); + if (fs.existsSync(photo2Path)) { + fs.unlinkSync(photo2Path); } } catch (error) { - console.error('Error cleaning up after all tests:', error); + console.error('Error cleaning up:', error); } }); });