Compare commits
1 Commits
rename
...
lat-lng-sc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0b4bc7879 |
@@ -3,15 +3,8 @@
|
|||||||
|
|
||||||
The purpose of this project is to build a web application that enables subscribing to notifications when new products are published on various ad based marketplaces. The MVP will be only based on OLX.ba
|
The purpose of this project is to build a web application that enables subscribing to notifications when new products are published on various ad based marketplaces. The MVP will be only based on OLX.ba
|
||||||
|
|
||||||
Create postgres docker image
|
|
||||||
docker build -t marketalerts .
|
|
||||||
|
|
||||||
Run postgres image with:
|
Run postgres image with:
|
||||||
docker run --name pg_test -d -p 5432:5432 marketalerts
|
docker run --name pg_test -d -p 5432:5432 marketalerts
|
||||||
|
|
||||||
Run migrations in app folder
|
Run with:
|
||||||
npx sequelize db:migrate
|
|
||||||
|
|
||||||
Run app with:
|
|
||||||
$ npm install
|
|
||||||
$ npm start
|
$ npm start
|
||||||
|
|||||||
7
app/controllers/dobrodosli.js
Normal file
7
app/controllers/dobrodosli.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const getDobrodosli = (req,res) => {
|
||||||
|
res.render('dobrodosli', { nextStep: '/vrstanekretnine' } );
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getDobrodosli
|
||||||
|
};
|
||||||
@@ -2,26 +2,26 @@ const db = require('../models/index');
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require('../helpers/url');
|
||||||
const { regions } = require('../helpers/codes');
|
const { regions } = require('../helpers/codes');
|
||||||
|
|
||||||
const cities = regions();
|
const gradovi = regions();
|
||||||
|
|
||||||
|
|
||||||
const getCity = (req,res) => {
|
const getGrad = (req,res) => {
|
||||||
const nextStep = req.query.nextStep || '/';
|
const nextStep = req.query.nextStep || '/';
|
||||||
res.render('city', {
|
res.render('grad', {
|
||||||
nextStep,
|
nextStep,
|
||||||
cities
|
gradovi
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const postCity = async (req, res) => {
|
const postGrad = async (req, res) => {
|
||||||
const request = await currentRERequest(req);
|
const request = await currentRERequest(req);
|
||||||
const nextStep = req.query.nextStep || `/mjesto/${request.uniqueId}`;
|
const nextStep = req.query.nextStep || `/mjesto/${request.uniqueId}`;
|
||||||
request.city = req.body.city;
|
request.city = req.body.grad;
|
||||||
await request.save();
|
await request.save();
|
||||||
res.redirect(nextStep)
|
res.redirect(nextStep)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getCity,
|
getGrad,
|
||||||
postCity
|
postGrad
|
||||||
};
|
};
|
||||||
@@ -2,24 +2,25 @@ const db = require('../models/index');
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require('../helpers/url');
|
||||||
const { places } = require('../helpers/codes');
|
const { places } = require('../helpers/codes');
|
||||||
|
|
||||||
const getNeighborhood = async (req,res) => {
|
const getMjesto = async (req,res) => {
|
||||||
let request = await currentRERequest(req);
|
let request = await currentRERequest(req);
|
||||||
const neighborhoods = places(request.city);
|
const mjesta = places(request.city);
|
||||||
const nextStep = req.query.nextStep || '/';
|
const nextStep = req.query.nextStep || '/';
|
||||||
res.render('neighborhood', {
|
res.render('mjesto', {
|
||||||
nextStep,
|
nextStep,
|
||||||
neighborhoods
|
mjesta
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const postgNeighborhood = async (req, res) => {
|
const postMjesto = async (req, res) => {
|
||||||
let request = await currentRERequest(req);
|
let request = await currentRERequest(req);
|
||||||
request.neighborhood = req.body.neighborhood;
|
request.place = req.body.mjesto;
|
||||||
|
console.log("AAA ", req.body);
|
||||||
await request.save();
|
await request.save();
|
||||||
res.send("Result is " + JSON.stringify(request));
|
res.send("Result is " + JSON.stringify(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getNeighborhood,
|
getMjesto,
|
||||||
postgNeighborhood
|
postMjesto
|
||||||
};
|
};
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
const db = require('../models/index');
|
const db = require('../models/index');
|
||||||
|
|
||||||
const realEstateTypes = [
|
const vrsteNekretnina = [
|
||||||
{ ime: "Kuća", id: "kuca" },
|
{ ime: "Kuća", id: "kuca" },
|
||||||
{ ime: "Stan", id: "stan" },
|
{ ime: "Stan", id: "stan" },
|
||||||
{ ime: "Vikendica", id: "vikendica" }
|
{ ime: "Vikendica", id: "vikendica" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const getRealEstateTypes = (req,res) => {
|
const getVrstaNekretnine = (req,res) => {
|
||||||
const nextStep = req.query.nextStep;
|
const nextStep = req.query.nextStep;
|
||||||
res.render('real_estate_type', {
|
res.render('vrsta_nekretnine', {
|
||||||
nextStep,
|
nextStep,
|
||||||
realEstateTypes: realEstateTypes
|
vrste: vrsteNekretnina
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const postRealEstateTypes = (req, res) => {
|
const postVrstaNekretnine = (req, res) => {
|
||||||
let nextStep = req.query.nextStep;
|
let nextStep = req.query.nextStep;
|
||||||
|
|
||||||
db.RealEstateRequest.create({
|
db.RealEstateRequest.create({
|
||||||
realEstateType: req.body.realestatetype
|
realEstateType: req.body.vrsta
|
||||||
}).then( (result) => {
|
}).then( (result) => {
|
||||||
nextStep = nextStep || `/grad/${result.uniqueId}`;
|
nextStep = nextStep || `/grad/${result.uniqueId}`;
|
||||||
res.redirect(nextStep);
|
res.redirect(nextStep);
|
||||||
@@ -29,6 +30,6 @@ const postRealEstateTypes = (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getRealEstateTypes,
|
getVrstaNekretnine,
|
||||||
postRealEstateTypes
|
postVrstaNekretnine
|
||||||
};
|
};
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
const getWelcome = (req,res) => {
|
|
||||||
res.render('welcome', { nextStep: '/vrstanekretnine' } );
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getWelcome
|
|
||||||
};
|
|
||||||
27
app/helpers/scraping.js
Normal file
27
app/helpers/scraping.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
let fetch = require("node-fetch");
|
||||||
|
|
||||||
|
const getRealEstateGeolocation = async (url) => {
|
||||||
|
let response = await fetch(url);
|
||||||
|
const body = await response.text();
|
||||||
|
let lat, long;
|
||||||
|
const googleMapRegex = new RegExp(/google.maps.LatLng\((.*?)\)/g);
|
||||||
|
const googleMapString = body.match(googleMapRegex);
|
||||||
|
if (googleMapString && googleMapString.length) {
|
||||||
|
const latLongRegex = new RegExp(/\((.*?)\)/g);
|
||||||
|
let latLongString = googleMapString[0].match(latLongRegex);
|
||||||
|
if (latLongString && latLongString.length) {
|
||||||
|
latLongString = latLongString[0].trim();
|
||||||
|
latLongString = latLongString.substr(1, latLongString.length - 2);
|
||||||
|
const latLongArray = latLongString.split(",");
|
||||||
|
if (latLongArray.length) {
|
||||||
|
lat = latLongArray[0];
|
||||||
|
long = latLongArray[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { lat, long };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getRealEstateGeolocation
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@ const currentRERequest = async (req) => {
|
|||||||
if(!uniqueId) return null;
|
if(!uniqueId) return null;
|
||||||
|
|
||||||
const request = await db.RealEstateRequest.findOne({ where: {uniqueId} });
|
const request = await db.RealEstateRequest.findOne({ where: {uniqueId} });
|
||||||
|
console.log("Request ", request);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.welcome-center-button {
|
.dobrodosli-center-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.welcome-big-logo {
|
.dobrodosli-big-logo {
|
||||||
font-size: 200pt;
|
font-size: 200pt;
|
||||||
background-image: url(./images/logo.png);
|
background-image: url(./images/logo.png);
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
<div class="row center-align">
|
|
||||||
<h2>U kojoj regiji tražite nekretninu?</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form method="POST" id="form-city">
|
|
||||||
<div class="row center-align">
|
|
||||||
<ul class="collection with-header">
|
|
||||||
<% for(const city of cities) { %>
|
|
||||||
<li class="collection-item" >
|
|
||||||
<div id="<%= city.id %>" ><%= city.ime %>
|
|
||||||
<a href="#!" class="secondary-content">
|
|
||||||
<i class="material-icons">send</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<% } %>
|
|
||||||
</ul>
|
|
||||||
<input type="hidden" name="city" id="city" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(document).ready( () => {
|
|
||||||
$(".collection-item").click( (e) => {
|
|
||||||
const clickedId = $(e.target).attr("id");
|
|
||||||
$("#city").val(clickedId);
|
|
||||||
$("#form-city").submit();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<div class="row center-align">
|
<div class="row center-align">
|
||||||
<span class="welcome-big-logo">🤙</span>
|
<span class="dobrodosli-big-logo">🤙</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row center-align">
|
<div class="row center-align">
|
||||||
<div>Sve nekretnine dostupne u oglasima.</div>
|
<div>Sve nekretnine dostupne u oglasima.</div>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col s6 push-s3">
|
<div class="col s6 push-s3">
|
||||||
<a href="<%= nextStep %>" class="welcome-center-button waves-effect waves-light btn">
|
<a href="<%= nextStep %>" class="dobrodosli-center-button waves-effect waves-light btn">
|
||||||
Javi mi
|
Javi mi
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
25
app/views/grad.ejs
Normal file
25
app/views/grad.ejs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<div class="row center-align">
|
||||||
|
<h2>U kojoj regiji tražite nekretninu?</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="POST" id="form-grad">
|
||||||
|
<div class="row center-align">
|
||||||
|
<ul class="collection with-header">
|
||||||
|
<% for(const grad of gradovi) { %>
|
||||||
|
<li class="collection-item" > <div id="<%= grad.id %>" ><%= grad.ime %><a href="#!" class="secondary-content"><i class="material-icons">send</i></a></div></li>
|
||||||
|
<% } %>
|
||||||
|
</ul>
|
||||||
|
<input type="hidden" name="grad" id="grad" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready( () => {
|
||||||
|
$(".collection-item").click( (e) => {
|
||||||
|
const clickedId = $(e.target).attr("id");
|
||||||
|
$("#grad").val(clickedId);
|
||||||
|
$("#form-grad").submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
25
app/views/mjesto.ejs
Normal file
25
app/views/mjesto.ejs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<div class="row center-align">
|
||||||
|
<h2>U kojem mjestu tražite nekretninu?</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="POST" id="form-mjesto">
|
||||||
|
<div class="row center-align">
|
||||||
|
<ul class="collection with-header">
|
||||||
|
<% for(const mjesto of mjesta) { %>
|
||||||
|
<li class="collection-item" > <div id="<%= mjesto.id %>" ><%= mjesto.ime %><a href="#!" class="secondary-content"><i class="material-icons">send</i></a></div></li>
|
||||||
|
<% } %>
|
||||||
|
</ul>
|
||||||
|
<input type="hidden" name="mjesto" id="mjesto" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready( () => {
|
||||||
|
$(".collection-item").click( (e) => {
|
||||||
|
const clickedId = $(e.target).attr("id");
|
||||||
|
$("#mjesto").val(clickedId);
|
||||||
|
$("#form-mjesto").submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<div class="row center-align">
|
|
||||||
<h2>U kojem mjestu tražite nekretninu?</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form method="POST" id="form-neighborhood">
|
|
||||||
<div class="row center-align">
|
|
||||||
<ul class="collection with-header">
|
|
||||||
<% for(const neighborhood of neighborhoods) { %>
|
|
||||||
<li class="collection-item" >
|
|
||||||
<div id="<%= neighborhood.id %>" ><%= neighborhood.ime %>
|
|
||||||
<a href="#!" class="secondary-content">
|
|
||||||
<i class="material-icons">send</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<% } %>
|
|
||||||
</ul>
|
|
||||||
<input type="hidden" name="neighborhood" id="neighborhoods" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(document).ready( () => {
|
|
||||||
$(".collection-item").click( (e) => {
|
|
||||||
const clickedId = $(e.target).attr("id");
|
|
||||||
$("#neighborhood").val(clickedId);
|
|
||||||
$("#form-neighborhood").submit();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<div class="row center-align">
|
|
||||||
<h2>Koju nekretninu tražite?</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form method="POST" id="form-real-estate-type">
|
|
||||||
<div class="row center-align">
|
|
||||||
<ul class="collection with-header">
|
|
||||||
<% for(const realEstatetype of realEstateTypes) { %>
|
|
||||||
<li class="collection-item" >
|
|
||||||
<div id="<%= realEstatetype.id %>" ><%= realEstatetype.ime %>
|
|
||||||
<a href="#!" class="secondary-content">
|
|
||||||
<i class="material-icons">send</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<% } %>
|
|
||||||
</ul>
|
|
||||||
<input type="hidden" name="realestatetype" id="realestatetype" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(document).ready( () => {
|
|
||||||
$(".collection-item").click( (e) => {
|
|
||||||
const clickedId = $(e.target).attr("id");
|
|
||||||
$("#realestatetype").val(clickedId);
|
|
||||||
$("#form-real-estate-type").submit();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
29
app/views/vrsta_nekretnine.ejs
Normal file
29
app/views/vrsta_nekretnine.ejs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<div class="row center-align">
|
||||||
|
<h2>Koju nekretninu tražite?</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="POST" id="form-vrsta">
|
||||||
|
<div class="row center-align">
|
||||||
|
<ul class="collection with-header">
|
||||||
|
<% for(let vrsta of vrste) { %>
|
||||||
|
<li class="collection-item" > <div id="<%= vrsta.id %>" ><%= vrsta.ime %><a href="#!" class="secondary-content"><i class="material-icons">send</i></a></div></li>
|
||||||
|
<% } %>
|
||||||
|
</ul>
|
||||||
|
<input type="hidden" name="vrsta" id="vrsta" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready( () => {
|
||||||
|
$(".collection-item").click( (e) => {
|
||||||
|
const clickedId = $(e.target).attr("id");
|
||||||
|
$("#vrsta").val(clickedId);
|
||||||
|
$("#form-vrsta").submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
26
index.js
26
index.js
@@ -1,7 +1,7 @@
|
|||||||
const welcome = require('./app/controllers/welcome').getWelcome;
|
const dobrodosli = require('./app/controllers/dobrodosli').getDobrodosli;
|
||||||
const { getRealEstateTypes, postRealEstateTypes} = require('./app/controllers/real_estate_types');
|
const { getVrstaNekretnine, postVrstaNekretnine} = require('./app/controllers/vrsta_nekretnine');
|
||||||
const { getCity, postCity } = require('./app/controllers/city');
|
const { getGrad, postGrad } = require('./app/controllers/grad');
|
||||||
const { getNeighborhood, postgNeighborhood } = require('./app/controllers/neighborhoods');
|
const { getMjesto, postMjesto } = require('./app/controllers/mjesto');
|
||||||
|
|
||||||
let express = require("express");
|
let express = require("express");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
@@ -108,18 +108,18 @@ app.post("/api/payforalert", function(request, response) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/', welcome);
|
app.get('/', dobrodosli);
|
||||||
app.get('/vrstanekretnine/:request_id', getRealEstateTypes);
|
app.get('/vrstanekretnine/:request_id', getVrstaNekretnine);
|
||||||
app.get('/vrstanekretnine', getRealEstateTypes);
|
app.get('/vrstanekretnine', getVrstaNekretnine);
|
||||||
|
|
||||||
app.post('/vrstanekretnine/:request_id', postRealEstateTypes);
|
app.post('/vrstanekretnine/:request_id', postVrstaNekretnine);
|
||||||
app.post('/vrstanekretnine', postRealEstateTypes);
|
app.post('/vrstanekretnine', postVrstaNekretnine);
|
||||||
|
|
||||||
app.get('/grad/:request_id', getCity);
|
app.get('/grad/:request_id', getGrad);
|
||||||
app.post('/grad/:request_id', postCity);
|
app.post('/grad/:request_id', postGrad);
|
||||||
|
|
||||||
app.get('/mjesto/:request_id', getNeighborhood);
|
app.get('/mjesto/:request_id', getMjesto);
|
||||||
app.post('/mjesto/:request_id', postgNeighborhood);
|
app.post('/mjesto/:request_id', postMjesto);
|
||||||
|
|
||||||
|
|
||||||
app.use('/assets', express.static('./app/public'))
|
app.use('/assets', express.static('./app/public'))
|
||||||
|
|||||||
Reference in New Issue
Block a user