Merge branch 'project-fixes' into 'master'
Project fixes See merge request saburly/marketalarm/web!26
This commit was merged in pull request #26.
This commit is contained in:
9
app/config/appConfig.js
Normal file
9
app/config/appConfig.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const APP_PORT = process.env.APP_PORT || 5000;
|
||||||
|
const APP_BASE_URL = process.env.APP_BASE_URL || "http://localhost";
|
||||||
|
|
||||||
|
const APP_URL = `${APP_BASE_URL}:${APP_PORT}`;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
APP_PORT,
|
||||||
|
APP_URL
|
||||||
|
};
|
||||||
@@ -1,32 +1,31 @@
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
const { getRealEstateTypeEnum } = require('../helpers/enums');
|
const { getRealEstateTypeEnum } = require("../helpers/enums");
|
||||||
|
|
||||||
const getGardenSize = (req,res) => {
|
const getGardenSize = (req, res) => {
|
||||||
|
const title = "Koliko okućnice tražite ?";
|
||||||
|
|
||||||
const title = "Koliko okućnice tražite ?"
|
const unit = " m2";
|
||||||
|
|
||||||
const unit = " m2"
|
|
||||||
const rangeFrom = {
|
const rangeFrom = {
|
||||||
min : 10,
|
min: 10,
|
||||||
max : 3000,
|
max: 3000,
|
||||||
value : 0,
|
value: 0,
|
||||||
step : 10
|
step: 10
|
||||||
}
|
};
|
||||||
|
|
||||||
const rangeTo = {
|
const rangeTo = {
|
||||||
min : 10,
|
min: 10,
|
||||||
max : 3000,
|
max: 3000,
|
||||||
value : 100,
|
value: 100,
|
||||||
step : 10
|
step: 10
|
||||||
}
|
};
|
||||||
|
|
||||||
res.render('gardenSize', { rangeFrom, rangeTo, unit, title });
|
res.render("gardenSize", { rangeFrom, rangeTo, unit, title });
|
||||||
};
|
};
|
||||||
|
|
||||||
const postGardenSize = async (req, res) => {
|
const postGardenSize = async (req, res) => {
|
||||||
const request = await currentRERequest(req);
|
const request = await currentRERequest(req);
|
||||||
|
|
||||||
const nextStepPage = req.query.nextStep || 'cijena';
|
const nextStepPage = req.query.nextStep || "cijena";
|
||||||
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
||||||
|
|
||||||
const realEstateType = getRealEstateTypeEnum(request.realEstateType);
|
const realEstateType = getRealEstateTypeEnum(request.realEstateType);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const getGoAgain = async (req,res) => {
|
const getGoAgain = async (req, res) => {
|
||||||
const title = "Želite li pretražiti još jednu nekretninu ?";
|
const title = "Želite li pretražiti još jednu nekretninu ?";
|
||||||
res.render('goAgain', {title});
|
res.render("goAgain", { title });
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
const { getMunicipalitiesForRegion, getMunicipalityName } = require('../helpers/codes');
|
const {
|
||||||
|
getMunicipalitiesForRegion,
|
||||||
|
getMunicipalityName
|
||||||
|
} = require("../helpers/codes");
|
||||||
|
|
||||||
const getMunicipality = async (req, res) => {
|
const getMunicipality = async (req, res) => {
|
||||||
|
const title = "U kojem mjestu tražite nekretninu?";
|
||||||
const title = "U kojem mjestu tražite nekretninu?"
|
|
||||||
let request = await currentRERequest(req);
|
let request = await currentRERequest(req);
|
||||||
const municipalities = getMunicipalitiesForRegion(request.region);
|
const municipalities = getMunicipalitiesForRegion(request.region);
|
||||||
|
|
||||||
res.render('municipality', { municipalities, title });
|
res.render("municipality", { municipalities, title });
|
||||||
};
|
};
|
||||||
|
|
||||||
const postMunicipality = async (req, res) => {
|
const postMunicipality = async (req, res) => {
|
||||||
|
|
||||||
const request = await currentRERequest(req);
|
const request = await currentRERequest(req);
|
||||||
const nextStepParam = req.query.nextStep ? "?nextStep=" + req.query.nextStep : "";
|
const nextStepParam = req.query.nextStep
|
||||||
const nextStepUrl = `/${'naselje'}/${request.uniqueId}/${getMunicipalityName(request.region, req.body.municipality)}${nextStepParam}`;
|
? "?nextStep=" + req.query.nextStep
|
||||||
|
: "";
|
||||||
|
const nextStepUrl = `/${"naselje"}/${request.uniqueId}/${getMunicipalityName(
|
||||||
|
request.region,
|
||||||
|
req.body.municipality
|
||||||
|
)}${nextStepParam}`;
|
||||||
|
|
||||||
request.municipality = req.body.municipality;
|
request.municipality = req.body.municipality;
|
||||||
await request.save();
|
await request.save();
|
||||||
|
|||||||
@@ -1,41 +1,37 @@
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
|
|
||||||
const getNeighborhood = async (req, res) => {
|
const getNeighborhood = async (req, res) => {
|
||||||
|
const title = "U kojem naselju tražite nekretninu?";
|
||||||
|
const municipality = req.params.municipality;
|
||||||
|
const nextStep = req.query.nextStep || "/";
|
||||||
|
|
||||||
const title = "U kojem naselju tražite nekretninu?"
|
res.render("neighborhoodMap", {
|
||||||
const municipality = req.params.municipality
|
nextStep,
|
||||||
const nextStep = req.query.nextStep || '/';
|
municipality,
|
||||||
|
title
|
||||||
res.render('neighborhoodMap', {
|
});
|
||||||
nextStep,
|
|
||||||
municipality,
|
|
||||||
title
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const postNeighborhood = async (req, res) => {
|
const postNeighborhood = async (req, res) => {
|
||||||
let request = await currentRERequest(req);
|
let request = await currentRERequest(req);
|
||||||
const northWest = [req.body.west, req.body.north];
|
const northWest = [req.body.west, req.body.north];
|
||||||
const northEast = [req.body.east, req.body.north];
|
const northEast = [req.body.east, req.body.north];
|
||||||
const southEast = [req.body.east, req.body.south];
|
const southEast = [req.body.east, req.body.south];
|
||||||
const southWest = [req.body.west, req.body.south];
|
const southWest = [req.body.west, req.body.south];
|
||||||
|
|
||||||
request.bounding_box = {
|
request.bounding_box = {
|
||||||
type: 'Polygon', coordinates: [
|
type: "Polygon",
|
||||||
[northWest, northEast, southEast,
|
coordinates: [[northWest, northEast, southEast, southWest, northWest]]
|
||||||
southWest, northWest]
|
};
|
||||||
]
|
await request.save();
|
||||||
};
|
|
||||||
await request.save();
|
|
||||||
|
|
||||||
const nextStepPage = req.query.nextStep || 'povrsina';
|
const nextStepPage = req.query.nextStep || "povrsina";
|
||||||
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
||||||
|
|
||||||
res.redirect(nextStepUrl);
|
res.redirect(nextStepUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getNeighborhood,
|
getNeighborhood,
|
||||||
postNeighborhood
|
postNeighborhood
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,32 +1,30 @@
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
|
|
||||||
const getPrice = (req,res) => {
|
const getPrice = (req, res) => {
|
||||||
|
const title = "Koja Vam okvirna cijena odgovara ?";
|
||||||
|
|
||||||
const title = "Koja Vam okvirna cijena odgovara ?"
|
const unit = " KM";
|
||||||
|
|
||||||
const unit = " KM"
|
|
||||||
const rangeFrom = {
|
const rangeFrom = {
|
||||||
min : 1000,
|
min: 1000,
|
||||||
max : 250000,
|
max: 250000,
|
||||||
value : 0,
|
value: 0,
|
||||||
step : 1000
|
step: 1000
|
||||||
}
|
};
|
||||||
|
|
||||||
const rangeTo = {
|
const rangeTo = {
|
||||||
min : 1000,
|
min: 1000,
|
||||||
max : 250000,
|
max: 250000,
|
||||||
value : 50000,
|
value: 50000,
|
||||||
step : 1000
|
step: 1000
|
||||||
}
|
};
|
||||||
|
|
||||||
|
res.render("price", { rangeFrom, rangeTo, unit, title });
|
||||||
res.render('price', {rangeFrom, rangeTo, unit, title });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const postPrice = async (req, res) => {
|
const postPrice = async (req, res) => {
|
||||||
const request = await currentRERequest(req);
|
const request = await currentRERequest(req);
|
||||||
|
|
||||||
const nextStepPage = req.query.nextStep || 'pregled';
|
const nextStepPage = req.query.nextStep || "pregled";
|
||||||
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
||||||
|
|
||||||
request.priceMin = req.body.from;
|
request.priceMin = req.body.from;
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
const { getRegionName, getMunicipalityName } = require('../helpers/codes');
|
const { getRegionName, getMunicipalityName } = require("../helpers/codes");
|
||||||
const { realEstateTypes, sizes, gardenSizes, prices, getEnumTypeTitle, getRealEstateTypeEnum } = require('../helpers/enums');
|
const {
|
||||||
|
realEstateTypes,
|
||||||
|
sizes,
|
||||||
|
gardenSizes,
|
||||||
|
prices,
|
||||||
|
getEnumTypeTitle,
|
||||||
|
getRealEstateTypeEnum
|
||||||
|
} = require("../helpers/enums");
|
||||||
|
|
||||||
const getQueryReview = async (req,res) => {
|
const getQueryReview = async (req, res) => {
|
||||||
|
const title = "Da li je ovo to što ste tražili ?";
|
||||||
const title = "Da li je ovo to što ste tražili ?"
|
|
||||||
const request = await currentRERequest(req);
|
const request = await currentRERequest(req);
|
||||||
const nextStep = req.query.nextStep;
|
const nextStep = req.query.nextStep;
|
||||||
|
|
||||||
@@ -12,63 +18,73 @@ const getQueryReview = async (req,res) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
realEstateType,
|
realEstateType,
|
||||||
region,
|
region,
|
||||||
municipality,
|
municipality,
|
||||||
sizeMin,
|
sizeMin,
|
||||||
sizeMax,
|
sizeMax,
|
||||||
gardenSizeMin,
|
gardenSizeMin,
|
||||||
gardenSizeMax,
|
gardenSizeMax,
|
||||||
priceMin,
|
priceMin,
|
||||||
priceMax } = request.dataValues;
|
priceMax
|
||||||
|
} = request.dataValues;
|
||||||
|
|
||||||
const realEstateTypeObject = getRealEstateTypeEnum(realEstateType);
|
const realEstateTypeObject = getRealEstateTypeEnum(realEstateType);
|
||||||
const enableGardenSizeEdit = realEstateTypeObject ? realEstateTypeObject.hasGardenSize : false;
|
const enableGardenSizeEdit = realEstateTypeObject
|
||||||
|
? realEstateTypeObject.hasGardenSize
|
||||||
|
: false;
|
||||||
|
|
||||||
const realEstateTypeTitle = realEstateType ? getEnumTypeTitle(realEstateTypes, realEstateType) : null;
|
const realEstateTypeTitle = realEstateType
|
||||||
|
? getEnumTypeTitle(realEstateTypes, realEstateType)
|
||||||
|
: null;
|
||||||
const regionName = region ? getRegionName(region) : null;
|
const regionName = region ? getRegionName(region) : null;
|
||||||
const municipalityName = (region && municipality) ? getMunicipalityName(region, municipality) : null;
|
const municipalityName =
|
||||||
|
region && municipality ? getMunicipalityName(region, municipality) : null;
|
||||||
const sizeTitle = sizeMin ? sizeMin + "-" + sizeMax + " m2" : null;
|
const sizeTitle = sizeMin ? sizeMin + "-" + sizeMax + " m2" : null;
|
||||||
const gardenSizeTitle = gardenSizeMin ? gardenSizeMin + "-" + gardenSizeMax + " m2" : null;
|
const gardenSizeTitle = gardenSizeMin
|
||||||
const priceTitle = priceMin ? priceMin + "-" + priceMax + " KM" : null;
|
? gardenSizeMin + "-" + gardenSizeMax + " m2"
|
||||||
|
: null;
|
||||||
|
const priceTitle = priceMin ? priceMin + "-" + priceMax + " KM" : null;
|
||||||
|
|
||||||
const uniqueId = request.dataValues.uniqueId ? request.dataValues.uniqueId : '';
|
const uniqueId = request.dataValues.uniqueId
|
||||||
|
? request.dataValues.uniqueId
|
||||||
|
: "";
|
||||||
|
|
||||||
const queryData = [
|
const queryData = [
|
||||||
{
|
{
|
||||||
id: 'realEstateType',
|
id: "realEstateType",
|
||||||
title: realEstateTypeTitle,
|
title: realEstateTypeTitle,
|
||||||
url: `/vrstanekretnine/${uniqueId}?nextStep=pregled`,
|
url: `/vrstanekretnine/${uniqueId}?nextStep=pregled`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'region',
|
id: "region",
|
||||||
title: regionName,
|
title: regionName,
|
||||||
url: `/grad/${uniqueId}?nextStep=mjesto`,
|
url: `/grad/${uniqueId}?nextStep=mjesto`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'municipality',
|
id: "municipality",
|
||||||
title: municipalityName,
|
title: municipalityName,
|
||||||
url: `/mjesto/${uniqueId}?nextStep=pregled`,
|
url: `/mjesto/${uniqueId}?nextStep=pregled`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'size',
|
id: "size",
|
||||||
title: sizeTitle,
|
title: sizeTitle,
|
||||||
url: `/povrsina/${uniqueId}?nextStep=pregled`,
|
url: `/povrsina/${uniqueId}?nextStep=pregled`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gardenSize',
|
id: "gardenSize",
|
||||||
title: gardenSizeTitle,
|
title: gardenSizeTitle,
|
||||||
url: enableGardenSizeEdit ? `/okucnica/${uniqueId}?nextStep=pregled` : '',
|
url: enableGardenSizeEdit ? `/okucnica/${uniqueId}?nextStep=pregled` : ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'price',
|
id: "price",
|
||||||
title: priceTitle,
|
title: priceTitle,
|
||||||
url: `/cijena/${uniqueId}?nextStep=pregled`
|
url: `/cijena/${uniqueId}?nextStep=pregled`
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
res.render('queryReview', {
|
res.render("queryReview", {
|
||||||
nextStep,
|
nextStep,
|
||||||
queryData,
|
queryData,
|
||||||
title
|
title
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
const { isValidEmail } = require('../helpers/email');
|
const { isValidEmail } = require("../helpers/email");
|
||||||
const { sendTemplatedEmail} = require('../helpers/awsEmail');
|
const { sendTemplatedEmail } = require("../helpers/awsEmail");
|
||||||
|
|
||||||
const getQuerySubmit = async (req, res) => {
|
const getQuerySubmit = async (req, res) => {
|
||||||
|
const title = "Upišite vaš e-mail";
|
||||||
const title = "Upišite vaš e-mail"
|
|
||||||
const nextStep = req.query.nextStep;
|
const nextStep = req.query.nextStep;
|
||||||
const error = req.query.error;
|
const error = req.query.error;
|
||||||
|
|
||||||
res.render('querySubmit', {
|
res.render("querySubmit", {
|
||||||
nextStep,
|
nextStep,
|
||||||
error,
|
error,
|
||||||
title
|
title
|
||||||
@@ -17,25 +16,23 @@ const getQuerySubmit = async (req, res) => {
|
|||||||
|
|
||||||
const postQuerySubmit = async (req, res) => {
|
const postQuerySubmit = async (req, res) => {
|
||||||
const request = await currentRERequest(req);
|
const request = await currentRERequest(req);
|
||||||
const nextStep = req.query.nextStep || '/ponovo';
|
const nextStep = req.query.nextStep || "/ponovo";
|
||||||
|
|
||||||
const emailInput = req.body.email;
|
const emailInput = req.body.email;
|
||||||
const emailConfirmInput = req.body.confirm;
|
const emailConfirmInput = req.body.confirm;
|
||||||
let error = "Greška ! Unesite validan email";
|
let error = "Greška ! Unesite validan email";
|
||||||
|
|
||||||
if (!isValidEmail(emailInput) || !isValidEmail(emailConfirmInput)) {
|
if (!isValidEmail(emailInput) || !isValidEmail(emailConfirmInput)) {
|
||||||
|
|
||||||
error = "Greška ! Unesite validan email";
|
error = "Greška ! Unesite validan email";
|
||||||
res.render('querySubmit', {
|
res.render("querySubmit", {
|
||||||
error
|
error
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emailInput !== emailConfirmInput) {
|
if (emailInput !== emailConfirmInput) {
|
||||||
|
|
||||||
error = "Greška ! Unešeni emailovi nisu isti";
|
error = "Greška ! Unešeni emailovi nisu isti";
|
||||||
res.render('querySubmit', {
|
res.render("querySubmit", {
|
||||||
error
|
error
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -45,7 +42,7 @@ const postQuerySubmit = async (req, res) => {
|
|||||||
request.subscribed = true;
|
request.subscribed = true;
|
||||||
await request.save();
|
await request.save();
|
||||||
sendTemplatedEmail(req.body.email, request);
|
sendTemplatedEmail(req.body.email, request);
|
||||||
res.redirect(nextStep);
|
res.redirect(nextStep);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,42 +1,39 @@
|
|||||||
const db = require('../models/index');
|
const db = require("../models/index");
|
||||||
|
|
||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
const { realEstateTypes, getRealEstateTypeEnum } = require('../helpers/enums');
|
const { realEstateTypes, getRealEstateTypeEnum } = require("../helpers/enums");
|
||||||
|
|
||||||
|
const getRealEstateTypes = (req, res) => {
|
||||||
const getRealEstateTypes = (req,res) => {
|
const title = "Koju nekretninu tražite?";
|
||||||
const title = "Koju nekretninu tražite?"
|
res.render("realEstateType", { realEstateTypes, title });
|
||||||
res.render('realEstateType', { realEstateTypes, title });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const postRealEstateTypes = async (req, res) => {
|
const postRealEstateTypes = async (req, res) => {
|
||||||
const request = await currentRERequest(req);
|
const request = await currentRERequest(req);
|
||||||
|
|
||||||
const nextStepPage = req.query.nextStep || 'grad';
|
const nextStepPage = req.query.nextStep || "grad";
|
||||||
|
|
||||||
if (request && request.uniqueId) {
|
if (request && request.uniqueId) {
|
||||||
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
||||||
request.realEstateType = req.body.realestatetype;
|
request.realEstateType = req.body.realestatetype;
|
||||||
if (!getRealEstateTypeEnum(request.realEstateType).hasGardenSize){
|
if (!getRealEstateTypeEnum(request.realEstateType).hasGardenSize) {
|
||||||
request.gardenSize = null;
|
request.gardenSize = null;
|
||||||
}
|
}
|
||||||
await request.save();
|
await request.save();
|
||||||
|
|
||||||
res.redirect(nextStepUrl)
|
res.redirect(nextStepUrl);
|
||||||
} else {
|
} else {
|
||||||
db.RealEstateRequest.create({
|
db.RealEstateRequest.create({
|
||||||
realEstateType: req.body.realestatetype
|
realEstateType: req.body.realestatetype
|
||||||
}).then( (result) => {
|
})
|
||||||
const nextStepUrl = `/${nextStepPage}/${result.uniqueId}`;
|
.then(result => {
|
||||||
res.redirect(nextStepUrl);
|
const nextStepUrl = `/${nextStepPage}/${result.uniqueId}`;
|
||||||
}).catch( (e) => {
|
res.redirect(nextStepUrl);
|
||||||
res.send(e);
|
})
|
||||||
});
|
.catch(e => {
|
||||||
|
res.send(e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
|
const { allMarketAlertsByRequest } = require("../helpers/db/dbHelper");
|
||||||
|
|
||||||
const {allMarketAlertsByRequest} = require('../helpers/db/dbHelper');
|
const getRealEstates = async (req, res) => {
|
||||||
|
const request = req.params["request_id"];
|
||||||
|
const realEstates = await allMarketAlertsByRequest(request);
|
||||||
|
|
||||||
const getRealEstates = async (req,res) => {
|
const title = "Ovo su nekretnine koje smo pronašli za vas";
|
||||||
console.log("Enter get realestates");
|
res.render("realEstates", { realEstates, title });
|
||||||
const request = req.params['request_id'];
|
};
|
||||||
console.log(req.params['request_id']);
|
|
||||||
const realEstates = await allMarketAlertsByRequest(request);
|
|
||||||
console.log(realEstates);
|
|
||||||
|
|
||||||
const title = "Ovo su nekretnine koje smo pronašli za vas"
|
module.exports = {
|
||||||
res.render('realEstates', {realEstates, title } );
|
getRealEstates
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getRealEstates
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
const { getRegions } = require('../helpers/codes');
|
const { getRegions } = require("../helpers/codes");
|
||||||
|
|
||||||
const regions = getRegions();
|
const regions = getRegions();
|
||||||
|
|
||||||
const getRegion = (req,res) => {
|
const getRegion = (req, res) => {
|
||||||
const title = "U kojoj regiji tražite nekretninu?"
|
const title = "U kojoj regiji tražite nekretninu?";
|
||||||
res.render('region', { regions, title });
|
res.render("region", { regions, title });
|
||||||
};
|
};
|
||||||
|
|
||||||
const postRegion = async (req, res) => {
|
const postRegion = async (req, res) => {
|
||||||
const request = await currentRERequest(req);
|
const request = await currentRERequest(req);
|
||||||
|
|
||||||
const nextStepQueryParam = req.query.nextStep ? '?nextStep=pregled' : '';
|
const nextStepQueryParam = req.query.nextStep ? "?nextStep=pregled" : "";
|
||||||
const nextStepPage = req.query.nextStep || 'mjesto';
|
const nextStepPage = req.query.nextStep || "mjesto";
|
||||||
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}${nextStepQueryParam}`;
|
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}${nextStepQueryParam}`;
|
||||||
|
|
||||||
request.region = req.body.region;
|
request.region = req.body.region;
|
||||||
request.municipality = null;
|
request.municipality = null;
|
||||||
await request.save();
|
await request.save();
|
||||||
|
|
||||||
res.redirect(nextStepUrl)
|
res.redirect(nextStepUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
const { currentRERequest } = require('../helpers/url');
|
const { currentRERequest } = require("../helpers/url");
|
||||||
const { sizes, getRealEstateTypeEnum } = require('../helpers/enums');
|
const { sizes, getRealEstateTypeEnum } = require("../helpers/enums");
|
||||||
|
|
||||||
const getSize = (req,res) => {
|
const getSize = (req, res) => {
|
||||||
|
const title = "Od koliko kvadrata tražite nekretninu ?";
|
||||||
const title = "Od koliko kvadrata tražite nekretninu ?"
|
const unit = " m2";
|
||||||
const unit = " m2"
|
|
||||||
const rangeFrom = {
|
const rangeFrom = {
|
||||||
min : 10,
|
min: 10,
|
||||||
max : 250,
|
max: 250,
|
||||||
value : 0,
|
value: 0,
|
||||||
step : 10
|
step: 10
|
||||||
}
|
};
|
||||||
|
|
||||||
const rangeTo = {
|
const rangeTo = {
|
||||||
min : 10,
|
min: 10,
|
||||||
max : 250,
|
max: 250,
|
||||||
value : 50,
|
value: 50,
|
||||||
step : 10
|
step: 10
|
||||||
}
|
};
|
||||||
|
|
||||||
res.render('size', { rangeFrom, rangeTo, unit, title });
|
res.render("size", { rangeFrom, rangeTo, unit, title });
|
||||||
};
|
};
|
||||||
|
|
||||||
const postSize = async (req, res) => {
|
const postSize = async (req, res) => {
|
||||||
@@ -27,7 +26,8 @@ const postSize = async (req, res) => {
|
|||||||
|
|
||||||
const realEstateType = getRealEstateTypeEnum(request.realEstateType);
|
const realEstateType = getRealEstateTypeEnum(request.realEstateType);
|
||||||
|
|
||||||
const nextStep = realEstateType && realEstateType.hasGardenSize ? 'okucnica' : 'cijena';
|
const nextStep =
|
||||||
|
realEstateType && realEstateType.hasGardenSize ? "okucnica" : "cijena";
|
||||||
const nextStepPage = req.query.nextStep || nextStep;
|
const nextStepPage = req.query.nextStep || nextStep;
|
||||||
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`;
|
||||||
request.sizeMin = req.body.from;
|
request.sizeMin = req.body.from;
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
|
const { currentRERequest } = require("../helpers/url");
|
||||||
const { currentRERequest } = require('../helpers/url');
|
|
||||||
|
|
||||||
const getUnsubscribe = async (req, res) => {
|
const getUnsubscribe = async (req, res) => {
|
||||||
|
const title = "Uspješno ste se odjavili";
|
||||||
|
const request = await currentRERequest(req);
|
||||||
|
request.subscribed = false;
|
||||||
|
await request.save();
|
||||||
|
|
||||||
const title = "Uspješno ste se odjavili"
|
res.render("unsubscribe", { nextStep: "/vrstanekretnine", title });
|
||||||
const request = await currentRERequest(req);
|
|
||||||
request.subscribed = false;
|
|
||||||
await request.save();
|
|
||||||
|
|
||||||
res.render('unsubscribe', { nextStep: '/vrstanekretnine', title });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getUnsubscribe
|
getUnsubscribe
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const getWelcome = (req,res) => {
|
const getWelcome = (req, res) => {
|
||||||
const title = "Koju nekretninu tražite?"
|
const title = "Koju nekretninu tražite?";
|
||||||
res.render('welcome', { nextStep: '/vrstanekretnine', title } );
|
res.render("welcome", { nextStep: "/vrstanekretnine", title });
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const dotenv = require("dotenv").config();
|
const { APP_URL } = require("../config/appConfig");
|
||||||
const { getRealEstateTypeEnum } = require("./enums");
|
const { getRealEstateTypeEnum } = require("./enums");
|
||||||
const { getRegionName, getMunicipalityName } = require("./codes");
|
const { getRegionName, getMunicipalityName } = require("./codes");
|
||||||
const { allRERequestByUiid } = require("./db/dbHelper");
|
const { allRERequestByUiid } = require("./db/dbHelper");
|
||||||
@@ -57,9 +57,7 @@ const getGreetingsEmailHTML = realestateRequest => {
|
|||||||
realestateRequest.realEstateType
|
realestateRequest.realEstateType
|
||||||
);
|
);
|
||||||
const gardenSize = realEstateType.hasGardenSize
|
const gardenSize = realEstateType.hasGardenSize
|
||||||
? `<div><strong>Kvadratura okućnice: Od ${
|
? `<div><strong>Kvadratura okućnice: Od ${realestateRequest.gardenSizeMin} do ${realestateRequest.gardenSizeMax} m2 </strong></div>`
|
||||||
realestateRequest.gardenSizeMin
|
|
||||||
} do ${realestateRequest.gardenSizeMax} m2 </strong></div>`
|
|
||||||
: ``;
|
: ``;
|
||||||
|
|
||||||
return `<h1> Zdravo,
|
return `<h1> Zdravo,
|
||||||
@@ -85,15 +83,15 @@ const getGreetingsEmailHTML = realestateRequest => {
|
|||||||
<div>
|
<div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div><strong> Ako želis prestati dobijati obavještenja za ovu pretragu klikni ${
|
<div><strong> Ako želis prestati dobijati obavještenja za ovu pretragu klikni ${APP_URL}/odjava/${
|
||||||
process.env.APP_URL
|
realestateRequest.uniqueId
|
||||||
}/odjava/${realestateRequest.uniqueId} </strong></div>
|
} </strong></div>
|
||||||
<div><strong>Ako želiš promijeniti uslove pretrage klikni ${
|
<div><strong>Ako želiš promijeniti uslove pretrage klikni ${APP_URL}/pregled/${
|
||||||
process.env.APP_URL
|
realestateRequest.uniqueId
|
||||||
}/pregled/${realestateRequest.uniqueId} </strong></div>
|
} </strong></div>
|
||||||
<h4> Tvoj,
|
<h4> Tvoj,
|
||||||
Javimi tim.
|
Javimi tim.
|
||||||
</h4>`;
|
</h4>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getGreetingsEmaiTextVersion = realestateRequest => {
|
const getGreetingsEmaiTextVersion = realestateRequest => {
|
||||||
@@ -101,40 +99,27 @@ const getGreetingsEmaiTextVersion = realestateRequest => {
|
|||||||
realestateRequest.realEstateType
|
realestateRequest.realEstateType
|
||||||
);
|
);
|
||||||
const gardenSize = realEstateType.hasGardenSize
|
const gardenSize = realEstateType.hasGardenSize
|
||||||
? "Kvadratura okućnice od " +
|
? `Kvadratura okućnice od ${realestateRequest.gardenSizeMin} do ${realestateRequest.gardenSizeMax}`
|
||||||
realestateRequest.gardenSizeMin +
|
|
||||||
" do " +
|
|
||||||
realestateRequest.gardenSizeMax
|
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const text =
|
const text = `Zdravo, \n Naručio/la si da ti javimo ako se nekretnina pojavi u oglasima
|
||||||
"Zdravo, \n Naručio/la si da ti javimo ako se nekretnina pojavi u oglasima \n Ovo je tražena nekretnina: \n , Tip nekretnine: " +
|
\n Ovo je tražena nekretnina: \n , Tip nekretnine: ${
|
||||||
realestateRequest.realEstateType +
|
realestateRequest.realEstateType
|
||||||
"\n Područje" +
|
} \n Područje ${getRegionName(
|
||||||
getRegionName(realestateRequest.region) +
|
realestateRequest.region
|
||||||
"\n Mjesto " +
|
)} \n Mjesto ${getMunicipalityName(
|
||||||
getMunicipalityName(
|
realestateRequest.region,
|
||||||
realestateRequest.region,
|
realestateRequest.municipality
|
||||||
realestateRequest.municipality
|
)}
|
||||||
) +
|
\n Kvadratura nekretnine Od ${realestateRequest.sizeMin} do ${
|
||||||
"\n Kvadratura nekretnine Od " +
|
realestateRequest.sizeMaX
|
||||||
realestateRequest.sizeMin +
|
} ${gardenSize} \n Cijena od ${realestateRequest.priceMin} do ${
|
||||||
" do " +
|
realestateRequest.priceMax
|
||||||
realestateRequest.sizeMaX +
|
} \n Ako želis prestati dobijati obavještenja za ovu pretragu klikni
|
||||||
+gardenSize;
|
${APP_URL}/odjava/${
|
||||||
"\n Cijena od " +
|
realestateRequest.uniqueId
|
||||||
realestateRequest.priceMin +
|
}\n Ako želiš promijeniti uslove pretrage klikni
|
||||||
" do " +
|
${APP_URL}/odpregled/${realestateRequest.uniqueId}\n Tvoj,\n Javimi tim`;
|
||||||
realestateRequest.priceMax +
|
|
||||||
"\n Ako želis prestati dobijati obavještenja za ovu pretragu klikni" +
|
|
||||||
process.env.APP_URL +
|
|
||||||
"/odjava/" +
|
|
||||||
realestateRequest.uniqueId +
|
|
||||||
"\n Ako želiš promijeniti uslove pretrage klikni " +
|
|
||||||
process.env.APP_URL +
|
|
||||||
"/odpregled/" +
|
|
||||||
realestateRequest.uniqueId +
|
|
||||||
"\n Tvoj,\n Javimi tim";
|
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
@@ -165,7 +150,7 @@ const sendBulkEmail = async marketAlerts => {
|
|||||||
realEstateType: RERequest.realEstateType,
|
realEstateType: RERequest.realEstateType,
|
||||||
region: RERequest.region,
|
region: RERequest.region,
|
||||||
municipality: RERequest.municipality,
|
municipality: RERequest.municipality,
|
||||||
requestUrl: `${process.env.APP_URL}/nekretnine/${RERequest.uniqueId}`
|
requestUrl: `${APP_URL}/nekretnine/${RERequest.uniqueId}`
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -213,8 +198,6 @@ const sendBulkEmail = async marketAlerts => {
|
|||||||
ReplacementTemplateData: repData
|
ReplacementTemplateData: repData
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log("AWS EMAIL : Bulk email replacement data:");
|
|
||||||
console.log(destinations);
|
|
||||||
|
|
||||||
var params = {
|
var params = {
|
||||||
Destinations: destinations,
|
Destinations: destinations,
|
||||||
@@ -229,15 +212,12 @@ const sendBulkEmail = async marketAlerts => {
|
|||||||
.sendBulkTemplatedEmail(params)
|
.sendBulkTemplatedEmail(params)
|
||||||
.promise();
|
.promise();
|
||||||
const awsResult = await sendPromise;
|
const awsResult = await sendPromise;
|
||||||
console.log("AWS SES bulk email response");
|
|
||||||
console.log(awsResult);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Could not send bulk email", e);
|
console.log("Could not send bulk email", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const redirectUrl = marketAlertId =>
|
const redirectUrl = marketAlertId => `${APP_URL}/redirect/${marketAlertId}`;
|
||||||
`${process.env.APP_URL}/redirect/${marketAlertId}`;
|
|
||||||
const toAWSArray = urlArray => {
|
const toAWSArray = urlArray => {
|
||||||
let arrayString = "";
|
let arrayString = "";
|
||||||
urlArray.forEach(element => {
|
urlArray.forEach(element => {
|
||||||
@@ -250,11 +230,11 @@ const toAWSArray = urlArray => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getNotificationEmailHtml = () => {
|
const getNotificationEmailHtml = () => {
|
||||||
return `<h2> Zdravo,
|
return `<h2> Zdravo,
|
||||||
Pronašli smo nekretninu koju ste tražili. </h2>
|
Pronašli smo nekretninu koju ste tražili. </h2>
|
||||||
<h3> Ovo su tražene nekretnine: </h3>
|
<h3> Ovo su tražene nekretnine: </h3>
|
||||||
<div>
|
<div>
|
||||||
<div>{{#each marketAlertUrl}}<li><a href="{{url}}">{{title}}</a></li><br />{{/each}}<div/>
|
<div>{{#each marketAlertUrl}}<li><a href="{{url}}">{{title}}</a></li><br />{{/each}}<div/>
|
||||||
<div/>
|
<div/>
|
||||||
<div>Kompletan spisak nekretnina možete pegledati ovdije: <a href="{{requestUrl}}">Nekretnine</a> <div>
|
<div>Kompletan spisak nekretnina možete pegledati ovdije: <a href="{{requestUrl}}">Nekretnine</a> <div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|||||||
1811
app/helpers/codes.js
1811
app/helpers/codes.js
File diff suppressed because it is too large
Load Diff
@@ -1,375 +1,364 @@
|
|||||||
const fetch = require('node-fetch');
|
const fetch = require("node-fetch");
|
||||||
const cheerio = require('cheerio');
|
const cheerio = require("cheerio");
|
||||||
const { allRERequest, findPointInsideBoundingBox } = require('../db/dbHelper');
|
const { allRERequest, findPointInsideBoundingBox } = require("../db/dbHelper");
|
||||||
const { getRealEstateTypeEnum } = require('../enums');
|
const { getRealEstateTypeEnum } = require("../enums");
|
||||||
const { getRegion, getMunicipality } = require('../codes')
|
const { getRegion, getMunicipality } = require("../codes");
|
||||||
const Promise = require("bluebird");
|
const Promise = require("bluebird");
|
||||||
|
|
||||||
module.exports = class OlxCrawler {
|
module.exports = class OlxCrawler {
|
||||||
//TODO figure best way to handle paging
|
//TODO figure best way to handle paging
|
||||||
constructor(hrefs = []) {
|
constructor(hrefs = []) {
|
||||||
this.hrefs = hrefs;
|
this.hrefs = hrefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
async indexPages(urls) {
|
async indexPages(urls) {
|
||||||
const indexers = [];
|
const indexers = [];
|
||||||
|
|
||||||
urls.forEach(url => {
|
urls.forEach(url => {
|
||||||
indexers.push(new Indexer(url));
|
indexers.push(new Indexer(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.map(indexers, function (indexer) {
|
return Promise.map(indexers, function(indexer) {
|
||||||
return indexer.indexWithPagination();
|
return indexer.indexWithPagination();
|
||||||
}).then(async (results) => {
|
}).then(async results => {
|
||||||
return results
|
return results;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async crawl() {
|
async crawl() {
|
||||||
console.log("OLX CRAWLER: start crawl");
|
const filteredResults = [];
|
||||||
|
const realestateRequests = await allRERequest();
|
||||||
|
const urls = this.createRequestUrls(realestateRequests);
|
||||||
|
let results = await this.indexPages(
|
||||||
|
urls,
|
||||||
|
this.fromPage,
|
||||||
|
this.toPage,
|
||||||
|
this.maxResults
|
||||||
|
);
|
||||||
|
const flatResults = results.flat();
|
||||||
|
if (flatResults) {
|
||||||
|
for (const finalResult of flatResults) {
|
||||||
|
if (null !== finalResult) {
|
||||||
|
if (
|
||||||
|
finalResult.lat !== undefined &&
|
||||||
|
finalResult.lat !== null &&
|
||||||
|
finalResult.lat !== ""
|
||||||
|
) {
|
||||||
|
const pointInsideBoundingBox = await findPointInsideBoundingBox(
|
||||||
|
[finalResult.lng, finalResult.lat],
|
||||||
|
finalResult.email,
|
||||||
|
finalResult.uuid
|
||||||
|
);
|
||||||
|
|
||||||
const filteredResults = [];
|
if (pointInsideBoundingBox[0].length !== 0) {
|
||||||
const realestateRequests = await allRERequest();
|
finalResult.hasLocation = true;
|
||||||
console.log("OLX CRAWLER: found " + realestateRequests.length + "subscribed RealEstateRequests");
|
filteredResults.push(finalResult);
|
||||||
const urls = this.createRequestUrls(realestateRequests);
|
} else {
|
||||||
let results = await this.indexPages(urls, this.fromPage, this.toPage, this.maxResults);
|
finalResult.hasLocation = false;
|
||||||
console.log("Final crawler results");
|
filteredResults.push(finalResult);
|
||||||
const flatResults = results.flat();
|
|
||||||
console.log(flatResults);
|
|
||||||
if (flatResults) {
|
|
||||||
console.log(flatResults.length);
|
|
||||||
|
|
||||||
for (const finalResult of flatResults) {
|
|
||||||
|
|
||||||
if (null !== finalResult) {
|
|
||||||
if (finalResult.lat !== undefined && finalResult.lat !== null && finalResult.lat !== "") {
|
|
||||||
const pointInsideBoundingBox = await findPointInsideBoundingBox([finalResult.lng, finalResult.lat], finalResult.email, finalResult.uuid);
|
|
||||||
|
|
||||||
|
|
||||||
if (pointInsideBoundingBox[0].length !== 0) {
|
|
||||||
finalResult.hasLocation = true
|
|
||||||
filteredResults.push(finalResult);
|
|
||||||
} else {
|
|
||||||
finalResult.hasLocation = false
|
|
||||||
filteredResults.push(finalResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
console.log("OLX CRAWLER: number of olx crawler results, after geo location filtering: " + filteredResults.length);
|
|
||||||
return filteredResults;
|
|
||||||
}
|
}
|
||||||
return []
|
}
|
||||||
|
return filteredResults;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
createRequestUrls(realestateRequests) {
|
||||||
|
const urls = [];
|
||||||
|
|
||||||
|
for (const request of realestateRequests) {
|
||||||
|
const realsestateType =
|
||||||
|
"kategorija=" +
|
||||||
|
getRealEstateTypeEnum(request.realEstateType).olxCategory;
|
||||||
|
const region = "kanton=" + getRegion(request.region).olxid;
|
||||||
|
const municipality =
|
||||||
|
"grad%5B%5D=" +
|
||||||
|
getMunicipality(request.region, request.municipality).olxid;
|
||||||
|
const sizeMin = "kvadrata_min=" + request.sizeMin;
|
||||||
|
const sizeMax = "kvadrata_max=" + request.sizeMax;
|
||||||
|
const priceMin = "od=" + request.priceMin;
|
||||||
|
const priceMax = "do=" + request.priceMax;
|
||||||
|
|
||||||
|
const olxUrl = {
|
||||||
|
url: `https://www.olx.ba/pretraga?${realsestateType}&id=2&stanje=0&vrstapregleda=tabela&sort_order=desc&${region}&${municipality}&${priceMin}&${priceMax}&vrsta=samoprodaja&${sizeMin}&${sizeMax}&stranica=`,
|
||||||
|
email: request.email,
|
||||||
|
uuid: request.uniqueId,
|
||||||
|
hrefs: this.hrefs
|
||||||
|
};
|
||||||
|
urls.push(olxUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
createRequestUrls(realestateRequests) {
|
return urls;
|
||||||
const urls = []
|
}
|
||||||
|
|
||||||
for (const request of realestateRequests) {
|
|
||||||
const realsestateType = "kategorija=" + getRealEstateTypeEnum(request.realEstateType).olxCategory;
|
|
||||||
const region = "kanton=" + getRegion(request.region).olxid;
|
|
||||||
const municipality = "grad%5B%5D=" + getMunicipality(request.region, request.municipality).olxid;
|
|
||||||
const sizeMin = "kvadrata_min=" + request.sizeMin;
|
|
||||||
const sizeMax = "kvadrata_max=" + request.sizeMax;
|
|
||||||
const priceMin = "od=" + request.priceMin;
|
|
||||||
const priceMax = "do=" + request.priceMax;
|
|
||||||
|
|
||||||
const olxUrl = {
|
|
||||||
url: `https://www.olx.ba/pretraga?${realsestateType}&id=2&stanje=0&vrstapregleda=tabela&sort_order=desc&${region}&${municipality}&${priceMin}&${priceMax}&vrsta=samoprodaja&${sizeMin}&${sizeMax}&stranica=`,
|
|
||||||
email: request.email,
|
|
||||||
uuid: request.uniqueId,
|
|
||||||
hrefs: this.hrefs
|
|
||||||
}
|
|
||||||
console.log(olxUrl.url);
|
|
||||||
urls.push(olxUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return urls;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Indexer {
|
class Indexer {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {String|Array} olxUrl single or array of objects containing url email and uuid
|
||||||
|
* @param {Array} hrefResutls array contaning urls from crawler results
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
constructor(olxUrl, hrefResutls) {
|
||||||
*
|
this.olxUrl = olxUrl;
|
||||||
* @param {String|Array} olxUrl single or array of objects containing url email and uuid
|
this.hrefResutls = hrefResutls;
|
||||||
* @param {Array} hrefResutls array contaning urls from crawler results
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
constructor(olxUrl, hrefResutls) {
|
async indexWithPagination(pageNumber = 1) {
|
||||||
this.olxUrl = olxUrl;
|
const pageNr = this.olxUrl.url.match(/\d+$/);
|
||||||
this.hrefResutls = hrefResutls;
|
const indexers = this.prepareIndexers(pageNumber ? [pageNumber] : pageNr);
|
||||||
}
|
|
||||||
|
|
||||||
async indexWithPagination(pageNumber = 1) {
|
try {
|
||||||
|
return Promise.map(indexers.indexers, function(indexer) {
|
||||||
|
return indexer.indexPage(pageNumber);
|
||||||
|
}).then(async results => {
|
||||||
|
let hasResults = false;
|
||||||
|
|
||||||
console.log("This is olxUrl:" + this.olxUrl.url);
|
results.forEach(result => {
|
||||||
const pageNr = this.olxUrl.url.match(/\d+$/);
|
if (!hasResults) {
|
||||||
const indexers = this.prepareIndexers(pageNumber ? [pageNumber] : pageNr);
|
hasResults = result.hasResults;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
if (!hasResults) {
|
||||||
|
const singlePageIndexers = this.prepareHrefIndexers(results);
|
||||||
|
if (singlePageIndexers.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.map(indexers.indexers, function (indexer) {
|
return Promise.map(singlePageIndexers, function(indexer) {
|
||||||
return indexer.indexPage(pageNumber);
|
return indexer.indexSingle();
|
||||||
}).then(async (results) => {
|
}).then(async results => {
|
||||||
let hasResults = false;
|
return results;
|
||||||
|
});
|
||||||
results.forEach(result => {
|
|
||||||
if (!hasResults) {
|
|
||||||
console.log("No results detected")
|
|
||||||
hasResults = result.hasResults
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!hasResults) {
|
|
||||||
console.log("HAS NO MORE RESULTS, stop the paging, there are some results and they should contain only HREFS");
|
|
||||||
console.log(results.length);
|
|
||||||
const singlePageIndexers = this.prepareHrefIndexers(results);
|
|
||||||
if (singlePageIndexers.length === 0) {
|
|
||||||
console.log("THERE IS NOT EVEN SINGLE RESULT");
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.map(singlePageIndexers, function (indexer) {
|
|
||||||
return indexer.indexSingle();
|
|
||||||
}).then(async (results) => {
|
|
||||||
console.log("SinglePageMethod in HAS NO RESULTS, MarketAralms");
|
|
||||||
console.log(results.length);
|
|
||||||
return results;
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("HAS MORE RESULTS, should only contain HREFS");
|
|
||||||
console.log(results.length);
|
|
||||||
const newResults = await this.indexWithPagination(results[0].pageNumber + 5);
|
|
||||||
const singlePageIndexers = this.prepareHrefIndexers(results);
|
|
||||||
|
|
||||||
const newerResults = await Promise.map(singlePageIndexers, function (indexer) {
|
|
||||||
return indexer.indexSingle();
|
|
||||||
}).then(async (results) => {
|
|
||||||
console.log("SinglePageMethod HAS RESULTS, should contain MarketAlerts only");
|
|
||||||
console.log(results.length);
|
|
||||||
return results;
|
|
||||||
});
|
|
||||||
|
|
||||||
Array.prototype.push.apply(newResults, newerResults);
|
|
||||||
return newResults;
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Error has accured", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareIndexers(pageNr) {
|
|
||||||
|
|
||||||
console.log("Entering prepareIndexers : page nr - " + pageNr);
|
|
||||||
const indexers = [];
|
|
||||||
let lastPageNumber;
|
|
||||||
if (pageNr) {
|
|
||||||
for (let index = Number(pageNr[0]); index <= Number(pageNr[0]) + 5; index++) {
|
|
||||||
lastPageNumber = index;
|
|
||||||
const newOlxUrl = {
|
|
||||||
url: this.olxUrl.url.replace(/\d+$/, "") + index,
|
|
||||||
email: this.olxUrl.email,
|
|
||||||
uuid: this.olxUrl.uuid,
|
|
||||||
hrefs: this.olxUrl.hrefs
|
|
||||||
}
|
|
||||||
indexers.push(new Indexer(newOlxUrl));
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (let index = 1; index <= 5; index++) {
|
const newResults = await this.indexWithPagination(
|
||||||
lastPageNumber = index;
|
results[0].pageNumber + 5
|
||||||
const newOlxUrl = {
|
);
|
||||||
url: this.olxUrl.url + index,
|
const singlePageIndexers = this.prepareHrefIndexers(results);
|
||||||
email: this.olxUrl.email,
|
|
||||||
uuid: this.olxUrl.uuid,
|
const newerResults = await Promise.map(singlePageIndexers, function(
|
||||||
hrefs: this.olxUrl.hrefs
|
indexer
|
||||||
}
|
) {
|
||||||
indexers.push(new Indexer(newOlxUrl));
|
return indexer.indexSingle();
|
||||||
}
|
}).then(async results => {
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
Array.prototype.push.apply(newResults, newerResults);
|
||||||
|
return newResults;
|
||||||
}
|
}
|
||||||
return {
|
});
|
||||||
indexers: indexers,
|
} catch (e) {
|
||||||
lastPageNumber: lastPageNumber
|
console.error("Error has accured", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareIndexers(pageNr) {
|
||||||
|
const indexers = [];
|
||||||
|
let lastPageNumber;
|
||||||
|
if (pageNr) {
|
||||||
|
for (
|
||||||
|
let index = Number(pageNr[0]);
|
||||||
|
index <= Number(pageNr[0]) + 5;
|
||||||
|
index++
|
||||||
|
) {
|
||||||
|
lastPageNumber = index;
|
||||||
|
const newOlxUrl = {
|
||||||
|
url: this.olxUrl.url.replace(/\d+$/, "") + index,
|
||||||
|
email: this.olxUrl.email,
|
||||||
|
uuid: this.olxUrl.uuid,
|
||||||
|
hrefs: this.olxUrl.hrefs
|
||||||
};
|
};
|
||||||
|
indexers.push(new Indexer(newOlxUrl));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let index = 1; index <= 5; index++) {
|
||||||
|
lastPageNumber = index;
|
||||||
|
const newOlxUrl = {
|
||||||
|
url: this.olxUrl.url + index,
|
||||||
|
email: this.olxUrl.email,
|
||||||
|
uuid: this.olxUrl.uuid,
|
||||||
|
hrefs: this.olxUrl.hrefs
|
||||||
|
};
|
||||||
|
indexers.push(new Indexer(newOlxUrl));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
indexers: indexers,
|
||||||
|
lastPageNumber: lastPageNumber
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
prepareHrefIndexers(results) {
|
prepareHrefIndexers(results) {
|
||||||
const indexers = []
|
const indexers = [];
|
||||||
|
|
||||||
if (!Array.isArray(results)) {
|
if (!Array.isArray(results)) {
|
||||||
results.hrefs.forEach(href => {
|
results.hrefs.forEach(href => {
|
||||||
const newOlxUrl = {
|
const newOlxUrl = {
|
||||||
url: href,
|
url: href,
|
||||||
email: results.olxUrl.email,
|
email: results.olxUrl.email,
|
||||||
uuid: results.olxUrl.uuid,
|
uuid: results.olxUrl.uuid,
|
||||||
hrefs: this.olxUrl.hrefs
|
hrefs: this.olxUrl.hrefs
|
||||||
}
|
};
|
||||||
|
|
||||||
indexers.push(new Indexer(newOlxUrl));
|
indexers.push(new Indexer(newOlxUrl));
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
} else {
|
results.forEach(result => {
|
||||||
|
if (result !== null && result.hasOwnProperty("hrefs")) {
|
||||||
|
result.hrefs.forEach(href => {
|
||||||
results.forEach(result => {
|
const newOlxUrl = {
|
||||||
|
url: href,
|
||||||
if (result !== null && result.hasOwnProperty('hrefs')) {
|
email: result.olxUrl.email,
|
||||||
result.hrefs.forEach(href => {
|
uuid: result.olxUrl.uuid,
|
||||||
const newOlxUrl = {
|
hrefs: this.olxUrl.hrefs
|
||||||
url: href,
|
|
||||||
email: result.olxUrl.email,
|
|
||||||
uuid: result.olxUrl.uuid,
|
|
||||||
hrefs: this.olxUrl.hrefs
|
|
||||||
}
|
|
||||||
|
|
||||||
indexers.push(new Indexer(newOlxUrl));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return indexers;
|
|
||||||
}
|
|
||||||
|
|
||||||
async indexPage(pageNumber) {
|
|
||||||
console.log("Page number in index page, max page number :")
|
|
||||||
console.log(pageNumber);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
console.log("Indexing page: " + this.olxUrl.url);
|
|
||||||
const res = await fetch(this.olxUrl.url);
|
|
||||||
const body = await res.text();
|
|
||||||
const $ = cheerio.load(body);
|
|
||||||
const hrefs = [];
|
|
||||||
let hasResults = false
|
|
||||||
|
|
||||||
$('#rezultatipretrage').find('.listitem').each((i, elem) => {
|
|
||||||
hasResults = true
|
|
||||||
const href = $(elem).find('a').first().attr('href');
|
|
||||||
hrefs.push(href);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("this is hrefs for olxUrl" + this.olxUrl.url);
|
|
||||||
console.log("NUMBER OF HREFS " + hrefs.length);
|
|
||||||
|
|
||||||
return {
|
|
||||||
hrefs: hrefs,
|
|
||||||
hasResults: hasResults,
|
|
||||||
pageNumber: pageNumber,
|
|
||||||
olxUrl: this.olxUrl
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Exception caught:' + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async indexSingle() {
|
|
||||||
try {
|
|
||||||
console.log("Index single");
|
|
||||||
console.log(this.olxUrl.url);
|
|
||||||
|
|
||||||
if (this.olxUrl.url === undefined) {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (global.hrefs) {
|
|
||||||
|
|
||||||
if (this.olxUrl.hrefs[this.olxUrl.uuid] && this.olxUrl.hrefs[this.olxUrl.uuid].includes(this.olxUrl.url)) {
|
|
||||||
|
|
||||||
console.log("We found duplicate URL");
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
|
|
||||||
const res = await fetch(this.olxUrl.url);
|
|
||||||
const body = await res.text();
|
|
||||||
const $ = cheerio.load(body);
|
|
||||||
|
|
||||||
const title = $('#naslovartikla').text().trim();
|
|
||||||
const realEstateType = $('#artikal_glavni_div > div.artikal_lijevo > div:nth-child(3) > div > span:nth-child(3) > a > span').text();
|
|
||||||
|
|
||||||
const price = $('#pc > p:nth-child(2)').text();
|
|
||||||
const size = $('#dodatnapolja1 > div:nth-child(1) > div.df2').text();
|
|
||||||
const rooms = $('#dodatnapolja1 > div:nth-child(2) > div.df2').text();
|
|
||||||
const address = $('#dodatnapolja1 > div:nth-child(5) > div.df2').text();
|
|
||||||
const gardenSize = $('#dodatnapolja1 > div:nth-child(6) > div.df2').text();
|
|
||||||
const location = $('#artikal_glavni_div > div.artikal_lijevo > div.op.pop.mobile-lokacija').attr('data-content');
|
|
||||||
|
|
||||||
const time = $('time').attr('datetime');
|
|
||||||
const olxId = $('#artikal_glavni_div > div.artikal_lijevo > div:nth-child(15) > div:nth-child(4) > div.df2').text();
|
|
||||||
|
|
||||||
const descriptions = $('.artikal_detaljniopis_tekst');
|
|
||||||
const latLngRe = /LatLng\(([0-9]+\.[0-9]+)\,\s+([0-9]+\.[0-9]+)\)/g;
|
|
||||||
const imgRe = /href":("[^"]*")/g;
|
|
||||||
const matches = latLngRe.exec(body);
|
|
||||||
let lng = '',
|
|
||||||
lat = '';
|
|
||||||
const parsePrice = (price) => parseFloat(price.replace(".", ""))
|
|
||||||
|
|
||||||
if (matches && matches.length >= 3) {
|
|
||||||
lat = matches[1];
|
|
||||||
lng = matches[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsedPrice = parsePrice(price);
|
|
||||||
|
|
||||||
const locationArray = location.split(",");
|
|
||||||
const region = locationArray[0];
|
|
||||||
const municipality = locationArray[1];
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
realEstateType: this.getCategoryId(realEstateType),
|
|
||||||
email: this.olxUrl.email,
|
|
||||||
uuid: this.olxUrl.uuid,
|
|
||||||
olxId: olxId,
|
|
||||||
url: this.olxUrl.url,
|
|
||||||
title,
|
|
||||||
price: isNaN(parsedPrice) ? 0 : parsedPrice,
|
|
||||||
size: parseFloat(size),
|
|
||||||
gardenSize: isNaN(parseFloat(gardenSize)) ? 0 : parseFloat(gardenSize),
|
|
||||||
address,
|
|
||||||
region,
|
|
||||||
municipality,
|
|
||||||
time,
|
|
||||||
shortDescription: descriptions.first().text(),
|
|
||||||
longDescription: descriptions.last().text(),
|
|
||||||
lat,
|
|
||||||
lng,
|
|
||||||
loc: [parseFloat(lat), parseFloat(lng)],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return data;
|
indexers.push(new Indexer(newOlxUrl));
|
||||||
} catch (e) {
|
});
|
||||||
console.error('Exception caught: ' + e.message);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return indexers;
|
||||||
|
}
|
||||||
|
|
||||||
|
async indexPage(pageNumber) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(this.olxUrl.url);
|
||||||
|
const body = await res.text();
|
||||||
|
const $ = cheerio.load(body);
|
||||||
|
const hrefs = [];
|
||||||
|
let hasResults = false;
|
||||||
|
|
||||||
|
$("#rezultatipretrage")
|
||||||
|
.find(".listitem")
|
||||||
|
.each((i, elem) => {
|
||||||
|
hasResults = true;
|
||||||
|
const href = $(elem)
|
||||||
|
.find("a")
|
||||||
|
.first()
|
||||||
|
.attr("href");
|
||||||
|
hrefs.push(href);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
hrefs: hrefs,
|
||||||
|
hasResults: hasResults,
|
||||||
|
pageNumber: pageNumber,
|
||||||
|
olxUrl: this.olxUrl
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Exception caught:" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async indexSingle() {
|
||||||
|
try {
|
||||||
|
if (this.olxUrl.url === undefined) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (global.hrefs) {
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.olxUrl.hrefs[this.olxUrl.uuid] &&
|
||||||
|
this.olxUrl.hrefs[this.olxUrl.uuid].includes(this.olxUrl.url)
|
||||||
|
) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
|
||||||
|
const res = await fetch(this.olxUrl.url);
|
||||||
|
const body = await res.text();
|
||||||
|
const $ = cheerio.load(body);
|
||||||
|
|
||||||
|
const title = $("#naslovartikla")
|
||||||
|
.text()
|
||||||
|
.trim();
|
||||||
|
const realEstateType = $(
|
||||||
|
"#artikal_glavni_div > div.artikal_lijevo > div:nth-child(3) > div > span:nth-child(3) > a > span"
|
||||||
|
).text();
|
||||||
|
|
||||||
|
const price = $("#pc > p:nth-child(2)").text();
|
||||||
|
const size = $("#dodatnapolja1 > div:nth-child(1) > div.df2").text();
|
||||||
|
const rooms = $("#dodatnapolja1 > div:nth-child(2) > div.df2").text();
|
||||||
|
const address = $("#dodatnapolja1 > div:nth-child(5) > div.df2").text();
|
||||||
|
const gardenSize = $(
|
||||||
|
"#dodatnapolja1 > div:nth-child(6) > div.df2"
|
||||||
|
).text();
|
||||||
|
const location = $(
|
||||||
|
"#artikal_glavni_div > div.artikal_lijevo > div.op.pop.mobile-lokacija"
|
||||||
|
).attr("data-content");
|
||||||
|
|
||||||
|
const time = $("time").attr("datetime");
|
||||||
|
const olxId = $(
|
||||||
|
"#artikal_glavni_div > div.artikal_lijevo > div:nth-child(15) > div:nth-child(4) > div.df2"
|
||||||
|
).text();
|
||||||
|
|
||||||
|
const descriptions = $(".artikal_detaljniopis_tekst");
|
||||||
|
const latLngRe = /LatLng\(([0-9]+\.[0-9]+)\,\s+([0-9]+\.[0-9]+)\)/g;
|
||||||
|
const imgRe = /href":("[^"]*")/g;
|
||||||
|
const matches = latLngRe.exec(body);
|
||||||
|
let lng = "",
|
||||||
|
lat = "";
|
||||||
|
const parsePrice = price => parseFloat(price.replace(".", ""));
|
||||||
|
|
||||||
|
if (matches && matches.length >= 3) {
|
||||||
|
lat = matches[1];
|
||||||
|
lng = matches[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedPrice = parsePrice(price);
|
||||||
|
|
||||||
|
const locationArray = location.split(",");
|
||||||
|
const region = locationArray[0];
|
||||||
|
const municipality = locationArray[1];
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
realEstateType: this.getCategoryId(realEstateType),
|
||||||
|
email: this.olxUrl.email,
|
||||||
|
uuid: this.olxUrl.uuid,
|
||||||
|
olxId: olxId,
|
||||||
|
url: this.olxUrl.url,
|
||||||
|
title,
|
||||||
|
price: isNaN(parsedPrice) ? 0 : parsedPrice,
|
||||||
|
size: parseFloat(size),
|
||||||
|
gardenSize: isNaN(parseFloat(gardenSize)) ? 0 : parseFloat(gardenSize),
|
||||||
|
address,
|
||||||
|
region,
|
||||||
|
municipality,
|
||||||
|
time,
|
||||||
|
shortDescription: descriptions.first().text(),
|
||||||
|
longDescription: descriptions.last().text(),
|
||||||
|
lat,
|
||||||
|
lng,
|
||||||
|
loc: [parseFloat(lat), parseFloat(lng)]
|
||||||
|
};
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Exception caught: " + e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCategoryId(category) {
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
switch (category) {
|
getCategoryId(category) {
|
||||||
case 'Stanovi':
|
switch (category) {
|
||||||
return 'stan';
|
case "Stanovi":
|
||||||
|
return "stan";
|
||||||
|
|
||||||
case 'Vikendice':
|
case "Vikendice":
|
||||||
return 'vikendica'
|
return "vikendica";
|
||||||
|
|
||||||
case 'Kuće':
|
case "Kuće":
|
||||||
return 'kuca';
|
return "kuca";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return '';
|
return "";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
const isValidEmail = email => {
|
||||||
const isValidEmail = (email) => {
|
|
||||||
const simpleEmailRegex = /^.+@.+\..+$/;
|
const simpleEmailRegex = /^.+@.+\..+$/;
|
||||||
return (email && email.length < 250 && simpleEmailRegex.test(email));
|
return email && email.length < 250 && simpleEmailRegex.test(email);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
const realEstateTypes = [
|
const realEstateTypes = [
|
||||||
{ title: "Kuća", id: "kuca", hasGardenSize: true, olxCategory: 24 },
|
{ title: "Kuća", id: "kuca", hasGardenSize: true, olxCategory: 24 },
|
||||||
{ title: "Stan", id: "stan", hasGardenSize: false, olxCategory: 23},
|
{ title: "Stan", id: "stan", hasGardenSize: false, olxCategory: 23 },
|
||||||
{ title: "Vikendica", id: "vikendica", hasGardenSize: true, olxCategory: 26 }
|
{ title: "Vikendica", id: "vikendica", hasGardenSize: true, olxCategory: 26 }
|
||||||
];
|
];
|
||||||
|
|
||||||
const sizes = [
|
const sizes = [
|
||||||
{ title: "do 50 m2", id: "50m2" },
|
{ title: "do 50 m2", id: "50m2" },
|
||||||
{ title: "do 75 m2", id: "75m2" },
|
{ title: "do 75 m2", id: "75m2" },
|
||||||
{ title: "do 100 m2", id: "100m2" },
|
{ title: "do 100 m2", id: "100m2" },
|
||||||
{ title: "do 150 m2", id: "150m2" },
|
{ title: "do 150 m2", id: "150m2" },
|
||||||
{ title: "do 200 m2", id: "200m2" },
|
{ title: "do 200 m2", id: "200m2" },
|
||||||
{ title: "preko 200 m2", id: "moreThan200m2" }
|
{ title: "preko 200 m2", id: "moreThan200m2" }
|
||||||
];
|
];
|
||||||
|
|
||||||
const gardenSizes = [
|
const gardenSizes = [
|
||||||
{ title: "do 100 m2", id: "100m2" },
|
{ title: "do 100 m2", id: "100m2" },
|
||||||
{ title: "do 500 m2", id: "500m2" },
|
{ title: "do 500 m2", id: "500m2" },
|
||||||
{ title: "do 1 dunum", id: "1000m2" },
|
{ title: "do 1 dunum", id: "1000m2" },
|
||||||
{ title: "do 2 dunuma", id: "2000m2" },
|
{ title: "do 2 dunuma", id: "2000m2" },
|
||||||
{ title: "do 3 dunuma", id: "3000m2" },
|
{ title: "do 3 dunuma", id: "3000m2" },
|
||||||
{ title: "preko 3 dunuma", id: "moreThan3000m2" }
|
{ title: "preko 3 dunuma", id: "moreThan3000m2" }
|
||||||
];
|
];
|
||||||
|
|
||||||
const prices = [
|
const prices = [
|
||||||
{ title: "do 50 000 KM", id: "50kKM" },
|
{ title: "do 50 000 KM", id: "50kKM" },
|
||||||
{ title: "do 100 000 KM", id: "100kKM" },
|
{ title: "do 100 000 KM", id: "100kKM" },
|
||||||
{ title: "do 150 000 KM", id: "150kKM" },
|
{ title: "do 150 000 KM", id: "150kKM" },
|
||||||
{ title: "do 200 000 KM", id: "200kKM" },
|
{ title: "do 200 000 KM", id: "200kKM" },
|
||||||
{ title: "do 250 000 KM", id: "250kKM" },
|
{ title: "do 250 000 KM", id: "250kKM" },
|
||||||
{ title: "preko 250 000 KM", id: "moreThan250kKM" }
|
{ title: "preko 250 000 KM", id: "moreThan250kKM" }
|
||||||
];
|
];
|
||||||
|
|
||||||
const getEnumObject = (enumType, enumId) => {
|
const getEnumObject = (enumType, enumId) => {
|
||||||
return enumType.find(enumValue => enumValue.id === enumId);
|
return enumType.find(enumValue => enumValue.id === enumId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRealEstateTypeEnum = (enumId) => {
|
const getRealEstateTypeEnum = enumId => {
|
||||||
return getEnumObject(realEstateTypes, enumId) || null;
|
return getEnumObject(realEstateTypes, enumId) || null;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getEnumTypeTitle = (enumType, enumId) => {
|
const getEnumTypeTitle = (enumType, enumId) => {
|
||||||
const enumObject = getEnumObject(enumType, enumId);
|
const enumObject = getEnumObject(enumType, enumId);
|
||||||
if (!enumObject){
|
if (!enumObject) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return enumObject.title;
|
return enumObject.title;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
realEstateTypes,
|
realEstateTypes,
|
||||||
sizes,
|
sizes,
|
||||||
gardenSizes,
|
gardenSizes,
|
||||||
prices,
|
prices,
|
||||||
getRealEstateTypeEnum,
|
getRealEstateTypeEnum,
|
||||||
getEnumTypeTitle,
|
getEnumTypeTitle
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
const db = require('../models/index');
|
const db = require("../models/index");
|
||||||
|
|
||||||
const currentRERequest = async (req) => {
|
const currentRERequest = async req => {
|
||||||
const uniqueId = req.params['request_id'];
|
const uniqueId = req.params["request_id"];
|
||||||
if(!uniqueId) return null;
|
if (!uniqueId) return null;
|
||||||
|
|
||||||
const request = await db.RealEstateRequest.findOne({ where: {uniqueId} });
|
const request = await db.RealEstateRequest.findOne({ where: { uniqueId } });
|
||||||
return request;
|
return request;
|
||||||
};
|
};
|
||||||
module.exports = {
|
module.exports = {
|
||||||
currentRERequest,
|
currentRERequest
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
const scrapTheItems = require("./scrapTheItems");
|
const scrapTheItems = require("./scrapTheItems");
|
||||||
const convertToDate = require("./convertToDate");
|
const convertToDate = require("./convertToDate");
|
||||||
const AWS = require('aws-sdk');
|
const AWS = require("aws-sdk");
|
||||||
// AWS.config.update({region: 'eu-central-1'});
|
// AWS.config.update({region: 'eu-central-1'});
|
||||||
|
|
||||||
|
|
||||||
async function sendNotification(marketAlert) {
|
async function sendNotification(marketAlert) {
|
||||||
const { id, email, olx_url } = marketAlert;
|
const { id, email, olx_url } = marketAlert;
|
||||||
let url =
|
let url =
|
||||||
@@ -19,37 +18,37 @@ async function sendNotification(marketAlert) {
|
|||||||
|
|
||||||
// Create sendEmail params
|
// Create sendEmail params
|
||||||
const params = {
|
const params = {
|
||||||
Destination: { /* required */
|
Destination: {
|
||||||
CcAddresses: [
|
/* required */
|
||||||
],
|
CcAddresses: [],
|
||||||
ToAddresses: [
|
ToAddresses: [email]
|
||||||
email
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
Message: { /* required */
|
Message: {
|
||||||
Body: { /* required */
|
/* required */
|
||||||
|
Body: {
|
||||||
|
/* required */
|
||||||
Html: {
|
Html: {
|
||||||
Charset: "UTF-8",
|
Charset: "UTF-8",
|
||||||
Data: message
|
Data: message
|
||||||
},
|
},
|
||||||
Text: {
|
Text: {
|
||||||
Charset: "UTF-8",
|
Charset: "UTF-8",
|
||||||
Data: message // TODO: convert to text
|
Data: message // TODO: convert to text
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Subject: {
|
Subject: {
|
||||||
Charset: 'UTF-8',
|
Charset: "UTF-8",
|
||||||
Data: 'Javimi alert'
|
Data: "Javimi alert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Source: 'info@saburly.com', /* required */
|
Source: "info@saburly.com" /* required */,
|
||||||
ReplyToAddresses: [
|
ReplyToAddresses: ["info@saburly.com"]
|
||||||
'info@saburly.com',
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
const sendPromise = new AWS.SES({apiVersion: '2010-12-01'}).sendEmail(params).promise();
|
const sendPromise = new AWS.SES({ apiVersion: "2010-12-01" })
|
||||||
|
.sendEmail(params)
|
||||||
|
.promise();
|
||||||
await sendPromise;
|
await sendPromise;
|
||||||
return { id, date: String(convertToDate(lastDate)) };
|
return { id, date: String(convertToDate(lastDate)) };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.createTable('MarketAlerts', {
|
return queryInterface.createTable("MarketAlerts", {
|
||||||
id: {
|
id: {
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
autoIncrement: true,
|
autoIncrement: true,
|
||||||
@@ -29,6 +29,6 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.dropTable('MarketAlerts');
|
return queryInterface.dropTable("MarketAlerts");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.createTable('RealEstateRequests', {
|
return queryInterface.createTable("RealEstateRequests", {
|
||||||
id: {
|
id: {
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
autoIncrement: true,
|
autoIncrement: true,
|
||||||
@@ -28,6 +28,6 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.dropTable('RealEstateRequests');
|
return queryInterface.dropTable("RealEstateRequests");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn(
|
||||||
'RealEstateRequests',
|
"RealEstateRequests",
|
||||||
'city',
|
"city",
|
||||||
Sequelize.STRING
|
Sequelize.STRING
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("RealEstateRequests", "city");
|
||||||
'RealEstateRequests',
|
|
||||||
'city'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn(
|
||||||
'RealEstateRequests',
|
"RealEstateRequests",
|
||||||
'place',
|
"place",
|
||||||
Sequelize.STRING
|
Sequelize.STRING
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("RealEstateRequests", "place");
|
||||||
'RealEstateRequests',
|
|
||||||
'place'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.renameColumn(
|
return queryInterface.renameColumn(
|
||||||
'RealEstateRequests',
|
"RealEstateRequests",
|
||||||
'place',
|
"place",
|
||||||
'municipality'
|
"municipality"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.renameColumn(
|
return queryInterface.renameColumn(
|
||||||
'RealEstateRequests',
|
"RealEstateRequests",
|
||||||
'municipality',
|
"municipality",
|
||||||
'place'
|
"place"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.renameColumn(
|
return queryInterface.renameColumn("RealEstateRequests", "city", "region");
|
||||||
'RealEstateRequests',
|
|
||||||
'city',
|
|
||||||
'region'
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.renameColumn(
|
return queryInterface.renameColumn("RealEstateRequests", "region", "city");
|
||||||
'RealEstateRequests',
|
|
||||||
'region',
|
|
||||||
'city'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn("RealEstateRequests", "size", {
|
||||||
'RealEstateRequests',
|
type: Sequelize.STRING
|
||||||
'size',
|
});
|
||||||
{
|
|
||||||
type: Sequelize.STRING
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("RealEstateRequests", "size");
|
||||||
'RealEstateRequests',
|
|
||||||
'size'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn("RealEstateRequests", "gardenSize", {
|
||||||
'RealEstateRequests',
|
type: Sequelize.STRING
|
||||||
'gardenSize',
|
});
|
||||||
{
|
|
||||||
type: Sequelize.STRING
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("RealEstateRequests", "gardenSize");
|
||||||
'RealEstateRequests',
|
|
||||||
'gardenSize'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn("RealEstateRequests", "price", {
|
||||||
'RealEstateRequests',
|
type: Sequelize.STRING
|
||||||
'price',
|
});
|
||||||
{
|
|
||||||
type: Sequelize.STRING
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("RealEstateRequests", "price");
|
||||||
'RealEstateRequests',
|
|
||||||
'price'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.query("CREATE EXTENSION postgis").then(([results, metadata]) => {
|
return queryInterface.sequelize
|
||||||
/// No result
|
.query("CREATE EXTENSION postgis")
|
||||||
})
|
.then(([results, metadata]) => {
|
||||||
|
/// No result
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.query("DROP EXTENSION IF EXISTS postgis").then(([results, metadata]) => {
|
return queryInterface.sequelize
|
||||||
|
.query("DROP EXTENSION IF EXISTS postgis")
|
||||||
|
.then(([results, metadata]) => {
|
||||||
/// No result
|
/// No result
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
|
return queryInterface.sequelize
|
||||||
return queryInterface.sequelize.query("ALTER TABLE \"RealEstateRequests\" ADD COLUMN bounding_box geometry(Polygon);").then(([results, metadata]) => {
|
.query(
|
||||||
/// No result
|
'ALTER TABLE "RealEstateRequests" ADD COLUMN bounding_box geometry(Polygon);'
|
||||||
})
|
)
|
||||||
|
.then(([results, metadata]) => {
|
||||||
|
/// No result
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.query("ALTER TABLE \"RealEstateRequests\" DROP COLUMN bounding_box").then(([results, metadata]) => {
|
return queryInterface.sequelize
|
||||||
/// No result
|
.query('ALTER TABLE "RealEstateRequests" DROP COLUMN bounding_box')
|
||||||
})
|
.then(([results, metadata]) => {
|
||||||
|
/// No result
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,27 +1,48 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.transaction((t) => {
|
return queryInterface.sequelize.transaction(t => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
queryInterface.addColumn('RealEstateRequests', 'sizeRange', {
|
queryInterface.addColumn(
|
||||||
type: Sequelize.STRING
|
"RealEstateRequests",
|
||||||
}, { transaction: t }),
|
"sizeRange",
|
||||||
queryInterface.addColumn('RealEstateRequests', 'gardenSizeRange', {
|
{
|
||||||
type: Sequelize.STRING,
|
type: Sequelize.STRING
|
||||||
}, { transaction: t }),
|
},
|
||||||
queryInterface.addColumn('RealEstateRequests', 'priceRange', {
|
{ transaction: t }
|
||||||
type: Sequelize.STRING,
|
),
|
||||||
}, { transaction: t })
|
queryInterface.addColumn(
|
||||||
])
|
"RealEstateRequests",
|
||||||
})
|
"gardenSizeRange",
|
||||||
},
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"priceRange",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.transaction((t) => {
|
return queryInterface.sequelize.transaction(t => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'sizeRange', { transaction: t }),
|
queryInterface.removeColumn("RealEstateRequests", "sizeRange", {
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'gardenSizeRange', { transaction: t }),
|
transaction: t
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'priceRange', { transaction: t })
|
}),
|
||||||
])
|
queryInterface.removeColumn("RealEstateRequests", "gardenSizeRange", {
|
||||||
|
transaction: t
|
||||||
|
}),
|
||||||
|
queryInterface.removeColumn("RealEstateRequests", "priceRange", {
|
||||||
|
transaction: t
|
||||||
})
|
})
|
||||||
}
|
]);
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,63 +1,147 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.transaction((t) => {
|
return queryInterface.sequelize.transaction(t => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'sizeRange', { transaction: t }),
|
queryInterface.removeColumn("RealEstateRequests", "sizeRange", {
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'gardenSizeRange', { transaction: t }),
|
transaction: t
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'priceRange', { transaction: t }),
|
}),
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'size', { transaction: t }),
|
queryInterface.removeColumn("RealEstateRequests", "gardenSizeRange", {
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'gardenSize', { transaction: t }),
|
transaction: t
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'price', { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'gardenSizeMin', {
|
queryInterface.removeColumn("RealEstateRequests", "priceRange", {
|
||||||
type: Sequelize.INTEGER,
|
transaction: t
|
||||||
}, { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'gardenSizeMax', {
|
queryInterface.removeColumn("RealEstateRequests", "size", {
|
||||||
type: Sequelize.INTEGER,
|
transaction: t
|
||||||
}, { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'sizeMin', {
|
queryInterface.removeColumn("RealEstateRequests", "gardenSize", {
|
||||||
type: Sequelize.INTEGER
|
transaction: t
|
||||||
}, { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'sizeMax', {
|
queryInterface.removeColumn("RealEstateRequests", "price", {
|
||||||
type: Sequelize.INTEGER,
|
transaction: t
|
||||||
}, { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'priceMin', {
|
queryInterface.addColumn(
|
||||||
type: Sequelize.INTEGER,
|
"RealEstateRequests",
|
||||||
}, { transaction: t }),
|
"gardenSizeMin",
|
||||||
queryInterface.addColumn('RealEstateRequests', 'priceMax', {
|
{
|
||||||
type: Sequelize.INTEGER
|
type: Sequelize.INTEGER
|
||||||
}, { transaction: t })
|
},
|
||||||
])
|
{ transaction: t }
|
||||||
})
|
),
|
||||||
},
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"gardenSizeMax",
|
||||||
|
{
|
||||||
|
type: Sequelize.INTEGER
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"sizeMin",
|
||||||
|
{
|
||||||
|
type: Sequelize.INTEGER
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"sizeMax",
|
||||||
|
{
|
||||||
|
type: Sequelize.INTEGER
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"priceMin",
|
||||||
|
{
|
||||||
|
type: Sequelize.INTEGER
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"priceMax",
|
||||||
|
{
|
||||||
|
type: Sequelize.INTEGER
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.transaction((t) => {
|
return queryInterface.sequelize.transaction(t => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'gardenSizeMin', { transaction: t }),
|
queryInterface.removeColumn("RealEstateRequests", "gardenSizeMin", {
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'gardenSizeMax', { transaction: t }),
|
transaction: t
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'sizeMin', { transaction: t }),
|
}),
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'sizeMax', { transaction: t }),
|
queryInterface.removeColumn("RealEstateRequests", "gardenSizeMax", {
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'priceMin', { transaction: t }),
|
transaction: t
|
||||||
queryInterface.removeColumn('RealEstateRequests', 'priceMin', { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'priceMax', {
|
queryInterface.removeColumn("RealEstateRequests", "sizeMin", {
|
||||||
type: Sequelize.STRING
|
transaction: t
|
||||||
}, { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'gardenSizeRange', {
|
queryInterface.removeColumn("RealEstateRequests", "sizeMax", {
|
||||||
type: Sequelize.STRING,
|
transaction: t
|
||||||
}, { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'priceRange', {
|
queryInterface.removeColumn("RealEstateRequests", "priceMin", {
|
||||||
type: Sequelize.STRING,
|
transaction: t
|
||||||
}, { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'size', {
|
queryInterface.removeColumn("RealEstateRequests", "priceMin", {
|
||||||
type: Sequelize.STRING
|
transaction: t
|
||||||
}, { transaction: t }),
|
}),
|
||||||
queryInterface.addColumn('RealEstateRequests', 'gardenSize', {
|
queryInterface.addColumn(
|
||||||
type: Sequelize.STRING,
|
"RealEstateRequests",
|
||||||
}, { transaction: t }),
|
"priceMax",
|
||||||
queryInterface.addColumn('RealEstateRequests', 'price', {
|
{
|
||||||
type: Sequelize.STRING,
|
type: Sequelize.STRING
|
||||||
}, { transaction: t })
|
},
|
||||||
])
|
{ transaction: t }
|
||||||
})
|
),
|
||||||
}
|
queryInterface.addColumn(
|
||||||
};
|
"RealEstateRequests",
|
||||||
|
"gardenSizeRange",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"priceRange",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"size",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"gardenSize",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"RealEstateRequests",
|
||||||
|
"price",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn(
|
||||||
'RealEstateRequests',
|
"RealEstateRequests",
|
||||||
'subscribed',
|
"subscribed",
|
||||||
Sequelize.BOOLEAN
|
Sequelize.BOOLEAN
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("RealEstateRequests", "subscribed");
|
||||||
'RealEstateRequests',
|
|
||||||
'subscribed'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,37 +1,70 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.transaction((t) => {
|
return queryInterface.sequelize.transaction(t => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
queryInterface.addColumn('MarketAlerts', 'size', {
|
queryInterface.addColumn(
|
||||||
type: Sequelize.INTEGER,
|
"MarketAlerts",
|
||||||
}, { transaction: t }),
|
"size",
|
||||||
queryInterface.addColumn('MarketAlerts', 'gardenSize', {
|
{
|
||||||
type: Sequelize.INTEGER,
|
type: Sequelize.INTEGER
|
||||||
}, { transaction: t }),
|
},
|
||||||
queryInterface.addColumn('MarketAlerts', 'price', {
|
{ transaction: t }
|
||||||
type: Sequelize.INTEGER,
|
),
|
||||||
}, { transaction: t }),
|
queryInterface.addColumn(
|
||||||
queryInterface.addColumn('MarketAlerts', 'municipality', {
|
"MarketAlerts",
|
||||||
type: Sequelize.STRING,
|
"gardenSize",
|
||||||
}, { transaction: t }),
|
{
|
||||||
queryInterface.addColumn('MarketAlerts', 'region', {
|
type: Sequelize.INTEGER
|
||||||
type: Sequelize.STRING,
|
},
|
||||||
}, { transaction: t })
|
{ transaction: t }
|
||||||
])
|
),
|
||||||
})
|
queryInterface.addColumn(
|
||||||
},
|
"MarketAlerts",
|
||||||
|
"price",
|
||||||
|
{
|
||||||
|
type: Sequelize.INTEGER
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"MarketAlerts",
|
||||||
|
"municipality",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"MarketAlerts",
|
||||||
|
"region",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.transaction((t) => {
|
return queryInterface.sequelize.transaction(t => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
queryInterface.removeColumn('MarketAlerts', 'size', { transaction: t }),
|
queryInterface.removeColumn("MarketAlerts", "size", { transaction: t }),
|
||||||
queryInterface.removeColumn('MarketAlerts', 'gardenSize', { transaction: t }),
|
queryInterface.removeColumn("MarketAlerts", "gardenSize", {
|
||||||
queryInterface.removeColumn('MarketAlerts', 'price', { transaction: t }),
|
transaction: t
|
||||||
queryInterface.removeColumn('MarketAlerts', 'municipality', { transaction: t }),
|
}),
|
||||||
queryInterface.removeColumn('MarketAlerts', 'region', { transaction: t })
|
queryInterface.removeColumn("MarketAlerts", "price", {
|
||||||
])
|
transaction: t
|
||||||
|
}),
|
||||||
|
queryInterface.removeColumn("MarketAlerts", "municipality", {
|
||||||
|
transaction: t
|
||||||
|
}),
|
||||||
|
queryInterface.removeColumn("MarketAlerts", "region", {
|
||||||
|
transaction: t
|
||||||
})
|
})
|
||||||
}
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,33 +1,59 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.transaction((t) => {
|
return queryInterface.sequelize.transaction(t => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
queryInterface.removeColumn('MarketAlerts', 'olxUrl', { transaction: t }),
|
queryInterface.removeColumn("MarketAlerts", "olxUrl", {
|
||||||
queryInterface.addColumn('MarketAlerts', 'url', {
|
transaction: t
|
||||||
type: Sequelize.STRING,
|
}),
|
||||||
}, { transaction: t }),
|
queryInterface.addColumn(
|
||||||
queryInterface.addColumn('MarketAlerts', 'realestateOrigin', {
|
"MarketAlerts",
|
||||||
type: Sequelize.STRING,
|
"url",
|
||||||
}, { transaction: t }),
|
{
|
||||||
queryInterface.addColumn('MarketAlerts', 'originId', {
|
type: Sequelize.STRING
|
||||||
type: Sequelize.STRING,
|
},
|
||||||
}, { transaction: t })
|
{ transaction: t }
|
||||||
])
|
),
|
||||||
})
|
queryInterface.addColumn(
|
||||||
},
|
"MarketAlerts",
|
||||||
|
"realestateOrigin",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
),
|
||||||
|
queryInterface.addColumn(
|
||||||
|
"MarketAlerts",
|
||||||
|
"originId",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.sequelize.transaction((t) => {
|
return queryInterface.sequelize.transaction(t => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
queryInterface.removeColumn('MarketAlerts', 'url', { transaction: t }),
|
queryInterface.removeColumn("MarketAlerts", "url", { transaction: t }),
|
||||||
queryInterface.removeColumn('MarketAlerts', 'realestateOrigin', { transaction: t }),
|
queryInterface.removeColumn("MarketAlerts", "realestateOrigin", {
|
||||||
queryInterface.removeColumn('MarketAlerts', 'originId', { transaction: t }),
|
transaction: t
|
||||||
queryInterface.addColumn('MarketAlerts', 'olxUrl', {
|
}),
|
||||||
type: Sequelize.STRING
|
queryInterface.removeColumn("MarketAlerts", "originId", {
|
||||||
}, { transaction: t })
|
transaction: t
|
||||||
])
|
}),
|
||||||
})
|
queryInterface.addColumn(
|
||||||
}
|
"MarketAlerts",
|
||||||
|
"olxUrl",
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
},
|
||||||
|
{ transaction: t }
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn("MarketAlerts", "realEstateType", {
|
||||||
'MarketAlerts',
|
type: Sequelize.STRING
|
||||||
'realEstateType',
|
});
|
||||||
{
|
|
||||||
type: Sequelize.STRING
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("MarketAlerts", "realEstateType");
|
||||||
'MarketAlerts',
|
|
||||||
'realEstateType'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn("MarketAlerts", "notified", {
|
||||||
'MarketAlerts',
|
type: Sequelize.BOOLEAN
|
||||||
'notified',
|
});
|
||||||
{
|
|
||||||
type: Sequelize.BOOLEAN
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("MarketAlerts", "notified");
|
||||||
'MarketAlerts',
|
|
||||||
'notified'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn("MarketAlerts", "title", {
|
||||||
'MarketAlerts',
|
type: Sequelize.STRING
|
||||||
'title',
|
});
|
||||||
{
|
|
||||||
type: Sequelize.STRING
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("MarketAlerts", "title");
|
||||||
'MarketAlerts',
|
|
||||||
'title'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn("MarketAlerts", "request", {
|
||||||
'MarketAlerts',
|
type: Sequelize.STRING
|
||||||
'request',
|
});
|
||||||
{
|
|
||||||
type: Sequelize.STRING
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("MarketAlerts", "request");
|
||||||
'MarketAlerts',
|
|
||||||
'request'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface, Sequelize) => {
|
up: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.addColumn(
|
return queryInterface.addColumn("MarketAlerts", "hasLocation", {
|
||||||
'MarketAlerts',
|
type: Sequelize.BOOLEAN
|
||||||
'hasLocation',
|
});
|
||||||
{
|
|
||||||
type: Sequelize.BOOLEAN
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
down: (queryInterface, Sequelize) => {
|
||||||
return queryInterface.removeColumn(
|
return queryInterface.removeColumn("MarketAlerts", "hasLocation");
|
||||||
'MarketAlerts',
|
|
||||||
'hasLocation'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,27 +1,39 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require("fs");
|
||||||
const path = require('path');
|
const path = require("path");
|
||||||
const Sequelize = require('sequelize');
|
const Sequelize = require("sequelize");
|
||||||
const basename = path.basename(__filename);
|
const basename = path.basename(__filename);
|
||||||
const env = process.env.NODE_ENV || 'development';
|
const env = process.env.NODE_ENV || "development";
|
||||||
const config = require(__dirname + '/../config/config.json')[env];
|
const config = require(__dirname + "/../config/config.json")[env];
|
||||||
const db = {};
|
const db = {};
|
||||||
|
|
||||||
|
config.username = process.env.DB_USERNAME || config.username;
|
||||||
|
config.password = process.env.DB_PASSWORD || config.password;
|
||||||
|
config.database = process.env.DB_NAME || config.database;
|
||||||
|
config.port = process.env.DB_PORT || config.port;
|
||||||
|
config.logging = parseInt(process.env.SEQUELIZE_LOGGING) ? console.log : false;
|
||||||
|
|
||||||
let sequelize;
|
let sequelize;
|
||||||
if (config.use_env_variable) {
|
if (config.use_env_variable) {
|
||||||
sequelize = new Sequelize(process.env[config.use_env_variable], config);
|
sequelize = new Sequelize(process.env[config.use_env_variable], config);
|
||||||
} else {
|
} else {
|
||||||
sequelize = new Sequelize(config.database, config.username, config.password, config);
|
sequelize = new Sequelize(
|
||||||
|
config.database,
|
||||||
|
config.username,
|
||||||
|
config.password,
|
||||||
|
config
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs
|
fs.readdirSync(__dirname)
|
||||||
.readdirSync(__dirname)
|
|
||||||
.filter(file => {
|
.filter(file => {
|
||||||
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
|
return (
|
||||||
|
file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.forEach(file => {
|
.forEach(file => {
|
||||||
const model = sequelize['import'](path.join(__dirname, file));
|
const model = sequelize["import"](path.join(__dirname, file));
|
||||||
db[model.name] = model;
|
db[model.name] = model;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
module.exports = (sequelize, DataTypes) => {
|
module.exports = (sequelize, DataTypes) => {
|
||||||
const MarketAlert = sequelize.define('MarketAlert', {
|
const MarketAlert = sequelize.define(
|
||||||
url: DataTypes.STRING,
|
"MarketAlert",
|
||||||
realestateOrigin: DataTypes.STRING,
|
{
|
||||||
originId: DataTypes.STRING,
|
url: DataTypes.STRING,
|
||||||
lastDate: DataTypes.STRING,
|
realestateOrigin: DataTypes.STRING,
|
||||||
size : DataTypes.INTEGER,
|
originId: DataTypes.STRING,
|
||||||
gardenSize : DataTypes.INTEGER,
|
lastDate: DataTypes.STRING,
|
||||||
price : DataTypes.INTEGER,
|
size: DataTypes.INTEGER,
|
||||||
municipality : DataTypes.STRING,
|
gardenSize: DataTypes.INTEGER,
|
||||||
region : DataTypes.STRING,
|
price: DataTypes.INTEGER,
|
||||||
realEstateType : DataTypes.STRING,
|
municipality: DataTypes.STRING,
|
||||||
notified : DataTypes.BOOLEAN,
|
region: DataTypes.STRING,
|
||||||
title : DataTypes.STRING,
|
realEstateType: DataTypes.STRING,
|
||||||
request: DataTypes.STRING,
|
notified: DataTypes.BOOLEAN,
|
||||||
hasLocation: DataTypes.BOOLEAN,
|
title: DataTypes.STRING,
|
||||||
|
request: DataTypes.STRING,
|
||||||
email: {
|
hasLocation: DataTypes.BOOLEAN,
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNul: false
|
email: {
|
||||||
}
|
type: DataTypes.STRING,
|
||||||
}, {});
|
allowNul: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
MarketAlert.associate = function(models) {
|
MarketAlert.associate = function(models) {
|
||||||
// associations can be defined here
|
// associations can be defined here
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,26 +1,29 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
module.exports = (sequelize, DataTypes) => {
|
||||||
|
const RealEstateRequest = sequelize.define(
|
||||||
const RealEstateRequest = sequelize.define('RealEstateRequest', {
|
"RealEstateRequest",
|
||||||
uniqueId: {
|
{
|
||||||
type: DataTypes.UUID,
|
uniqueId: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
allowNull: false
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
realEstateType: DataTypes.STRING,
|
||||||
|
email: DataTypes.STRING,
|
||||||
|
region: DataTypes.STRING,
|
||||||
|
municipality: DataTypes.STRING,
|
||||||
|
sizeMin: DataTypes.INTEGER,
|
||||||
|
sizeMax: DataTypes.INTEGER,
|
||||||
|
gardenSizeMin: DataTypes.INTEGER,
|
||||||
|
gardenSizeMax: DataTypes.INTEGER,
|
||||||
|
priceMin: DataTypes.INTEGER,
|
||||||
|
priceMax: DataTypes.INTEGER,
|
||||||
|
bounding_box: DataTypes.GEOMETRY("POINT", 4326),
|
||||||
|
subscribed: DataTypes.BOOLEAN
|
||||||
},
|
},
|
||||||
realEstateType: DataTypes.STRING,
|
{}
|
||||||
email: DataTypes.STRING,
|
);
|
||||||
region: DataTypes.STRING,
|
|
||||||
municipality: DataTypes.STRING,
|
|
||||||
sizeMin: DataTypes.INTEGER,
|
|
||||||
sizeMax: DataTypes.INTEGER,
|
|
||||||
gardenSizeMin: DataTypes.INTEGER,
|
|
||||||
gardenSizeMax: DataTypes.INTEGER,
|
|
||||||
priceMin: DataTypes.INTEGER,
|
|
||||||
priceMax: DataTypes.INTEGER,
|
|
||||||
bounding_box: DataTypes.GEOMETRY('POINT', 4326),
|
|
||||||
subscribed: DataTypes.BOOLEAN
|
|
||||||
}, {});
|
|
||||||
RealEstateRequest.associate = function(models) {
|
RealEstateRequest.associate = function(models) {
|
||||||
// associations can be defined here
|
// associations can be defined here
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,85 +1,77 @@
|
|||||||
|
|
||||||
const Promise = require("bluebird");
|
const Promise = require("bluebird");
|
||||||
const OlxCrawler = require("../helpers/crawlers/olxClawler");
|
const OlxCrawler = require("../helpers/crawlers/olxClawler");
|
||||||
const db = require("../models/index");
|
const db = require("../models/index");
|
||||||
const { allMarketAlerts } = require('../helpers/db/dbHelper');
|
const { allMarketAlerts } = require("../helpers/db/dbHelper");
|
||||||
|
|
||||||
|
|
||||||
async function crawlAll() {
|
async function crawlAll() {
|
||||||
console.log("CRAWLER SERVICE: crawlAll");
|
try {
|
||||||
|
const marketAlertsFromDb = await allMarketAlerts(true);
|
||||||
|
const hrefs = [];
|
||||||
|
|
||||||
try {
|
marketAlertsFromDb.map(marketAlert => {
|
||||||
const marketAlertsFromDb = await allMarketAlerts(true);
|
if (hrefs[marketAlert.request] === undefined) {
|
||||||
const hrefs = [];
|
hrefs[marketAlert.request] = [];
|
||||||
|
}
|
||||||
|
|
||||||
marketAlertsFromDb.map(marketAlert => {
|
hrefs[marketAlert.request].push(marketAlert.url);
|
||||||
if (hrefs[marketAlert.request] === undefined) {
|
});
|
||||||
hrefs[marketAlert.request] = []
|
|
||||||
}
|
|
||||||
|
|
||||||
hrefs[marketAlert.request].push(marketAlert.url);
|
const olxCrawler = new OlxCrawler(hrefs);
|
||||||
})
|
|
||||||
|
|
||||||
console.log("CRAWLER SERVICE: GLOBAL HREFS");
|
const crawlers = [olxCrawler];
|
||||||
console.log(hrefs);
|
|
||||||
const olxCrawler = new OlxCrawler(hrefs);
|
|
||||||
|
|
||||||
const crawlers = [
|
return Promise.map(crawlers, function(crawler) {
|
||||||
olxCrawler,
|
return crawler.crawl();
|
||||||
];
|
}).then(async results => {
|
||||||
|
try {
|
||||||
return Promise.map(crawlers, function (crawler) {
|
const marketAlertsFromDb = await allMarketAlerts(false, true);
|
||||||
return crawler.crawl();
|
|
||||||
}).then(async (results) => {
|
|
||||||
|
|
||||||
try {
|
const marketAlerts = [];
|
||||||
|
const mergedResults = [].concat.apply([], results);
|
||||||
|
|
||||||
const marketAlertsFromDb = await allMarketAlerts(false, true);
|
for (const result of mergedResults) {
|
||||||
|
marketAlerts.push({
|
||||||
|
url: result.url,
|
||||||
|
realestateOrigin: "OLX",
|
||||||
|
originId: 1,
|
||||||
|
size: result.size,
|
||||||
|
price: result.price,
|
||||||
|
email: result.email,
|
||||||
|
request: result.uuid,
|
||||||
|
municipality: result.municipality,
|
||||||
|
region: result.region,
|
||||||
|
gardenSize: isNaN(result.gardenSize) ? 0 : result.gardenSize,
|
||||||
|
realEstateType: result.realEstateType,
|
||||||
|
title: result.title,
|
||||||
|
notified: false,
|
||||||
|
hasLocation: result.hasLocation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
console.log("CRAWLER SERVICE: number of existing MarketAlerts from db: " + marketAlertsFromDb.length);
|
try {
|
||||||
|
const filteredMarketAlerts = marketAlerts.filter(
|
||||||
|
elem =>
|
||||||
|
!marketAlertsFromDb.find(({ url, request }) => {
|
||||||
|
return elem.url === url && elem.request === request;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const marketAlerts = [];
|
await db.MarketAlert.bulkCreate(filteredMarketAlerts);
|
||||||
const mergedResults = [].concat.apply([], results);
|
} catch (e) {
|
||||||
|
console.log(
|
||||||
for (const result of mergedResults) {
|
"CRAWLER SERVICE: Could not bulkCreate marketalers reason: ",
|
||||||
marketAlerts.push({
|
e
|
||||||
url: result.url,
|
);
|
||||||
realestateOrigin: "OLX",
|
}
|
||||||
originId: 1,
|
} catch (e) {
|
||||||
size: result.size,
|
console.log(
|
||||||
price: result.price,
|
"CRAWLER SERVICE: Error crawling. Trying next crawler! ",
|
||||||
email: result.email,
|
e
|
||||||
request: result.uuid,
|
);
|
||||||
municipality: result.municipality,
|
}
|
||||||
region: result.region,
|
});
|
||||||
gardenSize: isNaN(result.gardenSize) ? 0 : result.gardenSize,
|
} catch (e) {
|
||||||
realEstateType: result.realEstateType,
|
console.error("CRAWLER SERVICE:could not fetch marketalerts ", e);
|
||||||
title: result.title,
|
}
|
||||||
notified: false,
|
}
|
||||||
hasLocation: result.hasLocation
|
|
||||||
})
|
|
||||||
}
|
|
||||||
console.log("CRAWLER SERVICE: Number of crawler results: " + marketAlerts.length);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
const filteredMarketAlerts = marketAlerts.filter((elem) => !marketAlertsFromDb.find(({ url, request }) => {
|
|
||||||
|
|
||||||
return (elem.url === url && elem.request === request)
|
|
||||||
}));
|
|
||||||
console.log("CRAWLER SERVICE: Number of new crawler results: " + filteredMarketAlerts.length);
|
|
||||||
|
|
||||||
await db.MarketAlert.bulkCreate(filteredMarketAlerts);
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
console.log("CRAWLER SERVICE: Could not bulkCreate marketalers reason: ", e);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log("CRAWLER SERVICE: Error crawling. Trying next crawler! ", e);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.error("CRAWLER SERVICE:could not fetch marketalerts ", e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
module.exports = crawlAll;
|
module.exports = crawlAll;
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
|
|
||||||
const db = require("../models/index");
|
const db = require("../models/index");
|
||||||
const { allMarketAlerts } = require('../helpers/db/dbHelper');
|
const { allMarketAlerts } = require("../helpers/db/dbHelper");
|
||||||
const { createMarketAlertEmailTemplate, sendBulkEmail } = require('../helpers/awsEmail');
|
const {
|
||||||
|
createMarketAlertEmailTemplate,
|
||||||
|
sendBulkEmail
|
||||||
|
} = require("../helpers/awsEmail");
|
||||||
|
|
||||||
async function processNotifications() {
|
async function processNotifications() {
|
||||||
|
try {
|
||||||
try {
|
const marketAlerts = await allMarketAlerts(false, false);
|
||||||
const marketAlerts = await allMarketAlerts(false, false);
|
await createMarketAlertEmailTemplate();
|
||||||
console.log(marketAlerts.length)
|
if (marketAlerts.length > 0) {
|
||||||
await createMarketAlertEmailTemplate();
|
await sendBulkEmail(marketAlerts);
|
||||||
if (marketAlerts.length > 0) {
|
|
||||||
console.log("NOTIFICATION SERVICE: Number of new alerts: " + marketAlerts.length)
|
|
||||||
await sendBulkEmail(marketAlerts);
|
|
||||||
} else {
|
|
||||||
console.log("NOTIFICATION SERVICE: No new alerts");
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.MarketAlert.update(
|
|
||||||
{ notified: true }, /* set attributes' value */
|
|
||||||
{ where: { notified: false } } /* where criteria */
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.log("NOTIFICATION SERVICE: could not send notifications reason: ", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await db.MarketAlert.update(
|
||||||
|
{ notified: true } /* set attributes' value */,
|
||||||
|
{ where: { notified: false } } /* where criteria */
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(
|
||||||
|
"NOTIFICATION SERVICE: could not send notifications reason: ",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = processNotifications;
|
module.exports = processNotifications;
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
AMAZON_ACCES_KEY_ID=(your-key-here)
|
DB_USERNAME=Username for the database
|
||||||
AMAZON_SECRET_ACCESS_KEY=(your-key-here)
|
DB_PASSWORD=Password for the database
|
||||||
AMAZON_REGION=eu-west-1
|
DB_NAME=Database name
|
||||||
APP_URL=http://localhost:3001
|
DB_PORT=Database port
|
||||||
SOURCE_EMAIL=info@saburly.com
|
|
||||||
|
SEQUELIZE_LOGGING=0- no sequelize logging, 1- log to the console
|
||||||
|
|
||||||
|
APP_PORT=Port for the app, defaults to 5000
|
||||||
|
APP_BASE_URL=base url for the app
|
||||||
|
|
||||||
|
AMAZON_ACCES_KEY_ID=(your-key-here)
|
||||||
|
AMAZON_SECRET_ACCESS_KEY=(your-key-here)
|
||||||
|
AMAZON_REGION=eu-west-1
|
||||||
|
APP_URL=http://localhost:3001
|
||||||
|
SOURCE_EMAIL=info@saburly.com
|
||||||
|
|||||||
14
index.js
14
index.js
@@ -1,3 +1,6 @@
|
|||||||
|
require("dotenv").config();
|
||||||
|
const { APP_PORT } = require("./app/config/appConfig");
|
||||||
|
|
||||||
const welcome = require("./app/controllers/welcome").getWelcome;
|
const welcome = require("./app/controllers/welcome").getWelcome;
|
||||||
const {
|
const {
|
||||||
getRealEstateTypes,
|
getRealEstateTypes,
|
||||||
@@ -48,8 +51,6 @@ const app = express();
|
|||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
const port = process.env.PORT || 5000;
|
|
||||||
|
|
||||||
app.set("views", path.join(__dirname, "/app/views"));
|
app.set("views", path.join(__dirname, "/app/views"));
|
||||||
app.set("view engine", "ejs");
|
app.set("view engine", "ejs");
|
||||||
app.use(layout());
|
app.use(layout());
|
||||||
@@ -180,10 +181,13 @@ app.get("/redirect/:id", redirect);
|
|||||||
|
|
||||||
app.use("/assets", express.static("./app/public"));
|
app.use("/assets", express.static("./app/public"));
|
||||||
|
|
||||||
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
|
app.listen(APP_PORT, () =>
|
||||||
|
console.log(`Example app listening on port ${APP_PORT}!`)
|
||||||
|
);
|
||||||
|
|
||||||
var rule = new schedule.RecurrenceRule();
|
//TODO: based on node-schedule package author, setInterval is better suited for this kind of the job
|
||||||
rule.seccond = 1;
|
const rule = new schedule.RecurrenceRule();
|
||||||
|
rule.second = 1;
|
||||||
schedule.scheduleJob(rule, async function() {
|
schedule.scheduleJob(rule, async function() {
|
||||||
console.log(new Date(), "Crawler service started");
|
console.log(new Date(), "Crawler service started");
|
||||||
await crawlAll();
|
await crawlAll();
|
||||||
|
|||||||
@@ -1,389 +1,430 @@
|
|||||||
<!DOCTYPE>
|
<!DOCTYPE >
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script src="https://code.jquery.com/jquery-3.4.0.js"></script>
|
<script src="https://code.jquery.com/jquery-3.4.0.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<select name="kanton" id="kanton" class="drop-select" onchange="pronadji_gradove()">
|
<select
|
||||||
<option value="">Iz svih lokacija</option>
|
name="kanton"
|
||||||
|
id="kanton"
|
||||||
<option value="" disabled="">Federacija BiH</option>
|
class="drop-select"
|
||||||
<option value="9"> Sarajevo</option>
|
onchange="pronadji_gradove()"
|
||||||
<option value="3"> Tuzlanski</option>
|
>
|
||||||
<option value="4"> Zeničko-Dobojski</option>
|
<option value="">Iz svih lokacija</option>
|
||||||
<option value="1"> Unsko-Sanski</option>
|
|
||||||
<option value="2"> Posavski</option>
|
<option value="" disabled="">Federacija BiH</option>
|
||||||
<option value="5"> Bosansko-podrinjski</option>
|
<option value="9"> Sarajevo</option>
|
||||||
<option value="6"> Srednjobosanski</option>
|
<option value="3"> Tuzlanski</option>
|
||||||
<option value="7"> Hercegovačko-Neretvanski</option>
|
<option value="4"> Zeničko-Dobojski</option>
|
||||||
<option value="8"> Zapadno-Hercegovački</option>
|
<option value="1"> Unsko-Sanski</option>
|
||||||
<option value="10"> Livanjski</option>
|
<option value="2"> Posavski</option>
|
||||||
|
<option value="5"> Bosansko-podrinjski</option>
|
||||||
<option value="" disabled="">Republika Srpska</option>
|
<option value="6"> Srednjobosanski</option>
|
||||||
<option value="14"> Banjalučka</option>
|
<option value="7"> Hercegovačko-Neretvanski</option>
|
||||||
<option value="15"> Dobojsko-Bijeljinska</option>
|
<option value="8"> Zapadno-Hercegovački</option>
|
||||||
<option value="16"> Sarajevsko-Zvornička</option>
|
<option value="10"> Livanjski</option>
|
||||||
<option value="17"> Trebinjsko-Fočanska</option>
|
|
||||||
|
<option value="" disabled="">Republika Srpska</option>
|
||||||
<option value="12">Disktrikt Brčko</option>
|
<option value="14"> Banjalučka</option>
|
||||||
</select>
|
<option value="15"> Dobojsko-Bijeljinska</option>
|
||||||
|
<option value="16"> Sarajevsko-Zvornička</option>
|
||||||
|
<option value="17"> Trebinjsko-Fočanska</option>
|
||||||
<div style="height:40px;">
|
|
||||||
|
<option value="12">Disktrikt Brčko</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
</select>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
|
||||||
<select name="unskosanski" id="unskosanski" class="drop-select" onchange="stavi_grad()">
|
<div style="height:40px;">
|
||||||
<option value="0">Mjesto</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="75">Bihać</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="373">Bosanska Krupa</option>
|
<select
|
||||||
<option value="504">Bosanski Petrovac</option>
|
name="unskosanski"
|
||||||
<option value="374">Bužim</option>
|
id="unskosanski"
|
||||||
<option value="857">Cazin</option>
|
class="drop-select"
|
||||||
<option value="2362">Ključ</option>
|
onchange="stavi_grad()"
|
||||||
<option value="3738">Sanski Most</option>
|
>
|
||||||
<option value="5122">Velika Kladuša</option>
|
<option value="0">Mjesto</option>
|
||||||
</select>
|
<option value="75">Bihać</option>
|
||||||
</span>
|
<option value="373">Bosanska Krupa</option>
|
||||||
</div>
|
<option value="504">Bosanski Petrovac</option>
|
||||||
|
<option value="374">Bužim</option>
|
||||||
|
<option value="857">Cazin</option>
|
||||||
<div style="height:40px;">
|
<option value="2362">Ključ</option>
|
||||||
|
<option value="3738">Sanski Most</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
<option value="5122">Velika Kladuša</option>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
</select>
|
||||||
<select name="posavski" id="posavski" class="drop-select" onchange="stavi_grad()">
|
</span>
|
||||||
<option value="0">Mjesto</option>
|
</div>
|
||||||
<option value="6144">Domaljevac</option>
|
|
||||||
<option value="424">Odžak</option>
|
<div style="height:40px;">
|
||||||
<option value="3252">Orašje</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="540">Šamac</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
</select>
|
<select
|
||||||
</span>
|
name="posavski"
|
||||||
</div>
|
id="posavski"
|
||||||
|
class="drop-select"
|
||||||
|
onchange="stavi_grad()"
|
||||||
<div style="height:40px;">
|
>
|
||||||
|
<option value="0">Mjesto</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
<option value="6144">Domaljevac</option>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<option value="424">Odžak</option>
|
||||||
<select name="tuzlanski" id="tuzlanski" class="drop-select" onchange="stavi_grad()">
|
<option value="3252">Orašje</option>
|
||||||
<option value="0">Mjesto</option>
|
<option value="540">Šamac</option>
|
||||||
<option value="2">Banovići</option>
|
</select>
|
||||||
<option value="1090">Doboj-Istok</option>
|
</span>
|
||||||
<option value="1854">Gradačac</option>
|
</div>
|
||||||
<option value="1826">Gračanica</option>
|
|
||||||
<option value="2129">Kalesija</option>
|
<div style="height:40px;">
|
||||||
<option value="2319">Kladanj</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="2840">Lukavac</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="5699">Sapna</option>
|
<select
|
||||||
<option value="4391">Srebrenik</option>
|
name="tuzlanski"
|
||||||
<option value="5010">Teočak</option>
|
id="tuzlanski"
|
||||||
<option value="4944">Tuzla</option>
|
class="drop-select"
|
||||||
<option value="2801">Čelić</option>
|
onchange="stavi_grad()"
|
||||||
<option value="5774">Živinice</option>
|
>
|
||||||
</select>
|
<option value="0">Mjesto</option>
|
||||||
</span>
|
<option value="2">Banovići</option>
|
||||||
</div>
|
<option value="1090">Doboj-Istok</option>
|
||||||
|
<option value="1854">Gradačac</option>
|
||||||
|
<option value="1826">Gračanica</option>
|
||||||
<div style="height:40px;">
|
<option value="2129">Kalesija</option>
|
||||||
|
<option value="2319">Kladanj</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
<option value="2840">Lukavac</option>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<option value="5699">Sapna</option>
|
||||||
<select name="zenickodobojski" id="zenickodobojski" class="drop-select" onchange="stavi_grad()">
|
<option value="4391">Srebrenik</option>
|
||||||
<option value="0">Mjesto</option>
|
<option value="5010">Teočak</option>
|
||||||
<option value="704">Breza</option>
|
<option value="4944">Tuzla</option>
|
||||||
<option value="1122">Doboj-Jug</option>
|
<option value="2801">Čelić</option>
|
||||||
<option value="2022">Kakanj</option>
|
<option value="5774">Živinice</option>
|
||||||
<option value="2941">Maglaj</option>
|
</select>
|
||||||
<option value="1925">Olovo</option>
|
</span>
|
||||||
<option value="4594">Tešanj</option>
|
</div>
|
||||||
<option value="1087">Usora</option>
|
|
||||||
<option value="5037">Vareš</option>
|
<div style="height:40px;">
|
||||||
<option value="5171">Visoko</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="5548">Zavidovići</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="4571">Zenica</option>
|
<select
|
||||||
<option value="2940">Žepče</option>
|
name="zenickodobojski"
|
||||||
</select>
|
id="zenickodobojski"
|
||||||
</span>
|
class="drop-select"
|
||||||
</div>
|
onchange="stavi_grad()"
|
||||||
|
>
|
||||||
|
<option value="0">Mjesto</option>
|
||||||
<div style="height:40px;">
|
<option value="704">Breza</option>
|
||||||
|
<option value="1122">Doboj-Jug</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
<option value="2022">Kakanj</option>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<option value="2941">Maglaj</option>
|
||||||
<select name="" id="bosanskopodrinjski" class="drop-select" onchange="stavi_grad()">
|
<option value="1925">Olovo</option>
|
||||||
<option value="0">Mjesto</option>
|
<option value="4594">Tešanj</option>
|
||||||
<option value="1289">Foča</option>
|
<option value="1087">Usora</option>
|
||||||
<option value="1588">Goražde</option>
|
<option value="5037">Vareš</option>
|
||||||
<option value="3546">Pale</option>
|
<option value="5171">Visoko</option>
|
||||||
</select>
|
<option value="5548">Zavidovići</option>
|
||||||
</span>
|
<option value="4571">Zenica</option>
|
||||||
</div>
|
<option value="2940">Žepče</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
<div style="height:40px;">
|
</div>
|
||||||
|
|
||||||
<span class="drop-container" style="width: 168px;">
|
<div style="height:40px;">
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<select name="" id="srednjobosanski" class="drop-select" onchange="stavi_grad()">
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="0">Mjesto</option>
|
<select
|
||||||
<option value="732">Bugojno</option>
|
name=""
|
||||||
<option value="810">Busovača</option>
|
id="bosanskopodrinjski"
|
||||||
<option value="4151">Dobretići</option>
|
class="drop-select"
|
||||||
<option value="1160">Donji Vakuf</option>
|
onchange="stavi_grad()"
|
||||||
<option value="1407">Fojnica</option>
|
>
|
||||||
<option value="1775">Gornji Vakuf - Uskoplje</option>
|
<option value="0">Mjesto</option>
|
||||||
<option value="1960">Jajce</option>
|
<option value="1289">Foča</option>
|
||||||
<option value="2237">Kiseljak</option>
|
<option value="1588">Goražde</option>
|
||||||
<option value="2608">Kreševo</option>
|
<option value="3546">Pale</option>
|
||||||
<option value="3477">Novi Travnik</option>
|
</select>
|
||||||
<option value="4678">Travnik</option>
|
</span>
|
||||||
<option value="5422">Vitez</option>
|
</div>
|
||||||
</select>
|
|
||||||
</span>
|
<div style="height:40px;">
|
||||||
</div>
|
<span class="drop-container" style="width: 168px;">
|
||||||
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
|
<select
|
||||||
<div style="height:40px;">
|
name=""
|
||||||
|
id="srednjobosanski"
|
||||||
<span class="drop-container" style="width: 168px;">
|
class="drop-select"
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
onchange="stavi_grad()"
|
||||||
<select name="" id="hercegovackoneretvanski" class="drop-select" onchange="stavi_grad()">
|
>
|
||||||
<option value="0">Mjesto</option>
|
<option value="0">Mjesto</option>
|
||||||
<option value="3017">Grad Mostar</option>
|
<option value="732">Bugojno</option>
|
||||||
<option value="1930">Jablanica</option>
|
<option value="810">Busovača</option>
|
||||||
<option value="2169">Konjic</option>
|
<option value="4151">Dobretići</option>
|
||||||
<option value="3111">Neum</option>
|
<option value="1160">Donji Vakuf</option>
|
||||||
<option value="3421">Prozor</option>
|
<option value="1407">Fojnica</option>
|
||||||
<option value="4769">Ravno</option>
|
<option value="1775">Gornji Vakuf - Uskoplje</option>
|
||||||
<option value="4439">Stolac</option>
|
<option value="1960">Jajce</option>
|
||||||
<option value="947">Čapljina</option>
|
<option value="2237">Kiseljak</option>
|
||||||
<option value="1009">Čitluk</option>
|
<option value="2608">Kreševo</option>
|
||||||
</select>
|
<option value="3477">Novi Travnik</option>
|
||||||
</span>
|
<option value="4678">Travnik</option>
|
||||||
</div>
|
<option value="5422">Vitez</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
<div style="height:40px;">
|
</div>
|
||||||
|
|
||||||
<span class="drop-container" style="width: 168px;">
|
<div style="height:40px;">
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<select name="" id="zapadnohercegovacki" class="drop-select" onchange="stavi_grad()">
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="0">Mjesto</option>
|
<select
|
||||||
<option value="1892">Grude</option>
|
name=""
|
||||||
<option value="2905">Ljubuški</option>
|
id="hercegovackoneretvanski"
|
||||||
<option value="3268">Posušje</option>
|
class="drop-select"
|
||||||
<option value="2708">Široki Brijeg</option>
|
onchange="stavi_grad()"
|
||||||
</select>
|
>
|
||||||
</span>
|
<option value="0">Mjesto</option>
|
||||||
</div>
|
<option value="3017">Grad Mostar</option>
|
||||||
|
<option value="1930">Jablanica</option>
|
||||||
|
<option value="2169">Konjic</option>
|
||||||
<div style="height:40px;">
|
<option value="3111">Neum</option>
|
||||||
|
<option value="3421">Prozor</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
<option value="4769">Ravno</option>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<option value="4439">Stolac</option>
|
||||||
<select name="" id="sarajevo" class="drop-select" onchange="stavi_grad()">
|
<option value="947">Čapljina</option>
|
||||||
<option value="0">Mjesto</option>
|
<option value="1009">Čitluk</option>
|
||||||
<option value="3817">Hadžići</option>
|
</select>
|
||||||
<option value="3879">Ilidža</option>
|
</span>
|
||||||
<option value="3892">Ilijaš</option>
|
</div>
|
||||||
<option value="3812">Sarajevo - Centar</option>
|
|
||||||
<option value="3969">Sarajevo-Novi Grad</option>
|
<div style="height:40px;">
|
||||||
<option value="5896">Sarajevo-Novo Sarajevo</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="4048">Sarajevo-Stari Grad</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="4063">Trnovo</option>
|
<select
|
||||||
<option value="4126">Vogošća</option>
|
name=""
|
||||||
</select>
|
id="zapadnohercegovacki"
|
||||||
</span>
|
class="drop-select"
|
||||||
</div>
|
onchange="stavi_grad()"
|
||||||
|
>
|
||||||
|
<option value="0">Mjesto</option>
|
||||||
<div style="height:40px;">
|
<option value="1892">Grude</option>
|
||||||
|
<option value="2905">Ljubuški</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
<option value="3268">Posušje</option>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<option value="2708">Široki Brijeg</option>
|
||||||
<select name="" id="livanjski" class="drop-select" onchange="stavi_grad()">
|
</select>
|
||||||
<option value="0">Mjesto</option>
|
</span>
|
||||||
<option value="560">Bosansko Grahovo</option>
|
</div>
|
||||||
<option value="4640">Drvar</option>
|
|
||||||
<option value="1533">Glamoč</option>
|
<div style="height:40px;">
|
||||||
<option value="2635">Kupres</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="2741">Livno</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="1228">Tomislavgrad</option>
|
<select
|
||||||
</select>
|
name=""
|
||||||
</span>
|
id="sarajevo"
|
||||||
</div>
|
class="drop-select"
|
||||||
|
onchange="stavi_grad()"
|
||||||
|
>
|
||||||
<div style="height:40px;">
|
<option value="0">Mjesto</option>
|
||||||
|
<option value="3817">Hadžići</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
<option value="3879">Ilidža</option>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<option value="3892">Ilijaš</option>
|
||||||
<select name="" id="grad11" class="drop-select" onchange="stavi_grad()">
|
<option value="3812">Sarajevo - Centar</option>
|
||||||
<option value="0">Mjesto</option>
|
<option value="3969">Sarajevo-Novi Grad</option>
|
||||||
<option value="645">distriktbrcko</option>
|
<option value="5896">Sarajevo-Novo Sarajevo</option>
|
||||||
</select>
|
<option value="4048">Sarajevo-Stari Grad</option>
|
||||||
</span>
|
<option value="4063">Trnovo</option>
|
||||||
</div>
|
<option value="4126">Vogošća</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
<div style="height:40px;">
|
</div>
|
||||||
|
|
||||||
<span class="drop-container" style="width: 168px;">
|
<div style="height:40px;">
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<select name="" id="banjalučka" class="drop-select" onchange="stavi_grad()">
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="0">Mjesto</option>
|
<select
|
||||||
<option value="21">Banja Luka</option>
|
name=""
|
||||||
<option value="305">Gradiška</option>
|
id="livanjski"
|
||||||
<option value="4662">Istočni Drvar</option>
|
class="drop-select"
|
||||||
<option value="1965">Jezero</option>
|
onchange="stavi_grad()"
|
||||||
<option value="4147">Kneževo</option>
|
>
|
||||||
<option value="6142">Kostajnica</option>
|
<option value="0">Mjesto</option>
|
||||||
<option value="2574">Kotor Varoš</option>
|
<option value="560">Bosansko Grahovo</option>
|
||||||
<option value="244">Kozarska Dubica</option>
|
<option value="4640">Drvar</option>
|
||||||
<option value="382">Krupa na uni</option>
|
<option value="1533">Glamoč</option>
|
||||||
<option value="2654">Kupres </option>
|
<option value="2635">Kupres</option>
|
||||||
<option value="2671">Laktaši</option>
|
<option value="2741">Livno</option>
|
||||||
<option value="3073">Mrkonjić Grad</option>
|
<option value="1228">Tomislavgrad</option>
|
||||||
<option value="444">Novi Grad</option>
|
</select>
|
||||||
<option value="3737">Oštra Luka</option>
|
</span>
|
||||||
<option value="515">Petrovac</option>
|
</div>
|
||||||
<option value="3287">Prijedor</option>
|
|
||||||
<option value="3358">Prnjavor</option>
|
<div style="height:40px;">
|
||||||
<option value="2365">Ribnik</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="4271">Srbac</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="979">Čelinac</option>
|
<select name="" id="grad11" class="drop-select" onchange="stavi_grad()">
|
||||||
<option value="4509">Šipovo</option>
|
<option value="0">Mjesto</option>
|
||||||
</select>
|
<option value="645">distriktbrcko</option>
|
||||||
</span>
|
</select>
|
||||||
</div>
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="height:40px;">
|
<div style="height:40px;">
|
||||||
|
<span class="drop-container" style="width: 168px;">
|
||||||
<span class="drop-container" style="width: 168px;">
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
<select
|
||||||
<select name="" id="dobojskobijeljinska" class="drop-select" onchange="stavi_grad()">
|
name=""
|
||||||
<option value="0">Mjesto</option>
|
id="banjalučka"
|
||||||
<option value="123">Bijeljina</option>
|
class="drop-select"
|
||||||
<option value="421">Bosanski Brod</option>
|
onchange="stavi_grad()"
|
||||||
<option value="1030">Derventa</option>
|
>
|
||||||
<option value="1088">Doboj</option>
|
<option value="0">Mjesto</option>
|
||||||
<option value="3254">Donji Žabar</option>
|
<option value="21">Banja Luka</option>
|
||||||
<option value="2800">Lopare</option>
|
<option value="305">Gradiška</option>
|
||||||
<option value="6029">Lukavac</option>
|
<option value="4662">Istočni Drvar</option>
|
||||||
<option value="2996">Modriča</option>
|
<option value="1965">Jezero</option>
|
||||||
<option value="1856">Pelagićevo</option>
|
<option value="4147">Kneževo</option>
|
||||||
<option value="1827">Petrovo</option>
|
<option value="6142">Kostajnica</option>
|
||||||
<option value="1148">Stanari</option>
|
<option value="2574">Kotor Varoš</option>
|
||||||
<option value="4549">Teslić</option>
|
<option value="244">Kozarska Dubica</option>
|
||||||
<option value="4636">Tešanj</option>
|
<option value="382">Krupa na uni</option>
|
||||||
<option value="4692">Travnik</option>
|
<option value="2654">Kupres </option>
|
||||||
<option value="4966">Tuzla</option>
|
<option value="2671">Laktaši</option>
|
||||||
<option value="5009">Ugljevik</option>
|
<option value="3073">Mrkonjić Grad</option>
|
||||||
<option value="3197">Vukosavlje</option>
|
<option value="444">Novi Grad</option>
|
||||||
<option value="539">Šamac</option>
|
<option value="3737">Oštra Luka</option>
|
||||||
</select>
|
<option value="515">Petrovac</option>
|
||||||
</span>
|
<option value="3287">Prijedor</option>
|
||||||
</div>
|
<option value="3358">Prnjavor</option>
|
||||||
|
<option value="2365">Ribnik</option>
|
||||||
|
<option value="4271">Srbac</option>
|
||||||
<div style="height:40px;">
|
<option value="979">Čelinac</option>
|
||||||
|
<option value="4509">Šipovo</option>
|
||||||
<span class="drop-container" style="width: 168px;">
|
</select>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
</span>
|
||||||
<select name="" id="sarajevskozvornicka" class="drop-select" onchange="stavi_grad()">
|
</div>
|
||||||
<option value="0">Mjesto</option>
|
|
||||||
<option value="595">Bratunac</option>
|
<div style="height:40px;">
|
||||||
<option value="1904">Han Pijesak</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="3947">Ilijaš</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="4049">Istočni Stari Grad</option>
|
<select
|
||||||
<option value="3880">Kasindo</option>
|
name=""
|
||||||
<option value="2325">Kladanj</option>
|
id="dobojskobijeljinska"
|
||||||
<option value="3971">Lukavica</option>
|
class="drop-select"
|
||||||
<option value="6143">Milići</option>
|
onchange="stavi_grad()"
|
||||||
<option value="3221">Olovo</option>
|
>
|
||||||
<option value="2128">Osmaci</option>
|
<option value="0">Mjesto</option>
|
||||||
<option value="3978">Pale</option>
|
<option value="123">Bijeljina</option>
|
||||||
<option value="3529">Rogatica</option>
|
<option value="421">Bosanski Brod</option>
|
||||||
<option value="3648">Rudo</option>
|
<option value="1030">Derventa</option>
|
||||||
<option value="6069">Sarajevo-Novi Grad</option>
|
<option value="1088">Doboj</option>
|
||||||
<option value="4183">Sokolac</option>
|
<option value="3254">Donji Žabar</option>
|
||||||
<option value="4310">Srebrenica</option>
|
<option value="2800">Lopare</option>
|
||||||
<option value="4067">Trnovo</option>
|
<option value="6029">Lukavac</option>
|
||||||
<option value="1593">Ustiprača</option>
|
<option value="2996">Modriča</option>
|
||||||
<option value="5259">Višegrad</option>
|
<option value="1856">Pelagićevo</option>
|
||||||
<option value="5456">Vlasenica</option>
|
<option value="1827">Petrovo</option>
|
||||||
<option value="5684">Zvornik</option>
|
<option value="1148">Stanari</option>
|
||||||
<option value="4475">Šekovići</option>
|
<option value="4549">Teslić</option>
|
||||||
<option value="1906">Žepa</option>
|
<option value="4636">Tešanj</option>
|
||||||
</select>
|
<option value="4692">Travnik</option>
|
||||||
</span>
|
<option value="4966">Tuzla</option>
|
||||||
</div>
|
<option value="5009">Ugljevik</option>
|
||||||
|
<option value="3197">Vukosavlje</option>
|
||||||
|
<option value="539">Šamac</option>
|
||||||
<div style="height:40px;">
|
</select>
|
||||||
|
</span>
|
||||||
<span class="drop-container" style="width: 168px;">
|
</div>
|
||||||
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
|
||||||
<select name="" id="trebinjskofocanska" class="drop-select" onchange="stavi_grad()">
|
<div style="height:40px;">
|
||||||
<option value="0">Mjesto</option>
|
<span class="drop-container" style="width: 168px;">
|
||||||
<option value="4441">Berkovići</option>
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
<option value="183">Bileća</option>
|
<select
|
||||||
<option value="1287">Foča</option>
|
name=""
|
||||||
<option value="1462">Gacko</option>
|
id="sarajevskozvornicka"
|
||||||
<option value="3038">Istočni Mostar</option>
|
class="drop-select"
|
||||||
<option value="2164">Kalinovik</option>
|
onchange="stavi_grad()"
|
||||||
<option value="2884">Ljubinje</option>
|
>
|
||||||
<option value="3138">Nevesinje</option>
|
<option value="0">Mjesto</option>
|
||||||
<option value="4766">Trebinje</option>
|
<option value="595">Bratunac</option>
|
||||||
<option value="911">Čajniče</option>
|
<option value="1904">Han Pijesak</option>
|
||||||
</select>
|
<option value="3947">Ilijaš</option>
|
||||||
</span>
|
<option value="4049">Istočni Stari Grad</option>
|
||||||
</div>
|
<option value="3880">Kasindo</option>
|
||||||
|
<option value="2325">Kladanj</option>
|
||||||
<script>
|
<option value="3971">Lukavica</option>
|
||||||
|
<option value="6143">Milići</option>
|
||||||
const stavi_grad = () => {};
|
<option value="3221">Olovo</option>
|
||||||
const gradovi = [
|
<option value="2128">Osmaci</option>
|
||||||
{"ime":" Sarajevo","id":"sarajevo"},
|
<option value="3978">Pale</option>
|
||||||
{"ime":" Unsko-sanski","id":"unskosanski"},
|
<option value="3529">Rogatica</option>
|
||||||
{"ime":" Posavski","id":"posavski"},
|
<option value="3648">Rudo</option>
|
||||||
{"ime":" Tuzlanski","id":"tuzlanski"},
|
<option value="6069">Sarajevo-Novi Grad</option>
|
||||||
{"ime":" Zeničko-dobojski","id":"zenickodobojski"},
|
<option value="4183">Sokolac</option>
|
||||||
{"ime":" Bosansko-podrinjski","id":"bosanskopodrinjski"},
|
<option value="4310">Srebrenica</option>
|
||||||
{"ime":" Srednjobosanski","id":"srednjobosanski"},
|
<option value="4067">Trnovo</option>
|
||||||
{"ime":" Hercegovačko-neretvanski","id":"hercegovackoneretvanski"},
|
<option value="1593">Ustiprača</option>
|
||||||
{"ime":" Zapadno-hercegovački","id":"zapadnohercegovacki"},
|
<option value="5259">Višegrad</option>
|
||||||
{"ime":" Livanjski","id":"livanjski"},
|
<option value="5456">Vlasenica</option>
|
||||||
{"ime":" Banjalučka","id":"banjalučka"},
|
<option value="5684">Zvornik</option>
|
||||||
{"ime":" Dobojsko-Bijeljinska","id":"dobojskobijeljinska"},
|
<option value="4475">Šekovići</option>
|
||||||
{"ime":" Sarajevsko-Zvornička","id":"sarajevskozvornicka"},
|
<option value="1906">Žepa</option>
|
||||||
{"ime":" Trebinjsko-Fočanska","id":"trebinjskofocanska"},
|
</select>
|
||||||
{"ime":"Distrikt Brčko","id":"distriktbrcko"},
|
</span>
|
||||||
];
|
</div>
|
||||||
|
|
||||||
for (let grad of gradovi) {
|
<div style="height:40px;">
|
||||||
const mjesta = [];
|
<span class="drop-container" style="width: 168px;">
|
||||||
$('#' + grad.id).children().each( function() {
|
<span class="drop-label">Mjesto</span><span class="drop-arrow"></span>
|
||||||
const mjesto = $(this).text();
|
<select
|
||||||
mjesta.push( {
|
name=""
|
||||||
ime: mjesto,
|
id="trebinjskofocanska"
|
||||||
id: mjesto.toLowerCase().replace(/[^a-z]/g,''),
|
class="drop-select"
|
||||||
olxid: $(this).val()
|
onchange="stavi_grad()"
|
||||||
});
|
>
|
||||||
});
|
<option value="0">Mjesto</option>
|
||||||
grad.mjesta = mjesta;
|
<option value="4441">Berkovići</option>
|
||||||
}
|
<option value="183">Bileća</option>
|
||||||
|
<option value="1287">Foča</option>
|
||||||
console.log(JSON.stringify(gradovi));
|
<option value="1462">Gacko</option>
|
||||||
|
<option value="3038">Istočni Mostar</option>
|
||||||
</script>
|
<option value="2164">Kalinovik</option>
|
||||||
|
<option value="2884">Ljubinje</option>
|
||||||
</body>
|
<option value="3138">Nevesinje</option>
|
||||||
</html>
|
<option value="4766">Trebinje</option>
|
||||||
|
<option value="911">Čajniče</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const stavi_grad = () => {};
|
||||||
|
const gradovi = [
|
||||||
|
{ ime: " Sarajevo", id: "sarajevo" },
|
||||||
|
{ ime: " Unsko-sanski", id: "unskosanski" },
|
||||||
|
{ ime: " Posavski", id: "posavski" },
|
||||||
|
{ ime: " Tuzlanski", id: "tuzlanski" },
|
||||||
|
{ ime: " Zeničko-dobojski", id: "zenickodobojski" },
|
||||||
|
{ ime: " Bosansko-podrinjski", id: "bosanskopodrinjski" },
|
||||||
|
{ ime: " Srednjobosanski", id: "srednjobosanski" },
|
||||||
|
{ ime: " Hercegovačko-neretvanski", id: "hercegovackoneretvanski" },
|
||||||
|
{ ime: " Zapadno-hercegovački", id: "zapadnohercegovacki" },
|
||||||
|
{ ime: " Livanjski", id: "livanjski" },
|
||||||
|
{ ime: " Banjalučka", id: "banjalučka" },
|
||||||
|
{ ime: " Dobojsko-Bijeljinska", id: "dobojskobijeljinska" },
|
||||||
|
{ ime: " Sarajevsko-Zvornička", id: "sarajevskozvornicka" },
|
||||||
|
{ ime: " Trebinjsko-Fočanska", id: "trebinjskofocanska" },
|
||||||
|
{ ime: "Distrikt Brčko", id: "distriktbrcko" }
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let grad of gradovi) {
|
||||||
|
const mjesta = [];
|
||||||
|
$("#" + grad.id)
|
||||||
|
.children()
|
||||||
|
.each(function() {
|
||||||
|
const mjesto = $(this).text();
|
||||||
|
mjesta.push({
|
||||||
|
ime: mjesto,
|
||||||
|
id: mjesto.toLowerCase().replace(/[^a-z]/g, ""),
|
||||||
|
olxid: $(this).val()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
grad.mjesta = mjesta;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user