diff --git a/.gitignore b/.gitignore index 60338bff901424a518ab6be3fd5035e33d9452fb..229b0a877ab83569c54016a43366479aaa6136f6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ node_modules/ # IDE .idea/ # MongoDB -.data/ \ No newline at end of file +.data/ +#photos +.public/uploads/* diff --git a/app.js b/app.js index b913d3ef8f2303a75b3bcf5f9ebfd58f78b285d0..0863c3f7688cebff33508e26b89322facd90cdd3 100644 --- a/app.js +++ b/app.js @@ -20,6 +20,7 @@ const connectToDatabase = require('./database/connection'); var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users'); var authentifcationRouter = require('./routes/authentification'); +const announcementsRouter = require('./routes/announcement'); var app = express(); @@ -67,8 +68,9 @@ app.use(passport.initialize()); app.use(passport.session()); //app.use('/', indexRouter); -app.use('/', authentifcationRouter); +app.use('/', authentifcationRouter.router); app.use('/users', usersRouter); +app.use('/announcements', announcementsRouter); // catch 404 and forward to error handler app.use(function(req, res, next) { @@ -93,6 +95,8 @@ app.use(function(err, req, res, next) { res.render('error'); }); + + /* // error handlers diff --git a/models/account.js b/models/account.js deleted file mode 100644 index 3577372e27d04f6f553820eb3afdc0d57bbc8536..0000000000000000000000000000000000000000 --- a/models/account.js +++ /dev/null @@ -1,12 +0,0 @@ -var mongoose = require('mongoose'); -var Schema = mongoose.Schema; -var passportLocalMongoose = require('passport-local-mongoose'); - -var Account = new Schema({ - username: String, - password: String -}); - -Account.plugin(passportLocalMongoose); - -module.exports = mongoose.model('Account', Account); diff --git a/multer-config.js b/multer-config.js new file mode 100644 index 0000000000000000000000000000000000000000..a695df03bc31da7a67029849928f6a9eadcbc43a --- /dev/null +++ b/multer-config.js @@ -0,0 +1,14 @@ +const multer = require('multer'); + +const storage = multer.diskStorage({ + destination: function (req, file, cb) { + cb(null, 'public/uploads'); + }, + filename: function (req, file, cb) { + cb(null, Date.now() + '-' + file.originalname); + } +}); + +const upload = multer({ storage: storage }); + +module.exports = upload; diff --git a/package-lock.json b/package-lock.json index 6b81571a11c0f05c0abccc327013252475d0a09e..727cfaaeba7b3e6b234d7179632f3625af5824ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "express": "~4.16.1", "express-session": "^1.17.3", "http-errors": "~1.6.3", + "moment": "^2.29.4", "mongodb": "^6.1.0", "mongoose": "^7.5.2", "morgan": "~1.9.1", @@ -1219,6 +1220,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/mongodb": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.1.0.tgz", diff --git a/package.json b/package.json index 04ffbb536987d22b0f6d5095d610a153ec042081..50e8144dae08d011648f013c0416a3e54b7c397a 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "express": "~4.16.1", "express-session": "^1.17.3", "http-errors": "~1.6.3", + "moment": "^2.29.4", "mongodb": "^6.1.0", "mongoose": "^7.5.2", "morgan": "~1.9.1", diff --git a/passport-config.js b/passport-config.js index 77b539bdc49e4dbdad51a85b2a2d81b3b7f736ee..1678862eb4a7f434915a96f07957577376332beb 100644 --- a/passport-config.js +++ b/passport-config.js @@ -1,7 +1,9 @@ const passport = require('passport'); const LocalStrategy = require('passport-local').Strategy; -const User = require('./schemas/models'); +const models = require('./schemas/models'); + +const User = models.User; passport.use(new LocalStrategy( { usernameField: 'username' }, diff --git a/public/uploads/.gitkeep b/public/uploads/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/public/uploads/1696602445561-img2.jpeg b/public/uploads/1696602445561-img2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d23c0b253fd8722980efe9430e61b4e57321fd7b Binary files /dev/null and b/public/uploads/1696602445561-img2.jpeg differ diff --git a/public/uploads/1696604598903-img2.jpeg b/public/uploads/1696604598903-img2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d23c0b253fd8722980efe9430e61b4e57321fd7b Binary files /dev/null and b/public/uploads/1696604598903-img2.jpeg differ diff --git a/public/uploads/1696605084900-img1.jpeg b/public/uploads/1696605084900-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696605084900-img1.jpeg differ diff --git a/public/uploads/1696605276843-img1.jpeg b/public/uploads/1696605276843-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696605276843-img1.jpeg differ diff --git a/public/uploads/1696605304203-img2.jpeg b/public/uploads/1696605304203-img2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d23c0b253fd8722980efe9430e61b4e57321fd7b Binary files /dev/null and b/public/uploads/1696605304203-img2.jpeg differ diff --git a/public/uploads/1696606194070-img1.jpeg b/public/uploads/1696606194070-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696606194070-img1.jpeg differ diff --git a/public/uploads/1696606963753-img2.jpeg b/public/uploads/1696606963753-img2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d23c0b253fd8722980efe9430e61b4e57321fd7b Binary files /dev/null and b/public/uploads/1696606963753-img2.jpeg differ diff --git a/public/uploads/1696606970147-img2.jpeg b/public/uploads/1696606970147-img2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d23c0b253fd8722980efe9430e61b4e57321fd7b Binary files /dev/null and b/public/uploads/1696606970147-img2.jpeg differ diff --git a/public/uploads/1696607932544-img1.jpeg b/public/uploads/1696607932544-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696607932544-img1.jpeg differ diff --git a/public/uploads/1696607945459-img1.jpeg b/public/uploads/1696607945459-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696607945459-img1.jpeg differ diff --git a/public/uploads/1696608328834-img1.jpeg b/public/uploads/1696608328834-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696608328834-img1.jpeg differ diff --git a/public/uploads/1696608390204-img1.jpeg b/public/uploads/1696608390204-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696608390204-img1.jpeg differ diff --git a/public/uploads/1696608405897-img1.jpeg b/public/uploads/1696608405897-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696608405897-img1.jpeg differ diff --git a/public/uploads/1696608457229-img1.jpeg b/public/uploads/1696608457229-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696608457229-img1.jpeg differ diff --git a/public/uploads/1696610004725-img2.jpeg b/public/uploads/1696610004725-img2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d23c0b253fd8722980efe9430e61b4e57321fd7b Binary files /dev/null and b/public/uploads/1696610004725-img2.jpeg differ diff --git a/public/uploads/1696610065768-img1.jpeg b/public/uploads/1696610065768-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696610065768-img1.jpeg differ diff --git a/public/uploads/1696610200951-img2.jpeg b/public/uploads/1696610200951-img2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d23c0b253fd8722980efe9430e61b4e57321fd7b Binary files /dev/null and b/public/uploads/1696610200951-img2.jpeg differ diff --git a/public/uploads/1696610309899-img1.jpeg b/public/uploads/1696610309899-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696610309899-img1.jpeg differ diff --git a/public/uploads/1696610489472-img2.jpeg b/public/uploads/1696610489472-img2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d23c0b253fd8722980efe9430e61b4e57321fd7b Binary files /dev/null and b/public/uploads/1696610489472-img2.jpeg differ diff --git a/public/uploads/1696610666789-img1.jpeg b/public/uploads/1696610666789-img1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..61ec568836a59cbfab2d4a592cdd1365a51f851b Binary files /dev/null and b/public/uploads/1696610666789-img1.jpeg differ diff --git a/routes/announcement.js b/routes/announcement.js new file mode 100644 index 0000000000000000000000000000000000000000..7ad05f037f206ab41b47a2febea60058a45f8513 --- /dev/null +++ b/routes/announcement.js @@ -0,0 +1,68 @@ +const express = require('express'); +const router = express.Router(); +const models = require('../schemas/models'); +const routes = require('./authentification'); +const upload = require('../multer-config') + + +const Announcement = models.Announcement; +const isAuthenticated = routes.isAuthenticated; + +// Route pour récupérer toutes les annonces +router.get('/', async (req, res) => { + try { + const announcements = await Announcement.find(); + let isAuthenticated = false; + if (req.isAuthenticated()) { + isAuthenticated = true; + } + res.render('announcements', { announcements: announcements, isAuthenticated: isAuthenticated }); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); + +// Route pour afficher la page d'ajout d'annonce +router.get('/add-announcement', isAuthenticated, (req, res) => { + res.render('add_announcement'); +}); + +// details de l'annonce +router.get('/:id', async (req, res) => { + try { + const announcementId = req.params.id; + const announcementDetails = await Announcement.findById(announcementId); + res.render('announcement_details', { announcement: announcementDetails }); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); + +router.post('/add-announcement', isAuthenticated, upload.array('photos', ), async (req, res) => { + const { title, propertyType, publicationStatus, propertyStatus, description, price, availabilityDate} = req.body; + const photos = req.files.map(file => file.filename); + + const user = req.user; + + const newAnnouncement = new Announcement({ + title, + propertyType, + publicationStatus, + propertyStatus, + description, + price, + availabilityDate, + photos, + userName: user.username + }); + + try { + await newAnnouncement.save(); + const announcements = await Announcement.find(); + res.redirect('/announcements'); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); + +module.exports = router; diff --git a/routes/authentification.js b/routes/authentification.js index 8ceb94bb4932059011de6737396c8388dd856fa4..f4e8f7c40b21a5b48523367827c168517197d010 100644 --- a/routes/authentification.js +++ b/routes/authentification.js @@ -1,16 +1,21 @@ var express = require('express'); var router = express.Router(); const passport = require('../passport-config'); -const User = require('../schemas/models'); +const models = require('../schemas/models'); +const User = models.User; /* GET home page. */ router.get('/', function(req, res, next) { + res.redirect('/announcements'); +}); + +router.get('/authentification', function(req, res, next) { res.render('authentification'); }); router.post('/authentification', passport.authenticate('local', { - successRedirect: '/dashboard', - failureRedirect: '/' + successRedirect: '/announcements', + failureRedirect: '/authentification' })); router.get('/dashboard', isAuthenticated, function(req, res, next) { @@ -45,9 +50,9 @@ router.post('/register', async function(req, res) { }); await newUser.save(); - passport.authenticate('local')(req, res, function () { - res.redirect('/'); - }); + // passport.authenticate('local')(req, res, function () { + res.redirect('/authentification'); + //}); } catch (error) { res.render('register', { error: error.message }); } @@ -66,7 +71,10 @@ function isAuthenticated(req, res, next) { if (req.isAuthenticated()) { return next(); } - res.redirect('/'); + res.redirect('/authentification'); } -module.exports = router; \ No newline at end of file +module.exports = { + router: router, + isAuthenticated: isAuthenticated +}; \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 61e3b6acaf1457a8c7c48e222f0a8d7fe11a72a9..d88e6e3d6f7ac0d40dab19cc86941c2c389a97d3 100644 --- a/routes/index.js +++ b/routes/index.js @@ -8,9 +8,11 @@ router.get('/', function (req, res) { res.render('index', { user : req.user }); }); +/* router.get('/register', function(req, res) { res.render('register', { }); }); +*/ router.post('/register', async function(req, res) { /*User.register(new User({ username : req.body.username }), req.body.password, function(err, account) { diff --git a/schemas/models.js b/schemas/models.js index d961e582fd4922276c8dd166efac8a92430923bd..455d138c4926fc783789bd33b96c8a4726b3e7b7 100644 --- a/schemas/models.js +++ b/schemas/models.js @@ -13,6 +13,23 @@ userSchema.methods.validPassword = function(password) { return this.password === password; }; +const announcementSchema = new Schema({ + title: { type: String, required: true }, + propertyType: { type: String, required: true }, + publicationStatus: { type: String, required: true }, + propertyStatus: { type: String, required: true }, + description: { type: String, required: true }, + price: { type:Number, required: true }, + availabilityDate: { type: Date, required: true }, + photos:{ type: [String] }, + userName: { type: String, required: true } +}); + const User = mongoose.model('User', userSchema); -module.exports = User; +const Announcement = mongoose.model('Announcement', announcementSchema); + +module.exports = { + User: User, + Announcement: Announcement +}; diff --git a/views/add_announcement.pug b/views/add_announcement.pug new file mode 100644 index 0000000000000000000000000000000000000000..b3fcf95d2499a72e4502908d5d7151bab8b3307e --- /dev/null +++ b/views/add_announcement.pug @@ -0,0 +1,50 @@ +doctype html +html(lang="en") + head + meta(charset="UTF-8") + meta(name="viewport", content="width=device-width, initial-scale=1.0") + title Ajouter une Annonce + link(rel="stylesheet", href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css") + + body + .container.mt-5 + + h1 Ajouter une Annonce + + form(action="/announcements/add-announcement", method="post", enctype="multipart/form-data") + .form-group + label(for="title") Titre + input#title.form-control(type="text", name="title", required) + + .form-group + label(for="propertyType") Type de Bien + input#propertyType.form-control(type="text", name="propertyType", required) + + .form-group + label(for="price") Prix + input#price.form-control(type="text", name="price", required, pattern="[0-9]+(\.[0-9]{1,2})?", title="Veuillez entrer un nombre") + + .form-group + label(for="availabilityDate") Date de disponibilité + input#availabilityDate.form-control(type="date", name="availabilityDate", required) + + + .form-group + label(for="description") Description + textarea#description.form-control(name="description", required) + + .form-group + label(for="publicationStatus") Statut Publication + input#publicationStatus.form-control(type="text", name="publicationStatus", required) + + .form-group + label(for="propertyStatus") Statut Bien + input#propertyStatus.form-control(type="text", name="propertyStatus", required) + + .form-group + label(for="photos") Photos + input#photos.form-control(type="file", name="photos", accept="image/*", multiple) + + button.btn.btn-primary(type="submit") Ajouter l'annonce + a.btn.btn-secondary(href="/announcements") Annuler + diff --git a/views/announcement_details.pug b/views/announcement_details.pug new file mode 100644 index 0000000000000000000000000000000000000000..281be7b0557cd9ba4225d4b1e69a418233af674b --- /dev/null +++ b/views/announcement_details.pug @@ -0,0 +1,28 @@ +doctype html +html(lang="en") + head + meta(charset="UTF-8") + meta(name="viewport", content="width=device-width, initial-scale=1, shrink-to-fit=no") + title Détails de l'Annonce + link(href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css", rel="stylesheet") + body + .container.mt-5 + .row + .col-md-8.offset-md-2 + .card + .card-body + h5.card-title= announcement.title + p.card-text Type de Bien: #{announcement.propertyType} + p.card-text Prix: #{announcement.price}€ + p.card-text Description: #{announcement.description} + p.card-text Statut Publication: #{announcement.publicationStatus} + p.card-text Statut Bien: #{announcement.propertyStatus} + - var date = new Date(announcement.availabilityDate); + - var options = { year: 'numeric', month: 'long', day: 'numeric' }; + - var frenchDate = date.toLocaleDateString('fr-FR', options); + p.card-text Date de Disponibilité: #{frenchDate} + + if announcement.photos.length > 0 + each photo in announcement.photos + img.card-img-top(src=`/uploads/${photo}`, alt=announcement.title) + diff --git a/views/announcements.pug b/views/announcements.pug new file mode 100644 index 0000000000000000000000000000000000000000..c07dd042d89b377cf3240834d14a8a35b69b76d2 --- /dev/null +++ b/views/announcements.pug @@ -0,0 +1,27 @@ +doctype html +html(lang="en") + head + meta(charset="UTF-8") + meta(name="viewport", content="width=device-width, initial-scale=1, shrink-to-fit=no") + title Liste des Annonces Immobilières + link(href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css", rel="stylesheet") + body + .container.mt-5 + .d-flex.justify-content-between.mb-3 + h1 Liste des Annonces Immobilières + form(action="/announcements/add-announcement", method="get") + .d-flex + button.btn.btn-primary.mr-2(type="submit") Ajouter une Annonce + if isAuthenticated + a.btn.btn-danger(href="/logout") Déconnexion + + .row + each announcement in announcements + .col-md-4.mb-4 + .card + img.card-img-top(src=`/uploads/${announcement.photos[0]}`, alt=announcement.title) + .card-body + h5.card-title= announcement.title + p.card-text= announcement.propertyType + p.card-text= announcement.price + '€' + a.btn.btn-primary(href=`/announcements/${announcement._id}`) Voir les détails