From 60e618fd227008d0543860bd043d94a910351ba4 Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Thu, 5 Sep 2019 11:14:54 +0200 Subject: [PATCH 1/7] apply prettier on all files --- app/controllers/gardenSizes.js | 35 +- app/controllers/goAgain.js | 4 +- app/controllers/municipalities.js | 22 +- app/controllers/neighborhoodMap.js | 54 +- app/controllers/prices.js | 34 +- app/controllers/queryReview.js | 84 +- app/controllers/querySubmit.js | 21 +- app/controllers/realEstateTypes.js | 37 +- app/controllers/realEstates.js | 28 +- app/controllers/regions.js | 16 +- app/controllers/sizes.js | 36 +- app/controllers/unsubscribe.js | 19 +- app/controllers/welcome.js | 6 +- app/helpers/awsEmail.js | 4 +- app/helpers/codes.js | 1811 +++++++++-------- app/helpers/email.js | 5 +- app/helpers/enums.js | 72 +- app/helpers/url.js | 12 +- app/lib/sendNotification.js | 47 +- .../20190417035319-create-market-alert.js | 6 +- ...190417035707-create-real-estate-request.js | 6 +- ...7043621-add_city_to_real_estate_request.js | 13 +- ...050222-add_place_to_real_estate_request.js | 13 +- .../20190516180226-rename-place-column.js | 14 +- .../20190516222240-rename-city-column.js | 14 +- ...7072957-add-size-to-real-estate-request.js | 17 +- ...5-add-gardenSize-to-real-estate-request.js | 17 +- ...092716-add-price-to-real-estate-request.js | 17 +- .../20190523144812-activate-postgis.js | 16 +- .../20190523151420-add-bounding-box-column.js | 24 +- .../20190529093410-slider-fields.js | 69 +- app/migrations/20190530101945-range-fields.js | 206 +- .../20190531111232-subscribed-boolean.js | 13 +- .../20190618103020-expand-maketalert.js | 97 +- ...0618124522-marketalerts-additional-info.js | 84 +- ...90621162321-add-category-to-marketalert.js | 17 +- ...-notification-sent-boolean-marketalerts.js | 17 +- ...0190628165512-add-title-to-marketalerts.js | 17 +- ...132143-add-RREquet-uuid-to-marketalerts.js | 17 +- ...141356-add-has-location-to-marketalerts.js | 17 +- app/models/index.js | 28 +- app/models/marketalert.js | 48 +- app/models/realestaterequest.js | 43 +- app/services/crawlerService.js | 144 +- app/services/notificationService.js | 49 +- 45 files changed, 1749 insertions(+), 1621 deletions(-) diff --git a/app/controllers/gardenSizes.js b/app/controllers/gardenSizes.js index 11f89ac..83a8fe1 100644 --- a/app/controllers/gardenSizes.js +++ b/app/controllers/gardenSizes.js @@ -1,32 +1,31 @@ -const { currentRERequest } = require('../helpers/url'); -const { getRealEstateTypeEnum } = require('../helpers/enums'); +const { currentRERequest } = require("../helpers/url"); +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 = { - min : 10, - max : 3000, - value : 0, - step : 10 - } + min: 10, + max: 3000, + value: 0, + step: 10 + }; const rangeTo = { - min : 10, - max : 3000, - value : 100, - step : 10 - } + min: 10, + max: 3000, + value: 100, + step: 10 + }; - res.render('gardenSize', { rangeFrom, rangeTo, unit, title }); + res.render("gardenSize", { rangeFrom, rangeTo, unit, title }); }; const postGardenSize = async (req, res) => { const request = await currentRERequest(req); - const nextStepPage = req.query.nextStep || 'cijena'; + const nextStepPage = req.query.nextStep || "cijena"; const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`; const realEstateType = getRealEstateTypeEnum(request.realEstateType); diff --git a/app/controllers/goAgain.js b/app/controllers/goAgain.js index c6b6d81..93d057b 100644 --- a/app/controllers/goAgain.js +++ b/app/controllers/goAgain.js @@ -1,6 +1,6 @@ -const getGoAgain = async (req,res) => { +const getGoAgain = async (req, res) => { const title = "Želite li pretražiti još jednu nekretninu ?"; - res.render('goAgain', {title}); + res.render("goAgain", { title }); }; module.exports = { diff --git a/app/controllers/municipalities.js b/app/controllers/municipalities.js index 349fd9c..0950a43 100644 --- a/app/controllers/municipalities.js +++ b/app/controllers/municipalities.js @@ -1,20 +1,26 @@ -const { currentRERequest } = require('../helpers/url'); -const { getMunicipalitiesForRegion, getMunicipalityName } = require('../helpers/codes'); +const { currentRERequest } = require("../helpers/url"); +const { + getMunicipalitiesForRegion, + getMunicipalityName +} = require("../helpers/codes"); 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); const municipalities = getMunicipalitiesForRegion(request.region); - res.render('municipality', { municipalities, title }); + res.render("municipality", { municipalities, title }); }; const postMunicipality = async (req, res) => { - const request = await currentRERequest(req); - const nextStepParam = req.query.nextStep ? "?nextStep=" + req.query.nextStep : ""; - const nextStepUrl = `/${'naselje'}/${request.uniqueId}/${getMunicipalityName(request.region, req.body.municipality)}${nextStepParam}`; + const nextStepParam = req.query.nextStep + ? "?nextStep=" + req.query.nextStep + : ""; + const nextStepUrl = `/${"naselje"}/${request.uniqueId}/${getMunicipalityName( + request.region, + req.body.municipality + )}${nextStepParam}`; request.municipality = req.body.municipality; await request.save(); diff --git a/app/controllers/neighborhoodMap.js b/app/controllers/neighborhoodMap.js index 1edd926..f3a8e22 100644 --- a/app/controllers/neighborhoodMap.js +++ b/app/controllers/neighborhoodMap.js @@ -1,41 +1,37 @@ -const { currentRERequest } = require('../helpers/url'); +const { currentRERequest } = require("../helpers/url"); 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?" - const municipality = req.params.municipality - const nextStep = req.query.nextStep || '/'; - - res.render('neighborhoodMap', { - nextStep, - municipality, - title - }); - + res.render("neighborhoodMap", { + nextStep, + municipality, + title + }); }; const postNeighborhood = async (req, res) => { - let request = await currentRERequest(req); - const northWest = [req.body.west, req.body.north]; - const northEast = [req.body.east, req.body.north]; - const southEast = [req.body.east, req.body.south]; - const southWest = [req.body.west, req.body.south]; + let request = await currentRERequest(req); + const northWest = [req.body.west, req.body.north]; + const northEast = [req.body.east, req.body.north]; + const southEast = [req.body.east, req.body.south]; + const southWest = [req.body.west, req.body.south]; - request.bounding_box = { - type: 'Polygon', coordinates: [ - [northWest, northEast, southEast, - southWest, northWest] - ] - }; - await request.save(); + request.bounding_box = { + type: "Polygon", + coordinates: [[northWest, northEast, southEast, southWest, northWest]] + }; + await request.save(); - const nextStepPage = req.query.nextStep || 'povrsina'; - const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`; + const nextStepPage = req.query.nextStep || "povrsina"; + const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`; - res.redirect(nextStepUrl); + res.redirect(nextStepUrl); }; module.exports = { - getNeighborhood, - postNeighborhood -}; \ No newline at end of file + getNeighborhood, + postNeighborhood +}; diff --git a/app/controllers/prices.js b/app/controllers/prices.js index d4c99fe..2ae5720 100644 --- a/app/controllers/prices.js +++ b/app/controllers/prices.js @@ -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 = { - min : 1000, - max : 250000, - value : 0, - step : 1000 - } + min: 1000, + max: 250000, + value: 0, + step: 1000 + }; const rangeTo = { - min : 1000, - max : 250000, - value : 50000, - step : 1000 - } + min: 1000, + max: 250000, + value: 50000, + step: 1000 + }; - - res.render('price', {rangeFrom, rangeTo, unit, title }); + res.render("price", { rangeFrom, rangeTo, unit, title }); }; const postPrice = async (req, res) => { const request = await currentRERequest(req); - const nextStepPage = req.query.nextStep || 'pregled'; + const nextStepPage = req.query.nextStep || "pregled"; const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`; request.priceMin = req.body.from; diff --git a/app/controllers/queryReview.js b/app/controllers/queryReview.js index 023435c..fd1c40e 100644 --- a/app/controllers/queryReview.js +++ b/app/controllers/queryReview.js @@ -1,10 +1,16 @@ -const { currentRERequest } = require('../helpers/url'); -const { getRegionName, getMunicipalityName } = require('../helpers/codes'); -const { realEstateTypes, sizes, gardenSizes, prices, getEnumTypeTitle, getRealEstateTypeEnum } = require('../helpers/enums'); +const { currentRERequest } = require("../helpers/url"); +const { getRegionName, getMunicipalityName } = require("../helpers/codes"); +const { + realEstateTypes, + sizes, + gardenSizes, + prices, + getEnumTypeTitle, + getRealEstateTypeEnum +} = require("../helpers/enums"); -const getQueryReview = async (req,res) => { - - const title = "Da li je ovo to što ste tražili ?" +const getQueryReview = async (req, res) => { + const title = "Da li je ovo to što ste tražili ?"; const request = await currentRERequest(req); const nextStep = req.query.nextStep; @@ -12,63 +18,73 @@ const getQueryReview = async (req,res) => { return null; } - const { - realEstateType, - region, - municipality, - sizeMin, - sizeMax, - gardenSizeMin, - gardenSizeMax, - priceMin, - priceMax } = request.dataValues; + const { + realEstateType, + region, + municipality, + sizeMin, + sizeMax, + gardenSizeMin, + gardenSizeMax, + priceMin, + priceMax + } = request.dataValues; 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 municipalityName = (region && municipality) ? getMunicipalityName(region, municipality) : null; + const municipalityName = + region && municipality ? getMunicipalityName(region, municipality) : null; const sizeTitle = sizeMin ? sizeMin + "-" + sizeMax + " m2" : null; - const gardenSizeTitle = gardenSizeMin ? gardenSizeMin + "-" + gardenSizeMax + " m2" : null; - const priceTitle = priceMin ? priceMin + "-" + priceMax + " KM" : null; + const gardenSizeTitle = gardenSizeMin + ? 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 = [ { - id: 'realEstateType', + id: "realEstateType", title: realEstateTypeTitle, - url: `/vrstanekretnine/${uniqueId}?nextStep=pregled`, + url: `/vrstanekretnine/${uniqueId}?nextStep=pregled` }, { - id: 'region', + id: "region", title: regionName, - url: `/grad/${uniqueId}?nextStep=mjesto`, + url: `/grad/${uniqueId}?nextStep=mjesto` }, { - id: 'municipality', + id: "municipality", title: municipalityName, - url: `/mjesto/${uniqueId}?nextStep=pregled`, + url: `/mjesto/${uniqueId}?nextStep=pregled` }, { - id: 'size', + id: "size", title: sizeTitle, - url: `/povrsina/${uniqueId}?nextStep=pregled`, + url: `/povrsina/${uniqueId}?nextStep=pregled` }, { - id: 'gardenSize', + id: "gardenSize", title: gardenSizeTitle, - url: enableGardenSizeEdit ? `/okucnica/${uniqueId}?nextStep=pregled` : '', + url: enableGardenSizeEdit ? `/okucnica/${uniqueId}?nextStep=pregled` : "" }, { - id: 'price', + id: "price", title: priceTitle, url: `/cijena/${uniqueId}?nextStep=pregled` } ]; - res.render('queryReview', { + res.render("queryReview", { nextStep, queryData, title diff --git a/app/controllers/querySubmit.js b/app/controllers/querySubmit.js index 5d111d8..de48eba 100644 --- a/app/controllers/querySubmit.js +++ b/app/controllers/querySubmit.js @@ -1,14 +1,13 @@ -const { currentRERequest } = require('../helpers/url'); -const { isValidEmail } = require('../helpers/email'); -const { sendTemplatedEmail} = require('../helpers/awsEmail'); +const { currentRERequest } = require("../helpers/url"); +const { isValidEmail } = require("../helpers/email"); +const { sendTemplatedEmail } = require("../helpers/awsEmail"); 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 error = req.query.error; - res.render('querySubmit', { + res.render("querySubmit", { nextStep, error, title @@ -17,25 +16,23 @@ const getQuerySubmit = async (req, res) => { const postQuerySubmit = async (req, res) => { const request = await currentRERequest(req); - const nextStep = req.query.nextStep || '/ponovo'; + const nextStep = req.query.nextStep || "/ponovo"; const emailInput = req.body.email; const emailConfirmInput = req.body.confirm; let error = "Greška ! Unesite validan email"; if (!isValidEmail(emailInput) || !isValidEmail(emailConfirmInput)) { - error = "Greška ! Unesite validan email"; - res.render('querySubmit', { + res.render("querySubmit", { error }); return; } if (emailInput !== emailConfirmInput) { - error = "Greška ! Unešeni emailovi nisu isti"; - res.render('querySubmit', { + res.render("querySubmit", { error }); return; @@ -45,7 +42,7 @@ const postQuerySubmit = async (req, res) => { request.subscribed = true; await request.save(); sendTemplatedEmail(req.body.email, request); - res.redirect(nextStep); + res.redirect(nextStep); }; module.exports = { diff --git a/app/controllers/realEstateTypes.js b/app/controllers/realEstateTypes.js index 50b1aad..afefa0f 100644 --- a/app/controllers/realEstateTypes.js +++ b/app/controllers/realEstateTypes.js @@ -1,42 +1,39 @@ -const db = require('../models/index'); +const db = require("../models/index"); -const { currentRERequest } = require('../helpers/url'); -const { realEstateTypes, getRealEstateTypeEnum } = require('../helpers/enums'); +const { currentRERequest } = require("../helpers/url"); +const { realEstateTypes, getRealEstateTypeEnum } = require("../helpers/enums"); - -const getRealEstateTypes = (req,res) => { - const title = "Koju nekretninu tražite?" - res.render('realEstateType', { realEstateTypes, title }); +const getRealEstateTypes = (req, res) => { + const title = "Koju nekretninu tražite?"; + res.render("realEstateType", { realEstateTypes, title }); }; const postRealEstateTypes = async (req, res) => { const request = await currentRERequest(req); - const nextStepPage = req.query.nextStep || 'grad'; + const nextStepPage = req.query.nextStep || "grad"; if (request && request.uniqueId) { const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`; request.realEstateType = req.body.realestatetype; - if (!getRealEstateTypeEnum(request.realEstateType).hasGardenSize){ + if (!getRealEstateTypeEnum(request.realEstateType).hasGardenSize) { request.gardenSize = null; } await request.save(); - res.redirect(nextStepUrl) + res.redirect(nextStepUrl); } else { db.RealEstateRequest.create({ realEstateType: req.body.realestatetype - }).then( (result) => { - const nextStepUrl = `/${nextStepPage}/${result.uniqueId}`; - res.redirect(nextStepUrl); - }).catch( (e) => { - res.send(e); - }); + }) + .then(result => { + const nextStepUrl = `/${nextStepPage}/${result.uniqueId}`; + res.redirect(nextStepUrl); + }) + .catch(e => { + res.send(e); + }); } - - - - }; module.exports = { diff --git a/app/controllers/realEstates.js b/app/controllers/realEstates.js index ddb5e40..1533159 100644 --- a/app/controllers/realEstates.js +++ b/app/controllers/realEstates.js @@ -1,18 +1,16 @@ +const { allMarketAlertsByRequest } = require("../helpers/db/dbHelper"); -const {allMarketAlertsByRequest} = require('../helpers/db/dbHelper'); +const getRealEstates = async (req, res) => { + console.log("Enter get realestates"); + const request = req.params["request_id"]; + console.log(req.params["request_id"]); + const realEstates = await allMarketAlertsByRequest(request); + console.log(realEstates); -const getRealEstates = async (req,res) => { - console.log("Enter get realestates"); - 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"; + res.render("realEstates", { realEstates, title }); +}; - const title = "Ovo su nekretnine koje smo pronašli za vas" - res.render('realEstates', {realEstates, title } ); - }; - - module.exports = { - getRealEstates - }; - \ No newline at end of file +module.exports = { + getRealEstates +}; diff --git a/app/controllers/regions.js b/app/controllers/regions.js index b3f0b71..025c539 100644 --- a/app/controllers/regions.js +++ b/app/controllers/regions.js @@ -1,25 +1,25 @@ -const { currentRERequest } = require('../helpers/url'); -const { getRegions } = require('../helpers/codes'); +const { currentRERequest } = require("../helpers/url"); +const { getRegions } = require("../helpers/codes"); const regions = getRegions(); -const getRegion = (req,res) => { - const title = "U kojoj regiji tražite nekretninu?" - res.render('region', { regions, title }); +const getRegion = (req, res) => { + const title = "U kojoj regiji tražite nekretninu?"; + res.render("region", { regions, title }); }; const postRegion = async (req, res) => { const request = await currentRERequest(req); - const nextStepQueryParam = req.query.nextStep ? '?nextStep=pregled' : ''; - const nextStepPage = req.query.nextStep || 'mjesto'; + const nextStepQueryParam = req.query.nextStep ? "?nextStep=pregled" : ""; + const nextStepPage = req.query.nextStep || "mjesto"; const nextStepUrl = `/${nextStepPage}/${request.uniqueId}${nextStepQueryParam}`; request.region = req.body.region; request.municipality = null; await request.save(); - res.redirect(nextStepUrl) + res.redirect(nextStepUrl); }; module.exports = { diff --git a/app/controllers/sizes.js b/app/controllers/sizes.js index 58ec4a7..b3898c4 100644 --- a/app/controllers/sizes.js +++ b/app/controllers/sizes.js @@ -1,25 +1,24 @@ -const { currentRERequest } = require('../helpers/url'); -const { sizes, getRealEstateTypeEnum } = require('../helpers/enums'); +const { currentRERequest } = require("../helpers/url"); +const { sizes, getRealEstateTypeEnum } = require("../helpers/enums"); -const getSize = (req,res) => { - - const title = "Od koliko kvadrata tražite nekretninu ?" - const unit = " m2" +const getSize = (req, res) => { + const title = "Od koliko kvadrata tražite nekretninu ?"; + const unit = " m2"; const rangeFrom = { - min : 10, - max : 250, - value : 0, - step : 10 - } + min: 10, + max: 250, + value: 0, + step: 10 + }; const rangeTo = { - min : 10, - max : 250, - value : 50, - step : 10 - } + min: 10, + max: 250, + value: 50, + step: 10 + }; - res.render('size', { rangeFrom, rangeTo, unit, title }); + res.render("size", { rangeFrom, rangeTo, unit, title }); }; const postSize = async (req, res) => { @@ -27,7 +26,8 @@ const postSize = async (req, res) => { 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 nextStepUrl = `/${nextStepPage}/${request.uniqueId}`; request.sizeMin = req.body.from; diff --git a/app/controllers/unsubscribe.js b/app/controllers/unsubscribe.js index 5e32ddb..0199fa7 100644 --- a/app/controllers/unsubscribe.js +++ b/app/controllers/unsubscribe.js @@ -1,17 +1,14 @@ - -const { currentRERequest } = require('../helpers/url'); +const { currentRERequest } = require("../helpers/url"); 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" - const request = await currentRERequest(req); - request.subscribed = false; - await request.save(); - - res.render('unsubscribe', { nextStep: '/vrstanekretnine', title }); + res.render("unsubscribe", { nextStep: "/vrstanekretnine", title }); }; - module.exports = { - getUnsubscribe -}; \ No newline at end of file + getUnsubscribe +}; diff --git a/app/controllers/welcome.js b/app/controllers/welcome.js index 258b551..fe62105 100644 --- a/app/controllers/welcome.js +++ b/app/controllers/welcome.js @@ -1,6 +1,6 @@ -const getWelcome = (req,res) => { - const title = "Koju nekretninu tražite?" - res.render('welcome', { nextStep: '/vrstanekretnine', title } ); +const getWelcome = (req, res) => { + const title = "Koju nekretninu tražite?"; + res.render("welcome", { nextStep: "/vrstanekretnine", title }); }; module.exports = { diff --git a/app/helpers/awsEmail.js b/app/helpers/awsEmail.js index dac4f48..9ca4bcb 100644 --- a/app/helpers/awsEmail.js +++ b/app/helpers/awsEmail.js @@ -57,9 +57,7 @@ const getGreetingsEmailHTML = realestateRequest => { realestateRequest.realEstateType ); const gardenSize = realEstateType.hasGardenSize - ? `
Kvadratura okućnice: Od ${ - realestateRequest.gardenSizeMin - } do ${realestateRequest.gardenSizeMax} m2
` + ? `
Kvadratura okućnice: Od ${realestateRequest.gardenSizeMin} do ${realestateRequest.gardenSizeMax} m2
` : ``; return `

Zdravo, diff --git a/app/helpers/codes.js b/app/helpers/codes.js index bcec456..815c4d6 100644 --- a/app/helpers/codes.js +++ b/app/helpers/codes.js @@ -1,928 +1,931 @@ const regions = [ - { - "name": " Sarajevo", - "id": "sarajevo", - "olxid": "9", - "municipalities": [ - { - "name": "Hadžići", - "id": "hadii", - "olxid": "3817" - }, - { - "name": "Ilidža", - "id": "ilida", - "olxid": "3879" - }, - { - "name": "Ilijaš", - "id": "ilija", - "olxid": "3892" - }, - { - "name": "Sarajevo - Centar", - "id": "sarajevocentar", - "olxid": "3812" - }, - { - "name": "Sarajevo-Novi Grad", - "id": "sarajevonovigrad", - "olxid": "3969" - }, - { - "name": "Sarajevo-Novo Sarajevo", - "id": "sarajevonovosarajevo", - "olxid": "5896" - }, - { - "name": "Sarajevo-Stari Grad", - "id": "sarajevostarigrad", - "olxid": "4048" - }, - { - "name": "Trnovo", - "id": "trnovo", - "olxid": "4063" - }, - { - "name": "Vogošća", - "id": "vogoa", - "olxid": "4126" - } - ] - }, - { - "name": " Unsko-sanski", - "id": "unskosanski", - "olxid": "9", - "municipalities": [ - { - "name": "Bihać", - "id": "biha", - "olxid": "75" - }, - { - "name": "Bosanska Krupa", - "id": "bosanskakrupa", - "olxid": "373" - }, - { - "name": "Bosanski Petrovac", - "id": "bosanskipetrovac", - "olxid": "504" - }, - { - "name": "Bužim", - "id": "buim", - "olxid": "374" - }, - { - "name": "Cazin", - "id": "cazin", - "olxid": "857" - }, - { - "name": "Ključ", - "id": "klju", - "olxid": "2362" - }, - { - "name": "Sanski Most", - "id": "sanskimost", - "olxid": "3738" - }, - { - "name": "Velika Kladuša", - "id": "velikakladua", - "olxid": "5122" - } - ] - }, - { - "name": " Posavski", - "id": "posavski", - "olxid": "15", - "municipalities": [ - { - "name": "Domaljevac", - "id": "domaljevac", - "olxid": "6144" - }, - { - "name": "Odžak", - "id": "odak", - "olxid": "424" - }, - { - "name": "Orašje", - "id": "oraje", - "olxid": "3252" - }, - { - "name": "Šamac", - "id": "amac", - "olxid": "540" - } - ] - }, - { - "name": " Tuzlanski", - "id": "tuzlanski", - "olxid": "15", - "municipalities": [ - { - "name": "Banovići", - "id": "banovii", - "olxid": "2" - }, - { - "name": "Doboj-Istok", - "id": "dobojistok", - "olxid": "1090" - }, - { - "name": "Gradačac", - "id": "gradaac", - "olxid": "1854" - }, - { - "name": "Gračanica", - "id": "graanica", - "olxid": "1826" - }, - { - "name": "Kalesija", - "id": "kalesija", - "olxid": "2129" - }, - { - "name": "Kladanj", - "id": "kladanj", - "olxid": "2319" - }, - { - "name": "Lukavac", - "id": "lukavac", - "olxid": "2840" - }, - { - "name": "Sapna", - "id": "sapna", - "olxid": "5699" - }, - { - "name": "Srebrenik", - "id": "srebrenik", - "olxid": "4391" - }, - { - "name": "Teočak", - "id": "teoak", - "olxid": "5010" - }, - { - "name": "Tuzla", - "id": "tuzla", - "olxid": "4944" - }, - { - "name": "Čelić", - "id": "eli", - "olxid": "2801" - }, - { - "name": "Živinice", - "id": "ivinice", - "olxid": "5774" - } - ] - }, - { - "name": " Zeničko-dobojski", - "id": "zenickodobojski", - "olxid": "15", - "municipalities": [ - { - "name": "Breza", - "id": "breza", - "olxid": "704" - }, - { - "name": "Doboj-Jug", - "id": "dobojjug", - "olxid": "1122" - }, - { - "name": "Kakanj", - "id": "kakanj", - "olxid": "2022" - }, - { - "name": "Maglaj", - "id": "maglaj", - "olxid": "2941" - }, - { - "name": "Olovo", - "id": "olovo", - "olxid": "1925" - }, - { - "name": "Tešanj", - "id": "teanj", - "olxid": "4594" - }, - { - "name": "Usora", - "id": "usora", - "olxid": "1087" - }, - { - "name": "Vareš", - "id": "vare", - "olxid": "5037" - }, - { - "name": "Visoko", - "id": "visoko", - "olxid": "5171" - }, - { - "name": "Zavidovići", - "id": "zavidovii", - "olxid": "5548" - }, - { - "name": "Zenica", - "id": "zenica", - "olxid": "4571" - }, - { - "name": "Žepče", - "id": "epe", - "olxid": "2940" - } - ] - }, - { - "name": " Bosansko-podrinjski", - "id": "bosanskopodrinjski", - "olxid": "15", - "municipalities": [ - { - "name": "Foča", - "id": "foa", - "olxid": "1289" - }, - { - "name": "Goražde", - "id": "gorade", - "olxid": "1588" - }, - { - "name": "Pale", - "id": "pale", - "olxid": "3546" - } - ] - }, - { - "name": " Srednjobosanski", - "id": "srednjobosanski", - "olxid": "6", - "municipalities": [ - { - "name": "Bugojno", - "id": "bugojno", - "olxid": "732" - }, - { - "name": "Busovača", - "id": "busovaa", - "olxid": "810" - }, - { - "name": "Dobretići", - "id": "dobretii", - "olxid": "4151" - }, - { - "name": "Donji Vakuf", - "id": "donjivakuf", - "olxid": "1160" - }, - { - "name": "Fojnica", - "id": "fojnica", - "olxid": "1407" - }, - { - "name": "Gornji Vakuf - Uskoplje", - "id": "gornjivakufuskoplje", - "olxid": "1775" - }, - { - "name": "Jajce", - "id": "jajce", - "olxid": "1960" - }, - { - "name": "Kiseljak", - "id": "kiseljak", - "olxid": "2237" - }, - { - "name": "Kreševo", - "id": "kreevo", - "olxid": "2608" - }, - { - "name": "Novi Travnik", - "id": "novitravnik", - "olxid": "3477" - }, - { - "name": "Travnik", - "id": "travnik", - "olxid": "4678" - }, - { - "name": "Vitez", - "id": "vitez", - "olxid": "5422" - } - ] - }, - { - "name": " Hercegovačko-neretvanski", - "id": "hercegovackoneretvanski", - "olxid": "7", - "municipalities": [ - { - "name": "Grad Mostar", - "id": "gradmostar", - "olxid": "3017" - }, - { - "name": "Jablanica", - "id": "jablanica", - "olxid": "1930" - }, - { - "name": "Konjic", - "id": "konjic", - "olxid": "2169" - }, - { - "name": "Neum", - "id": "neum", - "olxid": "3111" - }, - { - "name": "Prozor", - "id": "prozor", - "olxid": "3421" - }, - { - "name": "Ravno", - "id": "ravno", - "olxid": "4769" - }, - { - "name": "Stolac", - "id": "stolac", - "olxid": "4439" - }, - { - "name": "Čapljina", - "id": "apljina", - "olxid": "947" - }, - { - "name": "Čitluk", - "id": "itluk", - "olxid": "1009" - } - ] - }, - { - "name": " Zapadno-hercegovački", - "id": "zapadnohercegovacki", - "olxid": "8", - "municipalities": [ - { - "name": "Grude", - "id": "grude", - "olxid": "1892" - }, - { - "name": "Ljubuški", - "id": "ljubuki", - "olxid": "2905" - }, - { - "name": "Posušje", - "id": "posuje", - "olxid": "3268" - }, - { - "name": "Široki Brijeg", - "id": "irokibrijeg", - "olxid": "2708" - } - ] - }, - { - "name": " Livanjski", - "id": "livanjski", - "olxid": "10", - "municipalities": [ - { - "name": "Bosansko Grahovo", - "id": "bosanskograhovo", - "olxid": "560" - }, - { - "name": "Drvar", - "id": "drvar", - "olxid": "4640" - }, - { - "name": "Glamoč", - "id": "glamo", - "olxid": "1533" - }, - { - "name": "Kupres", - "id": "kupres", - "olxid": "2635" - }, - { - "name": "Livno", - "id": "livno", - "olxid": "2741" - }, - { - "name": "Tomislavgrad", - "id": "tomislavgrad", - "olxid": "1228" - } - ] - }, - { - "name": " Banjalučka", - "id": "banjalučka", - "olxid": "14", - "municipalities": [ - { - "name": "Banja Luka", - "id": "banjaluka", - "olxid": "21" - }, - { - "name": "Gradiška", - "id": "gradika", - "olxid": "305" - }, - { - "name": "Istočni Drvar", - "id": "istonidrvar", - "olxid": "4662" - }, - { - "name": "Jezero", - "id": "jezero", - "olxid": "1965" - }, - { - "name": "Kneževo", - "id": "kneevo", - "olxid": "4147" - }, - { - "name": "Kostajnica", - "id": "kostajnica", - "olxid": "6142" - }, - { - "name": "Kotor Varoš", - "id": "kotorvaro", - "olxid": "2574" - }, - { - "name": "Kozarska Dubica", - "id": "kozarskadubica", - "olxid": "244" - }, - { - "name": "Krupa na uni", - "id": "krupanauni", - "olxid": "382" - }, - { - "name": "Kupres ", - "id": "kupres", - "olxid": "2654" - }, - { - "name": "Laktaši", - "id": "laktai", - "olxid": "2671" - }, - { - "name": "Mrkonjić Grad", - "id": "mrkonjigrad", - "olxid": "3073" - }, - { - "name": "Novi Grad", - "id": "novigrad", - "olxid": "444" - }, - { - "name": "Oštra Luka", - "id": "otraluka", - "olxid": "3737" - }, - { - "name": "Petrovac", - "id": "petrovac", - "olxid": "515" - }, - { - "name": "Prijedor", - "id": "prijedor", - "olxid": "3287" - }, - { - "name": "Prnjavor", - "id": "prnjavor", - "olxid": "3358" - }, - { - "name": "Ribnik", - "id": "ribnik", - "olxid": "2365" - }, - { - "name": "Srbac", - "id": "srbac", - "olxid": "4271" - }, - { - "name": "Čelinac", - "id": "elinac", - "olxid": "979" - }, - { - "name": "Šipovo", - "id": "ipovo", - "olxid": "4509" - } - ] - }, - { - "name": " Dobojsko-Bijeljinska", - "id": "dobojskobijeljinska", - "olxid": "15", - "municipalities": [ - { - "name": "Bijeljina", - "id": "bijeljina", - "olxid": "123" - }, - { - "name": "Bosanski Brod", - "id": "bosanskibrod", - "olxid": "421" - }, - { - "name": "Derventa", - "id": "derventa", - "olxid": "1030" - }, - { - "name": "Doboj", - "id": "doboj", - "olxid": "1088" - }, - { - "name": "Donji Žabar", - "id": "donjiabar", - "olxid": "3254" - }, - { - "name": "Lopare", - "id": "lopare", - "olxid": "2800" - }, - { - "name": "Lukavac", - "id": "lukavac", - "olxid": "6029" - }, - { - "name": "Modriča", - "id": "modria", - "olxid": "2996" - }, - { - "name": "Pelagićevo", - "id": "pelagievo", - "olxid": "1856" - }, - { - "name": "Petrovo", - "id": "petrovo", - "olxid": "1827" - }, - { - "name": "Stanari", - "id": "stanari", - "olxid": "1148" - }, - { - "name": "Teslić", - "id": "tesli", - "olxid": "4549" - }, - { - "name": "Tešanj", - "id": "teanj", - "olxid": "4636" - }, - { - "name": "Travnik", - "id": "travnik", - "olxid": "4692" - }, - { - "name": "Tuzla", - "id": "tuzla", - "olxid": "4966" - }, - { - "name": "Ugljevik", - "id": "ugljevik", - "olxid": "5009" - }, - { - "name": "Vukosavlje", - "id": "vukosavlje", - "olxid": "3197" - }, - { - "name": "Šamac", - "id": "amac", - "olxid": "539" - } - ] - }, - { - "name": " Sarajevsko-Zvornička", - "id": "sarajevskozvornicka", - "olxid": "16", - "municipalities": [ - { - "name": "Bratunac", - "id": "bratunac", - "olxid": "595" - }, - { - "name": "Han Pijesak", - "id": "hanpijesak", - "olxid": "1904" - }, - { - "name": "Ilijaš", - "id": "ilija", - "olxid": "3947" - }, - { - "name": "Istočni Stari Grad", - "id": "istonistarigrad", - "olxid": "4049" - }, - { - "name": "Kasindo", - "id": "kasindo", - "olxid": "3880" - }, - { - "name": "Kladanj", - "id": "kladanj", - "olxid": "2325" - }, - { - "name": "Lukavica", - "id": "lukavica", - "olxid": "3971" - }, - { - "name": "Milići", - "id": "milii", - "olxid": "6143" - }, - { - "name": "Olovo", - "id": "olovo", - "olxid": "3221" - }, - { - "name": "Osmaci", - "id": "osmaci", - "olxid": "2128" - }, - { - "name": "Pale", - "id": "pale", - "olxid": "3978" - }, - { - "name": "Rogatica", - "id": "rogatica", - "olxid": "3529" - }, - { - "name": "Rudo", - "id": "rudo", - "olxid": "3648" - }, - { - "name": "Sarajevo-Novi Grad", - "id": "sarajevonovigrad", - "olxid": "6069" - }, - { - "name": "Sokolac", - "id": "sokolac", - "olxid": "4183" - }, - { - "name": "Srebrenica", - "id": "srebrenica", - "olxid": "4310" - }, - { - "name": "Trnovo", - "id": "trnovo", - "olxid": "4067" - }, - { - "name": "Ustiprača", - "id": "ustipraa", - "olxid": "1593" - }, - { - "name": "Višegrad", - "id": "viegrad", - "olxid": "5259" - }, - { - "name": "Vlasenica", - "id": "vlasenica", - "olxid": "5456" - }, - { - "name": "Zvornik", - "id": "zvornik", - "olxid": "5684" - }, - { - "name": "Šekovići", - "id": "ekovii", - "olxid": "4475" - }, - { - "name": "Žepa", - "id": "epa", - "olxid": "1906" - } - ] - }, - { - "name": " Trebinjsko-Fočanska", - "id": "trebinjskofocanska", - "olxid": "17", - "municipalities": [ - { - "name": "Berkovići", - "id": "berkovii", - "olxid": "4441" - }, - { - "name": "Bileća", - "id": "bilea", - "olxid": "183" - }, - { - "name": "Foča", - "id": "foa", - "olxid": "1287" - }, - { - "name": "Gacko", - "id": "gacko", - "olxid": "1462" - }, - { - "name": "Istočni Mostar", - "id": "istonimostar", - "olxid": "3038" - }, - { - "name": "Kalinovik", - "id": "kalinovik", - "olxid": "2164" - }, - { - "name": "Ljubinje", - "id": "ljubinje", - "olxid": "2884" - }, - { - "name": "Nevesinje", - "id": "nevesinje", - "olxid": "3138" - }, - { - "name": "Trebinje", - "id": "trebinje", - "olxid": "4766" - }, - { - "name": "Čajniče", - "id": "ajnie", - "olxid": "911" - } - ] - }, - { - "name": "Distrikt Brčko", - "id": "distriktbrcko", - "olxid": "12", - "municipalities": [ - { - "name": "Brčko", - "id": "brko", - "olxid": "12" - } - - ] - } + { + name: " Sarajevo", + id: "sarajevo", + olxid: "9", + municipalities: [ + { + name: "Hadžići", + id: "hadii", + olxid: "3817" + }, + { + name: "Ilidža", + id: "ilida", + olxid: "3879" + }, + { + name: "Ilijaš", + id: "ilija", + olxid: "3892" + }, + { + name: "Sarajevo - Centar", + id: "sarajevocentar", + olxid: "3812" + }, + { + name: "Sarajevo-Novi Grad", + id: "sarajevonovigrad", + olxid: "3969" + }, + { + name: "Sarajevo-Novo Sarajevo", + id: "sarajevonovosarajevo", + olxid: "5896" + }, + { + name: "Sarajevo-Stari Grad", + id: "sarajevostarigrad", + olxid: "4048" + }, + { + name: "Trnovo", + id: "trnovo", + olxid: "4063" + }, + { + name: "Vogošća", + id: "vogoa", + olxid: "4126" + } + ] + }, + { + name: " Unsko-sanski", + id: "unskosanski", + olxid: "9", + municipalities: [ + { + name: "Bihać", + id: "biha", + olxid: "75" + }, + { + name: "Bosanska Krupa", + id: "bosanskakrupa", + olxid: "373" + }, + { + name: "Bosanski Petrovac", + id: "bosanskipetrovac", + olxid: "504" + }, + { + name: "Bužim", + id: "buim", + olxid: "374" + }, + { + name: "Cazin", + id: "cazin", + olxid: "857" + }, + { + name: "Ključ", + id: "klju", + olxid: "2362" + }, + { + name: "Sanski Most", + id: "sanskimost", + olxid: "3738" + }, + { + name: "Velika Kladuša", + id: "velikakladua", + olxid: "5122" + } + ] + }, + { + name: " Posavski", + id: "posavski", + olxid: "15", + municipalities: [ + { + name: "Domaljevac", + id: "domaljevac", + olxid: "6144" + }, + { + name: "Odžak", + id: "odak", + olxid: "424" + }, + { + name: "Orašje", + id: "oraje", + olxid: "3252" + }, + { + name: "Šamac", + id: "amac", + olxid: "540" + } + ] + }, + { + name: " Tuzlanski", + id: "tuzlanski", + olxid: "15", + municipalities: [ + { + name: "Banovići", + id: "banovii", + olxid: "2" + }, + { + name: "Doboj-Istok", + id: "dobojistok", + olxid: "1090" + }, + { + name: "Gradačac", + id: "gradaac", + olxid: "1854" + }, + { + name: "Gračanica", + id: "graanica", + olxid: "1826" + }, + { + name: "Kalesija", + id: "kalesija", + olxid: "2129" + }, + { + name: "Kladanj", + id: "kladanj", + olxid: "2319" + }, + { + name: "Lukavac", + id: "lukavac", + olxid: "2840" + }, + { + name: "Sapna", + id: "sapna", + olxid: "5699" + }, + { + name: "Srebrenik", + id: "srebrenik", + olxid: "4391" + }, + { + name: "Teočak", + id: "teoak", + olxid: "5010" + }, + { + name: "Tuzla", + id: "tuzla", + olxid: "4944" + }, + { + name: "Čelić", + id: "eli", + olxid: "2801" + }, + { + name: "Živinice", + id: "ivinice", + olxid: "5774" + } + ] + }, + { + name: " Zeničko-dobojski", + id: "zenickodobojski", + olxid: "15", + municipalities: [ + { + name: "Breza", + id: "breza", + olxid: "704" + }, + { + name: "Doboj-Jug", + id: "dobojjug", + olxid: "1122" + }, + { + name: "Kakanj", + id: "kakanj", + olxid: "2022" + }, + { + name: "Maglaj", + id: "maglaj", + olxid: "2941" + }, + { + name: "Olovo", + id: "olovo", + olxid: "1925" + }, + { + name: "Tešanj", + id: "teanj", + olxid: "4594" + }, + { + name: "Usora", + id: "usora", + olxid: "1087" + }, + { + name: "Vareš", + id: "vare", + olxid: "5037" + }, + { + name: "Visoko", + id: "visoko", + olxid: "5171" + }, + { + name: "Zavidovići", + id: "zavidovii", + olxid: "5548" + }, + { + name: "Zenica", + id: "zenica", + olxid: "4571" + }, + { + name: "Žepče", + id: "epe", + olxid: "2940" + } + ] + }, + { + name: " Bosansko-podrinjski", + id: "bosanskopodrinjski", + olxid: "15", + municipalities: [ + { + name: "Foča", + id: "foa", + olxid: "1289" + }, + { + name: "Goražde", + id: "gorade", + olxid: "1588" + }, + { + name: "Pale", + id: "pale", + olxid: "3546" + } + ] + }, + { + name: " Srednjobosanski", + id: "srednjobosanski", + olxid: "6", + municipalities: [ + { + name: "Bugojno", + id: "bugojno", + olxid: "732" + }, + { + name: "Busovača", + id: "busovaa", + olxid: "810" + }, + { + name: "Dobretići", + id: "dobretii", + olxid: "4151" + }, + { + name: "Donji Vakuf", + id: "donjivakuf", + olxid: "1160" + }, + { + name: "Fojnica", + id: "fojnica", + olxid: "1407" + }, + { + name: "Gornji Vakuf - Uskoplje", + id: "gornjivakufuskoplje", + olxid: "1775" + }, + { + name: "Jajce", + id: "jajce", + olxid: "1960" + }, + { + name: "Kiseljak", + id: "kiseljak", + olxid: "2237" + }, + { + name: "Kreševo", + id: "kreevo", + olxid: "2608" + }, + { + name: "Novi Travnik", + id: "novitravnik", + olxid: "3477" + }, + { + name: "Travnik", + id: "travnik", + olxid: "4678" + }, + { + name: "Vitez", + id: "vitez", + olxid: "5422" + } + ] + }, + { + name: " Hercegovačko-neretvanski", + id: "hercegovackoneretvanski", + olxid: "7", + municipalities: [ + { + name: "Grad Mostar", + id: "gradmostar", + olxid: "3017" + }, + { + name: "Jablanica", + id: "jablanica", + olxid: "1930" + }, + { + name: "Konjic", + id: "konjic", + olxid: "2169" + }, + { + name: "Neum", + id: "neum", + olxid: "3111" + }, + { + name: "Prozor", + id: "prozor", + olxid: "3421" + }, + { + name: "Ravno", + id: "ravno", + olxid: "4769" + }, + { + name: "Stolac", + id: "stolac", + olxid: "4439" + }, + { + name: "Čapljina", + id: "apljina", + olxid: "947" + }, + { + name: "Čitluk", + id: "itluk", + olxid: "1009" + } + ] + }, + { + name: " Zapadno-hercegovački", + id: "zapadnohercegovacki", + olxid: "8", + municipalities: [ + { + name: "Grude", + id: "grude", + olxid: "1892" + }, + { + name: "Ljubuški", + id: "ljubuki", + olxid: "2905" + }, + { + name: "Posušje", + id: "posuje", + olxid: "3268" + }, + { + name: "Široki Brijeg", + id: "irokibrijeg", + olxid: "2708" + } + ] + }, + { + name: " Livanjski", + id: "livanjski", + olxid: "10", + municipalities: [ + { + name: "Bosansko Grahovo", + id: "bosanskograhovo", + olxid: "560" + }, + { + name: "Drvar", + id: "drvar", + olxid: "4640" + }, + { + name: "Glamoč", + id: "glamo", + olxid: "1533" + }, + { + name: "Kupres", + id: "kupres", + olxid: "2635" + }, + { + name: "Livno", + id: "livno", + olxid: "2741" + }, + { + name: "Tomislavgrad", + id: "tomislavgrad", + olxid: "1228" + } + ] + }, + { + name: " Banjalučka", + id: "banjalučka", + olxid: "14", + municipalities: [ + { + name: "Banja Luka", + id: "banjaluka", + olxid: "21" + }, + { + name: "Gradiška", + id: "gradika", + olxid: "305" + }, + { + name: "Istočni Drvar", + id: "istonidrvar", + olxid: "4662" + }, + { + name: "Jezero", + id: "jezero", + olxid: "1965" + }, + { + name: "Kneževo", + id: "kneevo", + olxid: "4147" + }, + { + name: "Kostajnica", + id: "kostajnica", + olxid: "6142" + }, + { + name: "Kotor Varoš", + id: "kotorvaro", + olxid: "2574" + }, + { + name: "Kozarska Dubica", + id: "kozarskadubica", + olxid: "244" + }, + { + name: "Krupa na uni", + id: "krupanauni", + olxid: "382" + }, + { + name: "Kupres ", + id: "kupres", + olxid: "2654" + }, + { + name: "Laktaši", + id: "laktai", + olxid: "2671" + }, + { + name: "Mrkonjić Grad", + id: "mrkonjigrad", + olxid: "3073" + }, + { + name: "Novi Grad", + id: "novigrad", + olxid: "444" + }, + { + name: "Oštra Luka", + id: "otraluka", + olxid: "3737" + }, + { + name: "Petrovac", + id: "petrovac", + olxid: "515" + }, + { + name: "Prijedor", + id: "prijedor", + olxid: "3287" + }, + { + name: "Prnjavor", + id: "prnjavor", + olxid: "3358" + }, + { + name: "Ribnik", + id: "ribnik", + olxid: "2365" + }, + { + name: "Srbac", + id: "srbac", + olxid: "4271" + }, + { + name: "Čelinac", + id: "elinac", + olxid: "979" + }, + { + name: "Šipovo", + id: "ipovo", + olxid: "4509" + } + ] + }, + { + name: " Dobojsko-Bijeljinska", + id: "dobojskobijeljinska", + olxid: "15", + municipalities: [ + { + name: "Bijeljina", + id: "bijeljina", + olxid: "123" + }, + { + name: "Bosanski Brod", + id: "bosanskibrod", + olxid: "421" + }, + { + name: "Derventa", + id: "derventa", + olxid: "1030" + }, + { + name: "Doboj", + id: "doboj", + olxid: "1088" + }, + { + name: "Donji Žabar", + id: "donjiabar", + olxid: "3254" + }, + { + name: "Lopare", + id: "lopare", + olxid: "2800" + }, + { + name: "Lukavac", + id: "lukavac", + olxid: "6029" + }, + { + name: "Modriča", + id: "modria", + olxid: "2996" + }, + { + name: "Pelagićevo", + id: "pelagievo", + olxid: "1856" + }, + { + name: "Petrovo", + id: "petrovo", + olxid: "1827" + }, + { + name: "Stanari", + id: "stanari", + olxid: "1148" + }, + { + name: "Teslić", + id: "tesli", + olxid: "4549" + }, + { + name: "Tešanj", + id: "teanj", + olxid: "4636" + }, + { + name: "Travnik", + id: "travnik", + olxid: "4692" + }, + { + name: "Tuzla", + id: "tuzla", + olxid: "4966" + }, + { + name: "Ugljevik", + id: "ugljevik", + olxid: "5009" + }, + { + name: "Vukosavlje", + id: "vukosavlje", + olxid: "3197" + }, + { + name: "Šamac", + id: "amac", + olxid: "539" + } + ] + }, + { + name: " Sarajevsko-Zvornička", + id: "sarajevskozvornicka", + olxid: "16", + municipalities: [ + { + name: "Bratunac", + id: "bratunac", + olxid: "595" + }, + { + name: "Han Pijesak", + id: "hanpijesak", + olxid: "1904" + }, + { + name: "Ilijaš", + id: "ilija", + olxid: "3947" + }, + { + name: "Istočni Stari Grad", + id: "istonistarigrad", + olxid: "4049" + }, + { + name: "Kasindo", + id: "kasindo", + olxid: "3880" + }, + { + name: "Kladanj", + id: "kladanj", + olxid: "2325" + }, + { + name: "Lukavica", + id: "lukavica", + olxid: "3971" + }, + { + name: "Milići", + id: "milii", + olxid: "6143" + }, + { + name: "Olovo", + id: "olovo", + olxid: "3221" + }, + { + name: "Osmaci", + id: "osmaci", + olxid: "2128" + }, + { + name: "Pale", + id: "pale", + olxid: "3978" + }, + { + name: "Rogatica", + id: "rogatica", + olxid: "3529" + }, + { + name: "Rudo", + id: "rudo", + olxid: "3648" + }, + { + name: "Sarajevo-Novi Grad", + id: "sarajevonovigrad", + olxid: "6069" + }, + { + name: "Sokolac", + id: "sokolac", + olxid: "4183" + }, + { + name: "Srebrenica", + id: "srebrenica", + olxid: "4310" + }, + { + name: "Trnovo", + id: "trnovo", + olxid: "4067" + }, + { + name: "Ustiprača", + id: "ustipraa", + olxid: "1593" + }, + { + name: "Višegrad", + id: "viegrad", + olxid: "5259" + }, + { + name: "Vlasenica", + id: "vlasenica", + olxid: "5456" + }, + { + name: "Zvornik", + id: "zvornik", + olxid: "5684" + }, + { + name: "Šekovići", + id: "ekovii", + olxid: "4475" + }, + { + name: "Žepa", + id: "epa", + olxid: "1906" + } + ] + }, + { + name: " Trebinjsko-Fočanska", + id: "trebinjskofocanska", + olxid: "17", + municipalities: [ + { + name: "Berkovići", + id: "berkovii", + olxid: "4441" + }, + { + name: "Bileća", + id: "bilea", + olxid: "183" + }, + { + name: "Foča", + id: "foa", + olxid: "1287" + }, + { + name: "Gacko", + id: "gacko", + olxid: "1462" + }, + { + name: "Istočni Mostar", + id: "istonimostar", + olxid: "3038" + }, + { + name: "Kalinovik", + id: "kalinovik", + olxid: "2164" + }, + { + name: "Ljubinje", + id: "ljubinje", + olxid: "2884" + }, + { + name: "Nevesinje", + id: "nevesinje", + olxid: "3138" + }, + { + name: "Trebinje", + id: "trebinje", + olxid: "4766" + }, + { + name: "Čajniče", + id: "ajnie", + olxid: "911" + } + ] + }, + { + name: "Distrikt Brčko", + id: "distriktbrcko", + olxid: "12", + municipalities: [ + { + name: "Brčko", + id: "brko", + olxid: "12" + } + ] + } ]; const getRegions = () => { - return regions.map((g) => ({ name: g.name, id: g.id, olxid: g.olxid })); + return regions.map(g => ({ name: g.name, id: g.id, olxid: g.olxid })); }; -const getRegion = (regionId) => { - return regions.find(region => region.id === regionId); +const getRegion = regionId => { + return regions.find(region => region.id === regionId); }; -const getRegionName = (regionId) => { - const region = getRegion(regionId); - return (region && region.name) ? region.name : null; +const getRegionName = regionId => { + const region = getRegion(regionId); + return region && region.name ? region.name : null; }; -const getMunicipalitiesForRegion = (regionId) => { - const region = getRegion(regionId); - return (region && region.municipalities) ? region.municipalities : null; +const getMunicipalitiesForRegion = regionId => { + const region = getRegion(regionId); + return region && region.municipalities ? region.municipalities : null; }; const getMunicipality = (regionId, municipalityId) => { - const region = getRegion(regionId); - if (!region) { - return null; - } + const region = getRegion(regionId); + if (!region) { + return null; + } - const municipality = region.municipalities.find(municipality => municipality.id === municipalityId); - if (!municipality) { - return null; - } + const municipality = region.municipalities.find( + municipality => municipality.id === municipalityId + ); + if (!municipality) { + return null; + } - return municipality; + return municipality; }; const getMunicipalityName = (regionId, municipalityId) => { - const region = getRegion(regionId); - if (!region) { - return null; - } + const region = getRegion(regionId); + if (!region) { + return null; + } - const municipality = region.municipalities.find(municipality => municipality.id === municipalityId); - if (!municipality) { - return null; - } + const municipality = region.municipalities.find( + municipality => municipality.id === municipalityId + ); + if (!municipality) { + return null; + } - return municipality.name; + return municipality.name; }; module.exports = { - getRegion, - getRegions, - getRegionName, - getMunicipalitiesForRegion, - getMunicipalityName, - getMunicipality + getRegion, + getRegions, + getRegionName, + getMunicipalitiesForRegion, + getMunicipalityName, + getMunicipality }; diff --git a/app/helpers/email.js b/app/helpers/email.js index c5b7d66..730f2a6 100644 --- a/app/helpers/email.js +++ b/app/helpers/email.js @@ -1,7 +1,6 @@ - -const isValidEmail = (email) => { +const isValidEmail = email => { const simpleEmailRegex = /^.+@.+\..+$/; - return (email && email.length < 250 && simpleEmailRegex.test(email)); + return email && email.length < 250 && simpleEmailRegex.test(email); }; module.exports = { diff --git a/app/helpers/enums.js b/app/helpers/enums.js index ff78e09..91c243d 100644 --- a/app/helpers/enums.js +++ b/app/helpers/enums.js @@ -1,57 +1,57 @@ const realEstateTypes = [ - { title: "Kuća", id: "kuca", hasGardenSize: true, olxCategory: 24 }, - { title: "Stan", id: "stan", hasGardenSize: false, olxCategory: 23}, - { title: "Vikendica", id: "vikendica", hasGardenSize: true, olxCategory: 26 } + { title: "Kuća", id: "kuca", hasGardenSize: true, olxCategory: 24 }, + { title: "Stan", id: "stan", hasGardenSize: false, olxCategory: 23 }, + { title: "Vikendica", id: "vikendica", hasGardenSize: true, olxCategory: 26 } ]; const sizes = [ - { title: "do 50 m2", id: "50m2" }, - { title: "do 75 m2", id: "75m2" }, - { title: "do 100 m2", id: "100m2" }, - { title: "do 150 m2", id: "150m2" }, - { title: "do 200 m2", id: "200m2" }, - { title: "preko 200 m2", id: "moreThan200m2" } + { title: "do 50 m2", id: "50m2" }, + { title: "do 75 m2", id: "75m2" }, + { title: "do 100 m2", id: "100m2" }, + { title: "do 150 m2", id: "150m2" }, + { title: "do 200 m2", id: "200m2" }, + { title: "preko 200 m2", id: "moreThan200m2" } ]; const gardenSizes = [ - { title: "do 100 m2", id: "100m2" }, - { title: "do 500 m2", id: "500m2" }, - { title: "do 1 dunum", id: "1000m2" }, - { title: "do 2 dunuma", id: "2000m2" }, - { title: "do 3 dunuma", id: "3000m2" }, - { title: "preko 3 dunuma", id: "moreThan3000m2" } + { title: "do 100 m2", id: "100m2" }, + { title: "do 500 m2", id: "500m2" }, + { title: "do 1 dunum", id: "1000m2" }, + { title: "do 2 dunuma", id: "2000m2" }, + { title: "do 3 dunuma", id: "3000m2" }, + { title: "preko 3 dunuma", id: "moreThan3000m2" } ]; const prices = [ - { title: "do 50 000 KM", id: "50kKM" }, - { title: "do 100 000 KM", id: "100kKM" }, - { title: "do 150 000 KM", id: "150kKM" }, - { title: "do 200 000 KM", id: "200kKM" }, - { title: "do 250 000 KM", id: "250kKM" }, - { title: "preko 250 000 KM", id: "moreThan250kKM" } + { title: "do 50 000 KM", id: "50kKM" }, + { title: "do 100 000 KM", id: "100kKM" }, + { title: "do 150 000 KM", id: "150kKM" }, + { title: "do 200 000 KM", id: "200kKM" }, + { title: "do 250 000 KM", id: "250kKM" }, + { title: "preko 250 000 KM", id: "moreThan250kKM" } ]; const getEnumObject = (enumType, enumId) => { - return enumType.find(enumValue => enumValue.id === enumId); + return enumType.find(enumValue => enumValue.id === enumId); }; -const getRealEstateTypeEnum = (enumId) => { - return getEnumObject(realEstateTypes, enumId) || null; -} +const getRealEstateTypeEnum = enumId => { + return getEnumObject(realEstateTypes, enumId) || null; +}; const getEnumTypeTitle = (enumType, enumId) => { - const enumObject = getEnumObject(enumType, enumId); - if (!enumObject){ - return null; - } - return enumObject.title; + const enumObject = getEnumObject(enumType, enumId); + if (!enumObject) { + return null; + } + return enumObject.title; }; module.exports = { - realEstateTypes, - sizes, - gardenSizes, - prices, - getRealEstateTypeEnum, - getEnumTypeTitle, + realEstateTypes, + sizes, + gardenSizes, + prices, + getRealEstateTypeEnum, + getEnumTypeTitle }; diff --git a/app/helpers/url.js b/app/helpers/url.js index 8bf1cb5..78036c5 100644 --- a/app/helpers/url.js +++ b/app/helpers/url.js @@ -1,12 +1,12 @@ -const db = require('../models/index'); +const db = require("../models/index"); -const currentRERequest = async (req) => { - const uniqueId = req.params['request_id']; - if(!uniqueId) return null; +const currentRERequest = async req => { + const uniqueId = req.params["request_id"]; + if (!uniqueId) return null; - const request = await db.RealEstateRequest.findOne({ where: {uniqueId} }); + const request = await db.RealEstateRequest.findOne({ where: { uniqueId } }); return request; }; module.exports = { - currentRERequest, + currentRERequest }; diff --git a/app/lib/sendNotification.js b/app/lib/sendNotification.js index fe84d31..14e6b73 100644 --- a/app/lib/sendNotification.js +++ b/app/lib/sendNotification.js @@ -1,9 +1,8 @@ const scrapTheItems = require("./scrapTheItems"); const convertToDate = require("./convertToDate"); -const AWS = require('aws-sdk'); +const AWS = require("aws-sdk"); // AWS.config.update({region: 'eu-central-1'}); - async function sendNotification(marketAlert) { const { id, email, olx_url } = marketAlert; let url = @@ -19,37 +18,37 @@ async function sendNotification(marketAlert) { // Create sendEmail params const params = { - Destination: { /* required */ - CcAddresses: [ - ], - ToAddresses: [ - email - ] + Destination: { + /* required */ + CcAddresses: [], + ToAddresses: [email] }, - Message: { /* required */ - Body: { /* required */ + Message: { + /* required */ + Body: { + /* required */ Html: { - Charset: "UTF-8", - Data: message + Charset: "UTF-8", + Data: message }, Text: { - Charset: "UTF-8", - Data: message // TODO: convert to text + Charset: "UTF-8", + Data: message // TODO: convert to text } - }, - Subject: { - Charset: 'UTF-8', - Data: 'Javimi alert' - } + }, + Subject: { + Charset: "UTF-8", + Data: "Javimi alert" + } }, - Source: 'info@saburly.com', /* required */ - ReplyToAddresses: [ - 'info@saburly.com', - ], + Source: "info@saburly.com" /* required */, + ReplyToAddresses: ["info@saburly.com"] }; 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; return { id, date: String(convertToDate(lastDate)) }; } diff --git a/app/migrations/20190417035319-create-market-alert.js b/app/migrations/20190417035319-create-market-alert.js index 9ad4e62..7c4260f 100644 --- a/app/migrations/20190417035319-create-market-alert.js +++ b/app/migrations/20190417035319-create-market-alert.js @@ -1,7 +1,7 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.createTable('MarketAlerts', { + return queryInterface.createTable("MarketAlerts", { id: { allowNull: false, autoIncrement: true, @@ -29,6 +29,6 @@ module.exports = { }); }, down: (queryInterface, Sequelize) => { - return queryInterface.dropTable('MarketAlerts'); + return queryInterface.dropTable("MarketAlerts"); } }; diff --git a/app/migrations/20190417035707-create-real-estate-request.js b/app/migrations/20190417035707-create-real-estate-request.js index 49be61f..b0309f9 100644 --- a/app/migrations/20190417035707-create-real-estate-request.js +++ b/app/migrations/20190417035707-create-real-estate-request.js @@ -1,7 +1,7 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.createTable('RealEstateRequests', { + return queryInterface.createTable("RealEstateRequests", { id: { allowNull: false, autoIncrement: true, @@ -28,6 +28,6 @@ module.exports = { }); }, down: (queryInterface, Sequelize) => { - return queryInterface.dropTable('RealEstateRequests'); + return queryInterface.dropTable("RealEstateRequests"); } }; diff --git a/app/migrations/20190427043621-add_city_to_real_estate_request.js b/app/migrations/20190427043621-add_city_to_real_estate_request.js index be6f6a8..f64f12d 100644 --- a/app/migrations/20190427043621-add_city_to_real_estate_request.js +++ b/app/migrations/20190427043621-add_city_to_real_estate_request.js @@ -1,18 +1,15 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.addColumn( - 'RealEstateRequests', - 'city', - Sequelize.STRING + "RealEstateRequests", + "city", + Sequelize.STRING ); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'RealEstateRequests', - 'city' - ); + return queryInterface.removeColumn("RealEstateRequests", "city"); } }; diff --git a/app/migrations/20190429050222-add_place_to_real_estate_request.js b/app/migrations/20190429050222-add_place_to_real_estate_request.js index 3fb0b4b..5273e5f 100644 --- a/app/migrations/20190429050222-add_place_to_real_estate_request.js +++ b/app/migrations/20190429050222-add_place_to_real_estate_request.js @@ -1,18 +1,15 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.addColumn( - 'RealEstateRequests', - 'place', - Sequelize.STRING + "RealEstateRequests", + "place", + Sequelize.STRING ); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'RealEstateRequests', - 'place' - ); + return queryInterface.removeColumn("RealEstateRequests", "place"); } }; diff --git a/app/migrations/20190516180226-rename-place-column.js b/app/migrations/20190516180226-rename-place-column.js index 55f6484..58b9581 100644 --- a/app/migrations/20190516180226-rename-place-column.js +++ b/app/migrations/20190516180226-rename-place-column.js @@ -1,19 +1,19 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.renameColumn( - 'RealEstateRequests', - 'place', - 'municipality' + "RealEstateRequests", + "place", + "municipality" ); }, down: (queryInterface, Sequelize) => { return queryInterface.renameColumn( - 'RealEstateRequests', - 'municipality', - 'place' + "RealEstateRequests", + "municipality", + "place" ); } }; diff --git a/app/migrations/20190516222240-rename-city-column.js b/app/migrations/20190516222240-rename-city-column.js index 7b8742e..2a0e717 100644 --- a/app/migrations/20190516222240-rename-city-column.js +++ b/app/migrations/20190516222240-rename-city-column.js @@ -1,19 +1,11 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.renameColumn( - 'RealEstateRequests', - 'city', - 'region' - ); + return queryInterface.renameColumn("RealEstateRequests", "city", "region"); }, down: (queryInterface, Sequelize) => { - return queryInterface.renameColumn( - 'RealEstateRequests', - 'region', - 'city' - ); + return queryInterface.renameColumn("RealEstateRequests", "region", "city"); } }; diff --git a/app/migrations/20190517072957-add-size-to-real-estate-request.js b/app/migrations/20190517072957-add-size-to-real-estate-request.js index 7f28585..e910c21 100644 --- a/app/migrations/20190517072957-add-size-to-real-estate-request.js +++ b/app/migrations/20190517072957-add-size-to-real-estate-request.js @@ -1,20 +1,13 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.addColumn( - 'RealEstateRequests', - 'size', - { - type: Sequelize.STRING - } - ); + return queryInterface.addColumn("RealEstateRequests", "size", { + type: Sequelize.STRING + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'RealEstateRequests', - 'size' - ); + return queryInterface.removeColumn("RealEstateRequests", "size"); } }; diff --git a/app/migrations/20190517090015-add-gardenSize-to-real-estate-request.js b/app/migrations/20190517090015-add-gardenSize-to-real-estate-request.js index 84e2319..18e7f4c 100644 --- a/app/migrations/20190517090015-add-gardenSize-to-real-estate-request.js +++ b/app/migrations/20190517090015-add-gardenSize-to-real-estate-request.js @@ -1,20 +1,13 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.addColumn( - 'RealEstateRequests', - 'gardenSize', - { - type: Sequelize.STRING - } - ); + return queryInterface.addColumn("RealEstateRequests", "gardenSize", { + type: Sequelize.STRING + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'RealEstateRequests', - 'gardenSize' - ); + return queryInterface.removeColumn("RealEstateRequests", "gardenSize"); } }; diff --git a/app/migrations/20190517092716-add-price-to-real-estate-request.js b/app/migrations/20190517092716-add-price-to-real-estate-request.js index 13bcae6..2035378 100644 --- a/app/migrations/20190517092716-add-price-to-real-estate-request.js +++ b/app/migrations/20190517092716-add-price-to-real-estate-request.js @@ -1,20 +1,13 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.addColumn( - 'RealEstateRequests', - 'price', - { - type: Sequelize.STRING - } - ); + return queryInterface.addColumn("RealEstateRequests", "price", { + type: Sequelize.STRING + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'RealEstateRequests', - 'price' - ); + return queryInterface.removeColumn("RealEstateRequests", "price"); } }; diff --git a/app/migrations/20190523144812-activate-postgis.js b/app/migrations/20190523144812-activate-postgis.js index 8b944e3..48c8cde 100644 --- a/app/migrations/20190523144812-activate-postgis.js +++ b/app/migrations/20190523144812-activate-postgis.js @@ -1,15 +1,19 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.sequelize.query("CREATE EXTENSION postgis").then(([results, metadata]) => { - /// No result - }) + return queryInterface.sequelize + .query("CREATE EXTENSION postgis") + .then(([results, metadata]) => { + /// No result + }); }, 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 - }) + }); } }; diff --git a/app/migrations/20190523151420-add-bounding-box-column.js b/app/migrations/20190523151420-add-bounding-box-column.js index e319421..601b566 100644 --- a/app/migrations/20190523151420-add-bounding-box-column.js +++ b/app/migrations/20190523151420-add-bounding-box-column.js @@ -1,17 +1,21 @@ -'use strict'; +"use strict"; module.exports = { - up: (queryInterface, Sequelize) => { - - return queryInterface.sequelize.query("ALTER TABLE \"RealEstateRequests\" ADD COLUMN bounding_box geometry(Polygon);").then(([results, metadata]) => { - /// No result - }) + return queryInterface.sequelize + .query( + 'ALTER TABLE "RealEstateRequests" ADD COLUMN bounding_box geometry(Polygon);' + ) + .then(([results, metadata]) => { + /// No result + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.sequelize.query("ALTER TABLE \"RealEstateRequests\" DROP COLUMN bounding_box").then(([results, metadata]) => { - /// No result - }) + return queryInterface.sequelize + .query('ALTER TABLE "RealEstateRequests" DROP COLUMN bounding_box') + .then(([results, metadata]) => { + /// No result + }); } -}; \ No newline at end of file +}; diff --git a/app/migrations/20190529093410-slider-fields.js b/app/migrations/20190529093410-slider-fields.js index d260600..b4dc687 100644 --- a/app/migrations/20190529093410-slider-fields.js +++ b/app/migrations/20190529093410-slider-fields.js @@ -1,27 +1,48 @@ module.exports = { - up: (queryInterface, Sequelize) => { - return queryInterface.sequelize.transaction((t) => { - return Promise.all([ - queryInterface.addColumn('RealEstateRequests', 'sizeRange', { - type: Sequelize.STRING - }, { transaction: t }), - queryInterface.addColumn('RealEstateRequests', 'gardenSizeRange', { - type: Sequelize.STRING, - }, { transaction: t }), - queryInterface.addColumn('RealEstateRequests', 'priceRange', { - type: Sequelize.STRING, - }, { transaction: t }) - ]) - }) - }, + up: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.addColumn( + "RealEstateRequests", + "sizeRange", + { + 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) => { - return queryInterface.sequelize.transaction((t) => { - return Promise.all([ - queryInterface.removeColumn('RealEstateRequests', 'sizeRange', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'gardenSizeRange', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'priceRange', { transaction: t }) - ]) + down: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.removeColumn("RealEstateRequests", "sizeRange", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "gardenSizeRange", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "priceRange", { + transaction: t }) - } -}; \ No newline at end of file + ]); + }); + } +}; diff --git a/app/migrations/20190530101945-range-fields.js b/app/migrations/20190530101945-range-fields.js index caad42c..ef2a475 100644 --- a/app/migrations/20190530101945-range-fields.js +++ b/app/migrations/20190530101945-range-fields.js @@ -1,63 +1,147 @@ module.exports = { - up: (queryInterface, Sequelize) => { - return queryInterface.sequelize.transaction((t) => { - return Promise.all([ - queryInterface.removeColumn('RealEstateRequests', 'sizeRange', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'gardenSizeRange', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'priceRange', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'size', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'gardenSize', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'price', { transaction: t }), - queryInterface.addColumn('RealEstateRequests', 'gardenSizeMin', { - type: Sequelize.INTEGER, - }, { 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 }) - ]) - }) - }, + up: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.removeColumn("RealEstateRequests", "sizeRange", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "gardenSizeRange", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "priceRange", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "size", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "gardenSize", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "price", { + transaction: t + }), + queryInterface.addColumn( + "RealEstateRequests", + "gardenSizeMin", + { + type: Sequelize.INTEGER + }, + { 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) => { - return queryInterface.sequelize.transaction((t) => { - return Promise.all([ - queryInterface.removeColumn('RealEstateRequests', 'gardenSizeMin', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'gardenSizeMax', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'sizeMin', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'sizeMax', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'priceMin', { transaction: t }), - queryInterface.removeColumn('RealEstateRequests', 'priceMin', { transaction: t }), - queryInterface.addColumn('RealEstateRequests', 'priceMax', { - type: Sequelize.STRING - }, { 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 }) - ]) - }) - } -}; \ No newline at end of file + down: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.removeColumn("RealEstateRequests", "gardenSizeMin", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "gardenSizeMax", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "sizeMin", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "sizeMax", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "priceMin", { + transaction: t + }), + queryInterface.removeColumn("RealEstateRequests", "priceMin", { + transaction: t + }), + queryInterface.addColumn( + "RealEstateRequests", + "priceMax", + { + type: Sequelize.STRING + }, + { 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 } + ) + ]); + }); + } +}; diff --git a/app/migrations/20190531111232-subscribed-boolean.js b/app/migrations/20190531111232-subscribed-boolean.js index 2143f1c..acb4dd3 100644 --- a/app/migrations/20190531111232-subscribed-boolean.js +++ b/app/migrations/20190531111232-subscribed-boolean.js @@ -1,18 +1,15 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.addColumn( - 'RealEstateRequests', - 'subscribed', - Sequelize.BOOLEAN + "RealEstateRequests", + "subscribed", + Sequelize.BOOLEAN ); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'RealEstateRequests', - 'subscribed' - ); + return queryInterface.removeColumn("RealEstateRequests", "subscribed"); } }; diff --git a/app/migrations/20190618103020-expand-maketalert.js b/app/migrations/20190618103020-expand-maketalert.js index 54eed96..20cf2c7 100644 --- a/app/migrations/20190618103020-expand-maketalert.js +++ b/app/migrations/20190618103020-expand-maketalert.js @@ -1,37 +1,70 @@ -'use strict'; +"use strict"; module.exports = { - up: (queryInterface, Sequelize) => { - return queryInterface.sequelize.transaction((t) => { - return Promise.all([ - queryInterface.addColumn('MarketAlerts', 'size', { - type: Sequelize.INTEGER, - }, { transaction: t }), - queryInterface.addColumn('MarketAlerts', 'gardenSize', { - type: Sequelize.INTEGER, - }, { 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 }) - ]) - }) - }, + up: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.addColumn( + "MarketAlerts", + "size", + { + type: Sequelize.INTEGER + }, + { transaction: t } + ), + queryInterface.addColumn( + "MarketAlerts", + "gardenSize", + { + type: Sequelize.INTEGER + }, + { 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) => { - return queryInterface.sequelize.transaction((t) => { - return Promise.all([ - queryInterface.removeColumn('MarketAlerts', 'size', { transaction: t }), - queryInterface.removeColumn('MarketAlerts', 'gardenSize', { transaction: t }), - queryInterface.removeColumn('MarketAlerts', 'price', { transaction: t }), - queryInterface.removeColumn('MarketAlerts', 'municipality', { transaction: t }), - queryInterface.removeColumn('MarketAlerts', 'region', { transaction: t }) - ]) + down: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.removeColumn("MarketAlerts", "size", { transaction: t }), + queryInterface.removeColumn("MarketAlerts", "gardenSize", { + transaction: t + }), + queryInterface.removeColumn("MarketAlerts", "price", { + transaction: t + }), + queryInterface.removeColumn("MarketAlerts", "municipality", { + transaction: t + }), + queryInterface.removeColumn("MarketAlerts", "region", { + transaction: t }) - } + ]); + }); + } }; diff --git a/app/migrations/20190618124522-marketalerts-additional-info.js b/app/migrations/20190618124522-marketalerts-additional-info.js index 48847d1..330faf5 100644 --- a/app/migrations/20190618124522-marketalerts-additional-info.js +++ b/app/migrations/20190618124522-marketalerts-additional-info.js @@ -1,33 +1,59 @@ -'use strict'; +"use strict"; module.exports = { - up: (queryInterface, Sequelize) => { - return queryInterface.sequelize.transaction((t) => { - return Promise.all([ - queryInterface.removeColumn('MarketAlerts', 'olxUrl', { transaction: t }), - queryInterface.addColumn('MarketAlerts', 'url', { - type: Sequelize.STRING, - }, { transaction: t }), - queryInterface.addColumn('MarketAlerts', 'realestateOrigin', { - type: Sequelize.STRING, - }, { transaction: t }), - queryInterface.addColumn('MarketAlerts', 'originId', { - type: Sequelize.STRING, - }, { transaction: t }) - ]) - }) - }, + up: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.removeColumn("MarketAlerts", "olxUrl", { + transaction: t + }), + queryInterface.addColumn( + "MarketAlerts", + "url", + { + type: Sequelize.STRING + }, + { transaction: t } + ), + queryInterface.addColumn( + "MarketAlerts", + "realestateOrigin", + { + type: Sequelize.STRING + }, + { transaction: t } + ), + queryInterface.addColumn( + "MarketAlerts", + "originId", + { + type: Sequelize.STRING + }, + { transaction: t } + ) + ]); + }); + }, - down: (queryInterface, Sequelize) => { - return queryInterface.sequelize.transaction((t) => { - return Promise.all([ - queryInterface.removeColumn('MarketAlerts', 'url', { transaction: t }), - queryInterface.removeColumn('MarketAlerts', 'realestateOrigin', { transaction: t }), - queryInterface.removeColumn('MarketAlerts', 'originId', { transaction: t }), - queryInterface.addColumn('MarketAlerts', 'olxUrl', { - type: Sequelize.STRING - }, { transaction: t }) - ]) - }) - } + down: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.removeColumn("MarketAlerts", "url", { transaction: t }), + queryInterface.removeColumn("MarketAlerts", "realestateOrigin", { + transaction: t + }), + queryInterface.removeColumn("MarketAlerts", "originId", { + transaction: t + }), + queryInterface.addColumn( + "MarketAlerts", + "olxUrl", + { + type: Sequelize.STRING + }, + { transaction: t } + ) + ]); + }); + } }; diff --git a/app/migrations/20190621162321-add-category-to-marketalert.js b/app/migrations/20190621162321-add-category-to-marketalert.js index d8a49f5..8f7a755 100644 --- a/app/migrations/20190621162321-add-category-to-marketalert.js +++ b/app/migrations/20190621162321-add-category-to-marketalert.js @@ -1,20 +1,13 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.addColumn( - 'MarketAlerts', - 'realEstateType', - { - type: Sequelize.STRING - } - ); + return queryInterface.addColumn("MarketAlerts", "realEstateType", { + type: Sequelize.STRING + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'MarketAlerts', - 'realEstateType' - ); + return queryInterface.removeColumn("MarketAlerts", "realEstateType"); } }; diff --git a/app/migrations/20190625120813-add-notification-sent-boolean-marketalerts.js b/app/migrations/20190625120813-add-notification-sent-boolean-marketalerts.js index f70e6f6..339f4be 100644 --- a/app/migrations/20190625120813-add-notification-sent-boolean-marketalerts.js +++ b/app/migrations/20190625120813-add-notification-sent-boolean-marketalerts.js @@ -1,20 +1,13 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.addColumn( - 'MarketAlerts', - 'notified', - { - type: Sequelize.BOOLEAN - } - ); + return queryInterface.addColumn("MarketAlerts", "notified", { + type: Sequelize.BOOLEAN + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'MarketAlerts', - 'notified' - ); + return queryInterface.removeColumn("MarketAlerts", "notified"); } }; diff --git a/app/migrations/20190628165512-add-title-to-marketalerts.js b/app/migrations/20190628165512-add-title-to-marketalerts.js index d874f3d..6316d88 100644 --- a/app/migrations/20190628165512-add-title-to-marketalerts.js +++ b/app/migrations/20190628165512-add-title-to-marketalerts.js @@ -1,20 +1,13 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.addColumn( - 'MarketAlerts', - 'title', - { - type: Sequelize.STRING - } - ); + return queryInterface.addColumn("MarketAlerts", "title", { + type: Sequelize.STRING + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'MarketAlerts', - 'title' - ); + return queryInterface.removeColumn("MarketAlerts", "title"); } }; diff --git a/app/migrations/20190702132143-add-RREquet-uuid-to-marketalerts.js b/app/migrations/20190702132143-add-RREquet-uuid-to-marketalerts.js index b904e6f..d8d7c5b 100644 --- a/app/migrations/20190702132143-add-RREquet-uuid-to-marketalerts.js +++ b/app/migrations/20190702132143-add-RREquet-uuid-to-marketalerts.js @@ -1,20 +1,13 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.addColumn( - 'MarketAlerts', - 'request', - { - type: Sequelize.STRING - } - ); + return queryInterface.addColumn("MarketAlerts", "request", { + type: Sequelize.STRING + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'MarketAlerts', - 'request' - ); + return queryInterface.removeColumn("MarketAlerts", "request"); } }; diff --git a/app/migrations/20190710141356-add-has-location-to-marketalerts.js b/app/migrations/20190710141356-add-has-location-to-marketalerts.js index 049efe3..237c798 100644 --- a/app/migrations/20190710141356-add-has-location-to-marketalerts.js +++ b/app/migrations/20190710141356-add-has-location-to-marketalerts.js @@ -1,20 +1,13 @@ -'use strict'; +"use strict"; module.exports = { up: (queryInterface, Sequelize) => { - return queryInterface.addColumn( - 'MarketAlerts', - 'hasLocation', - { - type: Sequelize.BOOLEAN - } - ); + return queryInterface.addColumn("MarketAlerts", "hasLocation", { + type: Sequelize.BOOLEAN + }); }, down: (queryInterface, Sequelize) => { - return queryInterface.removeColumn( - 'MarketAlerts', - 'hasLocation' - ); + return queryInterface.removeColumn("MarketAlerts", "hasLocation"); } }; diff --git a/app/models/index.js b/app/models/index.js index c1a3d6d..e7926d0 100644 --- a/app/models/index.js +++ b/app/models/index.js @@ -1,27 +1,33 @@ -'use strict'; +"use strict"; -const fs = require('fs'); -const path = require('path'); -const Sequelize = require('sequelize'); +const fs = require("fs"); +const path = require("path"); +const Sequelize = require("sequelize"); const basename = path.basename(__filename); -const env = process.env.NODE_ENV || 'development'; -const config = require(__dirname + '/../config/config.json')[env]; +const env = process.env.NODE_ENV || "development"; +const config = require(__dirname + "/../config/config.json")[env]; const db = {}; let sequelize; if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config); } else { - sequelize = new Sequelize(config.database, config.username, config.password, config); + sequelize = new Sequelize( + config.database, + config.username, + config.password, + config + ); } -fs - .readdirSync(__dirname) +fs.readdirSync(__dirname) .filter(file => { - return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); + return ( + file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js" + ); }) .forEach(file => { - const model = sequelize['import'](path.join(__dirname, file)); + const model = sequelize["import"](path.join(__dirname, file)); db[model.name] = model; }); diff --git a/app/models/marketalert.js b/app/models/marketalert.js index 14742ff..ddae1d5 100644 --- a/app/models/marketalert.js +++ b/app/models/marketalert.js @@ -1,26 +1,30 @@ -'use strict'; +"use strict"; module.exports = (sequelize, DataTypes) => { - const MarketAlert = sequelize.define('MarketAlert', { - url: DataTypes.STRING, - realestateOrigin: DataTypes.STRING, - originId: DataTypes.STRING, - lastDate: DataTypes.STRING, - size : DataTypes.INTEGER, - gardenSize : DataTypes.INTEGER, - price : DataTypes.INTEGER, - municipality : DataTypes.STRING, - region : DataTypes.STRING, - realEstateType : DataTypes.STRING, - notified : DataTypes.BOOLEAN, - title : DataTypes.STRING, - request: DataTypes.STRING, - hasLocation: DataTypes.BOOLEAN, - - email: { - type: DataTypes.STRING, - allowNul: false - } - }, {}); + const MarketAlert = sequelize.define( + "MarketAlert", + { + url: DataTypes.STRING, + realestateOrigin: DataTypes.STRING, + originId: DataTypes.STRING, + lastDate: DataTypes.STRING, + size: DataTypes.INTEGER, + gardenSize: DataTypes.INTEGER, + price: DataTypes.INTEGER, + municipality: DataTypes.STRING, + region: DataTypes.STRING, + realEstateType: DataTypes.STRING, + notified: DataTypes.BOOLEAN, + title: DataTypes.STRING, + request: DataTypes.STRING, + hasLocation: DataTypes.BOOLEAN, + + email: { + type: DataTypes.STRING, + allowNul: false + } + }, + {} + ); MarketAlert.associate = function(models) { // associations can be defined here }; diff --git a/app/models/realestaterequest.js b/app/models/realestaterequest.js index e618d8d..8cedce9 100644 --- a/app/models/realestaterequest.js +++ b/app/models/realestaterequest.js @@ -1,26 +1,29 @@ -'use strict'; +"use strict"; module.exports = (sequelize, DataTypes) => { - - const RealEstateRequest = sequelize.define('RealEstateRequest', { - uniqueId: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - allowNull: false + const RealEstateRequest = sequelize.define( + "RealEstateRequest", + { + uniqueId: { + type: DataTypes.UUID, + 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) { // associations can be defined here }; diff --git a/app/services/crawlerService.js b/app/services/crawlerService.js index 860afa2..aaae6f7 100644 --- a/app/services/crawlerService.js +++ b/app/services/crawlerService.js @@ -1,85 +1,93 @@ - const Promise = require("bluebird"); const OlxCrawler = require("../helpers/crawlers/olxClawler"); const db = require("../models/index"); -const { allMarketAlerts } = require('../helpers/db/dbHelper'); - +const { allMarketAlerts } = require("../helpers/db/dbHelper"); async function crawlAll() { - console.log("CRAWLER SERVICE: crawlAll"); + console.log("CRAWLER SERVICE: crawlAll"); - try { - const marketAlertsFromDb = await allMarketAlerts(true); - const hrefs = []; + try { + const marketAlertsFromDb = await allMarketAlerts(true); + const hrefs = []; - marketAlertsFromDb.map(marketAlert => { - if (hrefs[marketAlert.request] === undefined) { - hrefs[marketAlert.request] = [] - } + marketAlertsFromDb.map(marketAlert => { + if (hrefs[marketAlert.request] === undefined) { + hrefs[marketAlert.request] = []; + } - hrefs[marketAlert.request].push(marketAlert.url); - }) + hrefs[marketAlert.request].push(marketAlert.url); + }); - console.log("CRAWLER SERVICE: GLOBAL HREFS"); - console.log(hrefs); - const olxCrawler = new OlxCrawler(hrefs); + console.log("CRAWLER SERVICE: GLOBAL HREFS"); + console.log(hrefs); + const olxCrawler = new OlxCrawler(hrefs); - const crawlers = [ - olxCrawler, - ]; - - return Promise.map(crawlers, function (crawler) { - return crawler.crawl(); - }).then(async (results) => { + const crawlers = [olxCrawler]; - try { + return Promise.map(crawlers, function(crawler) { + return crawler.crawl(); + }).then(async results => { + try { + const marketAlertsFromDb = await allMarketAlerts(false, true); - const marketAlertsFromDb = await allMarketAlerts(false, true); + console.log( + "CRAWLER SERVICE: number of existing MarketAlerts from db: " + + marketAlertsFromDb.length + ); - console.log("CRAWLER SERVICE: number of existing MarketAlerts from db: " + marketAlertsFromDb.length); + const marketAlerts = []; + const mergedResults = [].concat.apply([], results); - const marketAlerts = []; - const mergedResults = [].concat.apply([], results); + 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 crawler results: " + marketAlerts.length + ); - 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 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 + ); - 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); - } -}; + 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; diff --git a/app/services/notificationService.js b/app/services/notificationService.js index ba3b4ab..b49de5d 100644 --- a/app/services/notificationService.js +++ b/app/services/notificationService.js @@ -1,29 +1,34 @@ - const db = require("../models/index"); -const { allMarketAlerts } = require('../helpers/db/dbHelper'); -const { createMarketAlertEmailTemplate, sendBulkEmail } = require('../helpers/awsEmail'); - +const { allMarketAlerts } = require("../helpers/db/dbHelper"); +const { + createMarketAlertEmailTemplate, + sendBulkEmail +} = require("../helpers/awsEmail"); async function processNotifications() { - - try { - const marketAlerts = await allMarketAlerts(false, false); - console.log(marketAlerts.length) - await createMarketAlertEmailTemplate(); - 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); + try { + const marketAlerts = await allMarketAlerts(false, false); + console.log(marketAlerts.length); + await createMarketAlertEmailTemplate(); + 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 + ); + } } module.exports = processNotifications; From 08f73445e9a94f304333a6eaf7838f5bba8e63cf Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Thu, 5 Sep 2019 12:51:01 +0200 Subject: [PATCH 2/7] add ENV variables for DB credentials to override sequelize config --- app/helpers/awsEmail.js | 1 - app/models/index.js | 5 +++++ development.env | 15 ++++++++++----- index.js | 2 ++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/helpers/awsEmail.js b/app/helpers/awsEmail.js index 9ca4bcb..24544d6 100644 --- a/app/helpers/awsEmail.js +++ b/app/helpers/awsEmail.js @@ -1,4 +1,3 @@ -const dotenv = require("dotenv").config(); const { getRealEstateTypeEnum } = require("./enums"); const { getRegionName, getMunicipalityName } = require("./codes"); const { allRERequestByUiid } = require("./db/dbHelper"); diff --git a/app/models/index.js b/app/models/index.js index e7926d0..ac4279a 100644 --- a/app/models/index.js +++ b/app/models/index.js @@ -8,6 +8,11 @@ const env = process.env.NODE_ENV || "development"; const config = require(__dirname + "/../config/config.json")[env]; 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; + let sequelize; if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config); diff --git a/development.env b/development.env index 3980ba3..d14d427 100644 --- a/development.env +++ b/development.env @@ -1,5 +1,10 @@ - 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 \ No newline at end of file +DB_USERNAME=Username for the database +DB_PASSWORD=Password for the database +DB_NAME=Database name +DB_PORT=Database port + +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 diff --git a/index.js b/index.js index 5e9ad28..39d4049 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +require("dotenv").config(); + const welcome = require("./app/controllers/welcome").getWelcome; const { getRealEstateTypes, From f311404968577f9df4aa752a9e86986f45d3bef7 Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Thu, 5 Sep 2019 13:50:13 +0200 Subject: [PATCH 3/7] allow control over sequelize logging using ENV variable --- app/models/index.js | 1 + development.env | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/models/index.js b/app/models/index.js index ac4279a..f298a63 100644 --- a/app/models/index.js +++ b/app/models/index.js @@ -12,6 +12,7 @@ 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; if (config.use_env_variable) { diff --git a/development.env b/development.env index d14d427..b6295c9 100644 --- a/development.env +++ b/development.env @@ -3,6 +3,8 @@ DB_PASSWORD=Password for the database DB_NAME=Database name DB_PORT=Database port +SEQUELIZE_LOGGING=0- no sequelize logging, 1- log to the console + AMAZON_ACCES_KEY_ID=(your-key-here) AMAZON_SECRET_ACCESS_KEY=(your-key-here) AMAZON_REGION=eu-west-1 From 1d29f6c8ac01a4121544567edca339ca8001368b Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Thu, 5 Sep 2019 14:24:29 +0200 Subject: [PATCH 4/7] change how APP_URL is used, use JS templating string --- app/config/appConfig.js | 9 +++++ app/helpers/awsEmail.js | 81 +++++++++++++++++------------------------ development.env | 3 ++ index.js | 7 ++-- 4 files changed, 50 insertions(+), 50 deletions(-) create mode 100644 app/config/appConfig.js diff --git a/app/config/appConfig.js b/app/config/appConfig.js new file mode 100644 index 0000000..57b42df --- /dev/null +++ b/app/config/appConfig.js @@ -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 +}; diff --git a/app/helpers/awsEmail.js b/app/helpers/awsEmail.js index 24544d6..6c3edef 100644 --- a/app/helpers/awsEmail.js +++ b/app/helpers/awsEmail.js @@ -1,3 +1,4 @@ +const { APP_URL } = require("../config/appConfig"); const { getRealEstateTypeEnum } = require("./enums"); const { getRegionName, getMunicipalityName } = require("./codes"); const { allRERequestByUiid } = require("./db/dbHelper"); @@ -82,15 +83,15 @@ const getGreetingsEmailHTML = realestateRequest => {
-
Ako želis prestati dobijati obavještenja za ovu pretragu klikni ${ - process.env.APP_URL - }/odjava/${realestateRequest.uniqueId}
-
Ako želiš promijeniti uslove pretrage klikni ${ - process.env.APP_URL - }/pregled/${realestateRequest.uniqueId}
-

Tvoj, -Javimi tim. -

`; +
Ako želis prestati dobijati obavještenja za ovu pretragu klikni ${APP_URL}/odjava/${ + realestateRequest.uniqueId + }
+
Ako želiš promijeniti uslove pretrage klikni ${APP_URL}/pregled/${ + realestateRequest.uniqueId + }
+

Tvoj, + Javimi tim. +

`; }; const getGreetingsEmaiTextVersion = realestateRequest => { @@ -98,40 +99,27 @@ const getGreetingsEmaiTextVersion = realestateRequest => { realestateRequest.realEstateType ); const gardenSize = realEstateType.hasGardenSize - ? "Kvadratura okućnice od " + - realestateRequest.gardenSizeMin + - " do " + - realestateRequest.gardenSizeMax + ? `Kvadratura okućnice od ${realestateRequest.gardenSizeMin} do ${realestateRequest.gardenSizeMax}` : ""; - const text = - "Zdravo, \n Naručio/la si da ti javimo ako se nekretnina pojavi u oglasima \n Ovo je tražena nekretnina: \n , Tip nekretnine: " + - realestateRequest.realEstateType + - "\n Područje" + - getRegionName(realestateRequest.region) + - "\n Mjesto " + - getMunicipalityName( - realestateRequest.region, - realestateRequest.municipality - ) + - "\n Kvadratura nekretnine Od " + - realestateRequest.sizeMin + - " do " + - realestateRequest.sizeMaX + - +gardenSize; - "\n Cijena od " + - realestateRequest.priceMin + - " do " + - 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"; + const text = `Zdravo, \n Naručio/la si da ti javimo ako se nekretnina pojavi u oglasima + \n Ovo je tražena nekretnina: \n , Tip nekretnine: ${ + realestateRequest.realEstateType + } \n Područje ${getRegionName( + realestateRequest.region + )} \n Mjesto ${getMunicipalityName( + realestateRequest.region, + realestateRequest.municipality + )} + \n Kvadratura nekretnine Od ${realestateRequest.sizeMin} do ${ + realestateRequest.sizeMaX + } ${gardenSize} \n Cijena od ${realestateRequest.priceMin} do ${ + realestateRequest.priceMax + } \n Ako želis prestati dobijati obavještenja za ovu pretragu klikni + ${APP_URL}/odjava/${ + realestateRequest.uniqueId + }\n Ako želiš promijeniti uslove pretrage klikni + ${APP_URL}/odpregled/${realestateRequest.uniqueId}\n Tvoj,\n Javimi tim`; return text; }; @@ -162,7 +150,7 @@ const sendBulkEmail = async marketAlerts => { realEstateType: RERequest.realEstateType, region: RERequest.region, municipality: RERequest.municipality, - requestUrl: `${process.env.APP_URL}/nekretnine/${RERequest.uniqueId}` + requestUrl: `${APP_URL}/nekretnine/${RERequest.uniqueId}` }; }); @@ -233,8 +221,7 @@ const sendBulkEmail = async marketAlerts => { } }; -const redirectUrl = marketAlertId => - `${process.env.APP_URL}/redirect/${marketAlertId}`; +const redirectUrl = marketAlertId => `${APP_URL}/redirect/${marketAlertId}`; const toAWSArray = urlArray => { let arrayString = ""; urlArray.forEach(element => { @@ -247,11 +234,11 @@ const toAWSArray = urlArray => { }; const getNotificationEmailHtml = () => { - return `

Zdravo, + return `

Zdravo, Pronašli smo nekretninu koju ste tražili.

-

Ovo su tražene nekretnine:

+

Ovo su tražene nekretnine:

-
{{#each marketAlertUrl}}
  • {{title}}

  • {{/each}}
    +
    {{#each marketAlertUrl}}
  • {{title}}

  • {{/each}}
    Kompletan spisak nekretnina možete pegledati ovdije: Nekretnine
    `; diff --git a/development.env b/development.env index b6295c9..820ad3c 100644 --- a/development.env +++ b/development.env @@ -5,6 +5,9 @@ DB_PORT=Database port 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 diff --git a/index.js b/index.js index 39d4049..e572fc0 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ require("dotenv").config(); +const { APP_PORT } = require("./app/config/appConfig"); const welcome = require("./app/controllers/welcome").getWelcome; const { @@ -50,8 +51,6 @@ const app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); -const port = process.env.PORT || 5000; - app.set("views", path.join(__dirname, "/app/views")); app.set("view engine", "ejs"); app.use(layout()); @@ -182,7 +181,9 @@ app.get("/redirect/:id", redirect); 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(); rule.seccond = 1; From b0f9c2c47bb45bdd262fdd3e0058a7544ed26163 Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Fri, 6 Sep 2019 12:01:25 +0200 Subject: [PATCH 5/7] remove all logging noise --- app/controllers/realEstates.js | 3 - app/helpers/awsEmail.js | 4 - app/helpers/crawlers/olxClawler.js | 657 +++++++++++----------- app/services/crawlerService.js | 16 - app/services/notificationService.js | 6 - tools/kantoni.html | 819 +++++++++++++++------------- 6 files changed, 753 insertions(+), 752 deletions(-) diff --git a/app/controllers/realEstates.js b/app/controllers/realEstates.js index 1533159..24c05de 100644 --- a/app/controllers/realEstates.js +++ b/app/controllers/realEstates.js @@ -1,11 +1,8 @@ const { allMarketAlertsByRequest } = require("../helpers/db/dbHelper"); const getRealEstates = async (req, res) => { - console.log("Enter get realestates"); 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"; res.render("realEstates", { realEstates, title }); diff --git a/app/helpers/awsEmail.js b/app/helpers/awsEmail.js index 6c3edef..9466698 100644 --- a/app/helpers/awsEmail.js +++ b/app/helpers/awsEmail.js @@ -198,8 +198,6 @@ const sendBulkEmail = async marketAlerts => { ReplacementTemplateData: repData }); } - console.log("AWS EMAIL : Bulk email replacement data:"); - console.log(destinations); var params = { Destinations: destinations, @@ -214,8 +212,6 @@ const sendBulkEmail = async marketAlerts => { .sendBulkTemplatedEmail(params) .promise(); const awsResult = await sendPromise; - console.log("AWS SES bulk email response"); - console.log(awsResult); } catch (e) { console.log("Could not send bulk email", e); } diff --git a/app/helpers/crawlers/olxClawler.js b/app/helpers/crawlers/olxClawler.js index 139b30b..90e1543 100644 --- a/app/helpers/crawlers/olxClawler.js +++ b/app/helpers/crawlers/olxClawler.js @@ -1,375 +1,364 @@ -const fetch = require('node-fetch'); -const cheerio = require('cheerio'); -const { allRERequest, findPointInsideBoundingBox } = require('../db/dbHelper'); -const { getRealEstateTypeEnum } = require('../enums'); -const { getRegion, getMunicipality } = require('../codes') +const fetch = require("node-fetch"); +const cheerio = require("cheerio"); +const { allRERequest, findPointInsideBoundingBox } = require("../db/dbHelper"); +const { getRealEstateTypeEnum } = require("../enums"); +const { getRegion, getMunicipality } = require("../codes"); const Promise = require("bluebird"); module.exports = class OlxCrawler { - //TODO figure best way to handle paging - constructor(hrefs = []) { - this.hrefs = hrefs; - } + //TODO figure best way to handle paging + constructor(hrefs = []) { + this.hrefs = hrefs; + } - async indexPages(urls) { - const indexers = []; + async indexPages(urls) { + const indexers = []; - urls.forEach(url => { - indexers.push(new Indexer(url)); - }); + urls.forEach(url => { + indexers.push(new Indexer(url)); + }); - return Promise.map(indexers, function (indexer) { - return indexer.indexWithPagination(); - }).then(async (results) => { - return results - }) - } + return Promise.map(indexers, function(indexer) { + return indexer.indexWithPagination(); + }).then(async results => { + return results; + }); + } - async crawl() { - console.log("OLX CRAWLER: start crawl"); + async 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 = []; - const realestateRequests = await allRERequest(); - console.log("OLX CRAWLER: found " + realestateRequests.length + "subscribed RealEstateRequests"); - const urls = this.createRequestUrls(realestateRequests); - let results = await this.indexPages(urls, this.fromPage, this.toPage, this.maxResults); - console.log("Final crawler results"); - 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); - } - } - } + 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) { - 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; - } + return urls; + } }; - 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 + */ - /** - * - * @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; + this.hrefResutls = hrefResutls; + } - constructor(olxUrl, hrefResutls) { - this.olxUrl = olxUrl; - this.hrefResutls = hrefResutls; - } + async indexWithPagination(pageNumber = 1) { + const pageNr = this.olxUrl.url.match(/\d+$/); + 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); - const pageNr = this.olxUrl.url.match(/\d+$/); - const indexers = this.prepareIndexers(pageNumber ? [pageNumber] : pageNr); + results.forEach(result => { + if (!hasResults) { + hasResults = result.hasResults; + } + }); - try { + if (!hasResults) { + const singlePageIndexers = this.prepareHrefIndexers(results); + if (singlePageIndexers.length === 0) { + return []; + } - return Promise.map(indexers.indexers, function (indexer) { - return indexer.indexPage(pageNumber); - }).then(async (results) => { - let hasResults = false; - - 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)); - - } + return Promise.map(singlePageIndexers, function(indexer) { + return indexer.indexSingle(); + }).then(async results => { + return results; + }); } 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)); - } + 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 => { + return results; + }); + + Array.prototype.push.apply(newResults, newerResults); + return newResults; } - return { - indexers: indexers, - lastPageNumber: lastPageNumber + }); + } catch (e) { + 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) { - const indexers = [] + prepareHrefIndexers(results) { + const indexers = []; - if (!Array.isArray(results)) { - results.hrefs.forEach(href => { - const newOlxUrl = { - url: href, - email: results.olxUrl.email, - uuid: results.olxUrl.uuid, - hrefs: this.olxUrl.hrefs - } + if (!Array.isArray(results)) { + results.hrefs.forEach(href => { + const newOlxUrl = { + url: href, + email: results.olxUrl.email, + uuid: results.olxUrl.uuid, + hrefs: this.olxUrl.hrefs + }; - indexers.push(new Indexer(newOlxUrl)); - }); - - } else { - - - results.forEach(result => { - - if (result !== null && result.hasOwnProperty('hrefs')) { - result.hrefs.forEach(href => { - const newOlxUrl = { - 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)], + indexers.push(new Indexer(newOlxUrl)); + }); + } else { + results.forEach(result => { + if (result !== null && result.hasOwnProperty("hrefs")) { + result.hrefs.forEach(href => { + const newOlxUrl = { + url: href, + email: result.olxUrl.email, + uuid: result.olxUrl.uuid, + hrefs: this.olxUrl.hrefs }; - return data; - } catch (e) { - console.error('Exception caught: ' + e.message); + indexers.push(new Indexer(newOlxUrl)); + }); } + }); + } + 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; + } + // } + + 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) { - case 'Stanovi': - return 'stan'; + getCategoryId(category) { + switch (category) { + case "Stanovi": + return "stan"; - case 'Vikendice': - return 'vikendica' + case "Vikendice": + return "vikendica"; - case 'Kuće': - return 'kuca'; + case "Kuće": + return "kuca"; - default: - return ''; - } + default: + return ""; } + } } - diff --git a/app/services/crawlerService.js b/app/services/crawlerService.js index aaae6f7..1de43b8 100644 --- a/app/services/crawlerService.js +++ b/app/services/crawlerService.js @@ -4,8 +4,6 @@ const db = require("../models/index"); const { allMarketAlerts } = require("../helpers/db/dbHelper"); async function crawlAll() { - console.log("CRAWLER SERVICE: crawlAll"); - try { const marketAlertsFromDb = await allMarketAlerts(true); const hrefs = []; @@ -18,8 +16,6 @@ async function crawlAll() { hrefs[marketAlert.request].push(marketAlert.url); }); - console.log("CRAWLER SERVICE: GLOBAL HREFS"); - console.log(hrefs); const olxCrawler = new OlxCrawler(hrefs); const crawlers = [olxCrawler]; @@ -30,11 +26,6 @@ async function crawlAll() { try { const marketAlertsFromDb = await allMarketAlerts(false, true); - console.log( - "CRAWLER SERVICE: number of existing MarketAlerts from db: " + - marketAlertsFromDb.length - ); - const marketAlerts = []; const mergedResults = [].concat.apply([], results); @@ -56,9 +47,6 @@ async function crawlAll() { hasLocation: result.hasLocation }); } - console.log( - "CRAWLER SERVICE: Number of crawler results: " + marketAlerts.length - ); try { const filteredMarketAlerts = marketAlerts.filter( @@ -67,10 +55,6 @@ async function crawlAll() { 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) { diff --git a/app/services/notificationService.js b/app/services/notificationService.js index b49de5d..e5625ca 100644 --- a/app/services/notificationService.js +++ b/app/services/notificationService.js @@ -8,15 +8,9 @@ const { async function processNotifications() { try { const marketAlerts = await allMarketAlerts(false, false); - console.log(marketAlerts.length); await createMarketAlertEmailTemplate(); 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( diff --git a/tools/kantoni.html b/tools/kantoni.html index e0a4091..2d28d98 100644 --- a/tools/kantoni.html +++ b/tools/kantoni.html @@ -1,389 +1,430 @@ - - - - - - - - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - -
    - - - Mjesto - - -
    - - - - - - + + + + + + + + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + +
    + + Mjesto + + +
    + + + + From 68c69144a2a39a98d88a413951b550efd71b6915 Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Fri, 6 Sep 2019 12:25:34 +0200 Subject: [PATCH 6/7] fix scheduler execution rule --- index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index e572fc0..b9ea96c 100644 --- a/index.js +++ b/index.js @@ -185,8 +185,9 @@ app.listen(APP_PORT, () => console.log(`Example app listening on port ${APP_PORT}!`) ); -var rule = new schedule.RecurrenceRule(); -rule.seccond = 1; +//TODO: based on node-schedule package author, setInterval is better suited for this kind of the job +const rule = new schedule.RecurrenceRule(); +rule.second = 1; schedule.scheduleJob(rule, async function() { console.log(new Date(), "Crawler service started"); await crawlAll(); From 87b79f39389746e262cd7169443837e7882af181 Mon Sep 17 00:00:00 2001 From: Bilal Catic Date: Sat, 7 Sep 2019 00:36:47 +0200 Subject: [PATCH 7/7] fix region and municipality OLX ids --- app/helpers/codes.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/helpers/codes.js b/app/helpers/codes.js index 815c4d6..ac589d4 100644 --- a/app/helpers/codes.js +++ b/app/helpers/codes.js @@ -54,7 +54,7 @@ const regions = [ { name: " Unsko-sanski", id: "unskosanski", - olxid: "9", + olxid: "1", municipalities: [ { name: "Bihać", @@ -101,7 +101,7 @@ const regions = [ { name: " Posavski", id: "posavski", - olxid: "15", + olxid: "2", municipalities: [ { name: "Domaljevac", @@ -128,7 +128,7 @@ const regions = [ { name: " Tuzlanski", id: "tuzlanski", - olxid: "15", + olxid: "3", municipalities: [ { name: "Banovići", @@ -200,7 +200,7 @@ const regions = [ { name: " Zeničko-dobojski", id: "zenickodobojski", - olxid: "15", + olxid: "4", municipalities: [ { name: "Breza", @@ -267,7 +267,7 @@ const regions = [ { name: " Bosansko-podrinjski", id: "bosanskopodrinjski", - olxid: "15", + olxid: "5", municipalities: [ { name: "Foča", @@ -865,7 +865,7 @@ const regions = [ { name: "Brčko", id: "brko", - olxid: "12" + olxid: "645" } ] }