diff --git a/app/controllers/neighborhoodMap.js b/app/controllers/location.js similarity index 59% rename from app/controllers/neighborhoodMap.js rename to app/controllers/location.js index f3a8e22..185bee9 100644 --- a/app/controllers/neighborhoodMap.js +++ b/app/controllers/location.js @@ -1,28 +1,42 @@ const { currentRERequest } = require("../helpers/url"); -const getNeighborhood = async (req, res) => { +const getLocation = async (req, res) => { const title = "U kojem naselju tražite nekretninu?"; - const municipality = req.params.municipality; const nextStep = req.query.nextStep || "/"; - res.render("neighborhoodMap", { + res.render("location", { nextStep, - municipality, title }); }; -const postNeighborhood = async (req, res) => { +const postLocation = 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]; - request.bounding_box = { + request.locationInput = + req.body.locationInput && req.body.locationInput.length > 0 + ? req.body.locationInput + : null; + + request.boundingBox = { type: "Polygon", coordinates: [[northWest, northEast, southEast, southWest, northWest]] }; + + let locationInputData; + if (req.body.locationInputData) { + try { + locationInputData = JSON.parse(req.body.locationInputData); + } catch (e) { + locationInputData = null; + } + } + await request.save(); const nextStepPage = req.query.nextStep || "povrsina"; @@ -32,6 +46,6 @@ const postNeighborhood = async (req, res) => { }; module.exports = { - getNeighborhood, - postNeighborhood + getLocation, + postLocation }; diff --git a/app/controllers/municipalities.js b/app/controllers/municipalities.js deleted file mode 100644 index 0950a43..0000000 --- a/app/controllers/municipalities.js +++ /dev/null @@ -1,34 +0,0 @@ -const { currentRERequest } = require("../helpers/url"); -const { - getMunicipalitiesForRegion, - getMunicipalityName -} = require("../helpers/codes"); - -const getMunicipality = async (req, res) => { - const title = "U kojem mjestu tražite nekretninu?"; - let request = await currentRERequest(req); - const municipalities = getMunicipalitiesForRegion(request.region); - - 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}`; - - request.municipality = req.body.municipality; - await request.save(); - - res.redirect(nextStepUrl); -}; - -module.exports = { - getMunicipality, - postMunicipality -}; diff --git a/app/controllers/queryReview.js b/app/controllers/queryReview.js index fd1c40e..e0ec70b 100644 --- a/app/controllers/queryReview.js +++ b/app/controllers/queryReview.js @@ -1,10 +1,6 @@ const { currentRERequest } = require("../helpers/url"); -const { getRegionName, getMunicipalityName } = require("../helpers/codes"); const { realEstateTypes, - sizes, - gardenSizes, - prices, getEnumTypeTitle, getRealEstateTypeEnum } = require("../helpers/enums"); @@ -20,14 +16,13 @@ const getQueryReview = async (req, res) => { const { realEstateType, - region, - municipality, sizeMin, sizeMax, gardenSizeMin, gardenSizeMax, priceMin, - priceMax + priceMax, + locationInput } = request.dataValues; const realEstateTypeObject = getRealEstateTypeEnum(realEstateType); @@ -38,9 +33,9 @@ const getQueryReview = async (req, res) => { const realEstateTypeTitle = realEstateType ? getEnumTypeTitle(realEstateTypes, realEstateType) : null; - const regionName = region ? getRegionName(region) : null; - const municipalityName = - region && municipality ? getMunicipalityName(region, municipality) : null; + + const locationTitle = locationInput ? locationInput : "-"; + const sizeTitle = sizeMin ? sizeMin + "-" + sizeMax + " m2" : null; const gardenSizeTitle = gardenSizeMin ? gardenSizeMin + "-" + gardenSizeMax + " m2" @@ -58,14 +53,9 @@ const getQueryReview = async (req, res) => { url: `/vrstanekretnine/${uniqueId}?nextStep=pregled` }, { - id: "region", - title: regionName, - url: `/grad/${uniqueId}?nextStep=mjesto` - }, - { - id: "municipality", - title: municipalityName, - url: `/mjesto/${uniqueId}?nextStep=pregled` + id: "location", + title: locationTitle, + url: `/lokacija/${uniqueId}?nextStep=pregled` }, { id: "size", diff --git a/app/controllers/realEstateTypes.js b/app/controllers/realEstateTypes.js index afefa0f..853b693 100644 --- a/app/controllers/realEstateTypes.js +++ b/app/controllers/realEstateTypes.js @@ -11,7 +11,7 @@ const getRealEstateTypes = (req, res) => { const postRealEstateTypes = async (req, res) => { const request = await currentRERequest(req); - const nextStepPage = req.query.nextStep || "grad"; + const nextStepPage = req.query.nextStep || "lokacija"; if (request && request.uniqueId) { const nextStepUrl = `/${nextStepPage}/${request.uniqueId}`; diff --git a/app/controllers/regions.js b/app/controllers/regions.js deleted file mode 100644 index 025c539..0000000 --- a/app/controllers/regions.js +++ /dev/null @@ -1,28 +0,0 @@ -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 postRegion = async (req, res) => { - const request = await currentRERequest(req); - - 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); -}; - -module.exports = { - getRegion, - postRegion -}; diff --git a/app/helpers/awsEmail.js b/app/helpers/awsEmail.js index 9466698..5e2b572 100644 --- a/app/helpers/awsEmail.js +++ b/app/helpers/awsEmail.js @@ -2,7 +2,7 @@ const { APP_URL } = require("../config/appConfig"); const { getRealEstateTypeEnum } = require("./enums"); const { getRegionName, getMunicipalityName } = require("./codes"); const { allRERequestByUiid } = require("./db/dbHelper"); -var AWS = require("aws-sdk"); +let AWS = require("aws-sdk"); const TEMPLATE_NAME = "MarketAlertTemplate"; AWS.config.update({ @@ -30,16 +30,12 @@ const sendTemplatedEmail = async (email, request) => { }, Text: { Charset: "UTF-8", - Data: getGreetingsEmaiTextVersion(request) + Data: getGreetingsEmailTextVersion(request) } }, Subject: { Charset: "UTF-8", - Data: `Javimi Potvrda: ${getSubject( - request.realEstateType, - request.region, - request.municipality - )}` + Data: `Javimi Potvrda: ${getSubject(request.realEstateType)}` } }, Source: process.env.SOURCE_EMAIL /* required */, @@ -52,12 +48,12 @@ const sendTemplatedEmail = async (email, request) => { await sendEmailPromise; }; -const getGreetingsEmailHTML = realestateRequest => { +const getGreetingsEmailHTML = realEstateRequest => { const realEstateType = getRealEstateTypeEnum( - realestateRequest.realEstateType + 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, @@ -65,63 +61,40 @@ const getGreetingsEmailHTML = realestateRequest => {

Ovo je tražena nekretnina:

Tip nekretnine: ${realEstateType.title}
-
Područje: ${getRegionName( - realestateRequest.region - )}
-
Mjesto: ${getMunicipalityName( - realestateRequest.region, - realestateRequest.municipality - )}
-
Kvadratura nekretnine: Od ${realestateRequest.sizeMin} do ${ - realestateRequest.sizeMax - } m2
+
Lokacija:
+
Kvadratura nekretnine: Od ${realEstateRequest.sizeMin} do ${realEstateRequest.sizeMax} m2
${gardenSize} -
Cijena: ${realestateRequest.priceMin} do ${ - realestateRequest.priceMax - } KM
+
Cijena: ${realEstateRequest.priceMin} do ${realEstateRequest.priceMax} KM
-
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 - }
+
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 => { +const getGreetingsEmailTextVersion = realEstateRequest => { const realEstateType = getRealEstateTypeEnum( - realestateRequest.realEstateType + 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 - ${APP_URL}/odjava/${ - realestateRequest.uniqueId - }\n Ako želiš promijeniti uslove pretrage klikni - ${APP_URL}/odpregled/${realestateRequest.uniqueId}\n Tvoj,\n Javimi tim`; - - return text; + return `Zdravo\nNaručio/la si da ti javimo ako se nekretnina pojavi u oglasima\n + Ovo je tražena nekretnina:\nTip nekretnine: ${realEstateRequest.realEstateType}\n + Lokacija nekretnine :\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`; }; const sendBulkEmail = async marketAlerts => { @@ -249,8 +222,7 @@ const createMarketAlertEmailTemplate = async () => { const marketAlertTemplate = { Template: { TemplateName: TEMPLATE_NAME, - SubjectPart: - "Javi mi obavijest: {{realestateType}}, {{region}}, {{municipality}}", + SubjectPart: "Javi mi obavijest: {{realestateType}}", TextPart: getNotificationEmailText(), HtmlPart: getNotificationEmailHtml() } @@ -266,10 +238,8 @@ const createMarketAlertEmailTemplate = async () => { } }; -const getSubject = (realEstateType, region, municipality) => { - return `${getRealEstateTypeEnum(realEstateType).title} ${getRegionName( - region - )}, ${getMunicipalityName(region, municipality)}`; +const getSubject = realEstateType => { + return getRealEstateTypeEnum(realEstateType).title; }; module.exports = { diff --git a/app/helpers/crawlers/olxClawler.js b/app/helpers/crawlers/olxClawler.js index 90e1543..d7007b7 100644 --- a/app/helpers/crawlers/olxClawler.js +++ b/app/helpers/crawlers/olxClawler.js @@ -27,8 +27,8 @@ module.exports = class OlxCrawler { async crawl() { const filteredResults = []; - const realestateRequests = await allRERequest(); - const urls = this.createRequestUrls(realestateRequests); + const realEstateRequests = await allRERequest(); + const urls = this.createRequestUrls(realEstateRequests); let results = await this.indexPages( urls, this.fromPage, @@ -65,24 +65,94 @@ module.exports = class OlxCrawler { return []; } - createRequestUrls(realestateRequests) { + 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; + for (const request of realEstateRequests) { + const { + realEstateType, + region, + sizeMin, + sizeMax, + priceMin, + priceMax + } = request; + + const urlRealEstateParams = [ + { + paramName: "kanton", + paramValue: region, + useParam: false + }, + { + paramName: "kategorija", + paramValue: getRealEstateTypeEnum(realEstateType).olxid, + useParam: true + }, + { + paramName: "kvadrata_min", + paramValue: sizeMin, + useParam: true + }, + { + paramName: "kvadrata_max", + paramValue: sizeMax, + useParam: true + }, + { + paramName: "od", + paramValue: priceMin, + useParam: true + }, + { + paramName: "do", + paramValue: priceMax, + useParam: true + } + ]; + const urlResultsParams = [ + { + paramName: "vrstapregleda", + paramValue: "tabela", + useParam: true + }, + { + paramName: "sort_order", + paramValue: "desc", + useParam: true + }, + { + paramName: "vrsta", + paramValue: "samoprodaja", + useParam: true + }, + { + paramName: "stranica", + paramValue: "0", + useParam: true + } + ]; + + const paramsReduceFunction = (accumulatedValue, currentParam) => { + const { paramName, paramValue, useParam } = currentParam; + if (useParam) { + return `${accumulatedValue}&${paramName}=${paramValue}`; + } else { + return accumulatedValue; + } + }; + + const reducedRealEstateParams = urlRealEstateParams.reduce( + paramsReduceFunction, + "" + ); + const reducedResultsParams = urlResultsParams.reduce( + paramsReduceFunction, + "" + ); 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=`, + url: `https://www.olx.ba/pretraga?${reducedRealEstateParams}${reducedResultsParams}`, email: request.email, uuid: request.uniqueId, hrefs: this.hrefs @@ -313,9 +383,10 @@ class Indexer { const parsedPrice = parsePrice(price); - const locationArray = location.split(","); - const region = locationArray[0]; - const municipality = locationArray[1]; + const locationArray = + location && location.length > 0 ? location.split(",") : []; + const region = locationArray.length > 0 ? locationArray[0] : ""; + const municipality = locationArray.length > 1 ? locationArray[1] : ""; const data = { realEstateType: this.getCategoryId(realEstateType), diff --git a/app/helpers/db/dbHelper.js b/app/helpers/db/dbHelper.js index b606cbb..d5288be 100644 --- a/app/helpers/db/dbHelper.js +++ b/app/helpers/db/dbHelper.js @@ -90,7 +90,7 @@ const getMarketAlertById = async id => { */ const findPointInsideBoundingBox = async (latLng, email, uniqueId) => { return await db.sequelize.query( - `SELECT * FROM "RealEstateRequests" WHERE email = '${email}' AND "uniqueId" = '${uniqueId}' AND subscribed = true AND ST_Contains("RealEstateRequests".bounding_box, ST_GEOMFROMTEXT('POINT (${ + `SELECT * FROM "RealEstateRequests" WHERE email = '${email}' AND "uniqueId" = '${uniqueId}' AND subscribed = true AND ST_Contains("RealEstateRequests"."boundingBox", ST_GEOMFROMTEXT('POINT (${ latLng[0] } ${latLng[1]})'))` ); diff --git a/app/helpers/enums.js b/app/helpers/enums.js index 91c243d..93f1f6f 100644 --- a/app/helpers/enums.js +++ b/app/helpers/enums.js @@ -1,7 +1,7 @@ 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, olxid: 24 }, + { title: "Stan", id: "stan", hasGardenSize: false, olxid: 23 }, + { title: "Vikendica", id: "vikendica", hasGardenSize: true, olxid: 26 } ]; const sizes = [ diff --git a/app/helpers/url.js b/app/helpers/url.js index 78036c5..10512ff 100644 --- a/app/helpers/url.js +++ b/app/helpers/url.js @@ -4,8 +4,7 @@ const currentRERequest = async req => { const uniqueId = req.params["request_id"]; if (!uniqueId) return null; - const request = await db.RealEstateRequest.findOne({ where: { uniqueId } }); - return request; + return await db.RealEstateRequest.findOne({ where: { uniqueId } }); }; module.exports = { currentRERequest diff --git a/app/migrations/20190909110623-add-location-input-to-real-estate-request.js b/app/migrations/20190909110623-add-location-input-to-real-estate-request.js new file mode 100644 index 0000000..62b4f3a --- /dev/null +++ b/app/migrations/20190909110623-add-location-input-to-real-estate-request.js @@ -0,0 +1,13 @@ +"use strict"; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.addColumn("RealEstateRequests", "locationInput", { + type: Sequelize.STRING + }); + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.removeColumn("RealEstateRequests", "locationInput"); + } +}; diff --git a/app/migrations/20190910033923-change-bounding-box-from-snake-case-to-camel-case.js b/app/migrations/20190910033923-change-bounding-box-from-snake-case-to-camel-case.js new file mode 100644 index 0000000..1c77e5d --- /dev/null +++ b/app/migrations/20190910033923-change-bounding-box-from-snake-case-to-camel-case.js @@ -0,0 +1,19 @@ +"use strict"; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.renameColumn( + "RealEstateRequests", + "bounding_box", + "boundingBox" + ); + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.renameColumn( + "RealEstateRequests", + "boundingBox", + "bounding_box" + ); + } +}; diff --git a/app/models/realestaterequest.js b/app/models/realestaterequest.js index 8cedce9..b4671b8 100644 --- a/app/models/realestaterequest.js +++ b/app/models/realestaterequest.js @@ -19,8 +19,9 @@ module.exports = (sequelize, DataTypes) => { gardenSizeMax: DataTypes.INTEGER, priceMin: DataTypes.INTEGER, priceMax: DataTypes.INTEGER, - bounding_box: DataTypes.GEOMETRY("POINT", 4326), - subscribed: DataTypes.BOOLEAN + boundingBox: DataTypes.GEOMETRY("POINT", 4326), + subscribed: DataTypes.BOOLEAN, + locationInput: DataTypes.STRING }, {} ); diff --git a/app/views/location.ejs b/app/views/location.ejs new file mode 100644 index 0000000..0f8f7f8 --- /dev/null +++ b/app/views/location.ejs @@ -0,0 +1,121 @@ +<% include partials/navBar %> + +
+
+ +
+
+ gps_fixed +
+
+
+
+ +
+
+
+ Dalje +
+
+ + + + + + +
+ + + diff --git a/app/views/municipality.ejs b/app/views/municipality.ejs deleted file mode 100644 index aae8813..0000000 --- a/app/views/municipality.ejs +++ /dev/null @@ -1,26 +0,0 @@ - -<% include partials/navBar %> - -
-
- - -
-
- - diff --git a/app/views/neighborhoodMap.ejs b/app/views/neighborhoodMap.ejs deleted file mode 100644 index e8cf5fd..0000000 --- a/app/views/neighborhoodMap.ejs +++ /dev/null @@ -1,127 +0,0 @@ -<% include partials/navBar %> - -
-
- - -
-
-
-
-
- -
- - - - -
- - - \ No newline at end of file diff --git a/app/views/region.ejs b/app/views/region.ejs deleted file mode 100644 index a5c4a40..0000000 --- a/app/views/region.ejs +++ /dev/null @@ -1,27 +0,0 @@ - -<% include partials/navBar %> - -
-
- - -
-
- - - diff --git a/index.js b/index.js index b9ea96c..b08652d 100644 --- a/index.js +++ b/index.js @@ -6,11 +6,6 @@ const { getRealEstateTypes, postRealEstateTypes } = require("./app/controllers/realEstateTypes"); -const { getRegion, postRegion } = require("./app/controllers/regions"); -const { - getMunicipality, - postMunicipality -} = require("./app/controllers/municipalities"); const { getSize, postSize } = require("./app/controllers/sizes"); const { getGardenSize, @@ -26,10 +21,7 @@ const { postQuerySubmit } = require("./app/controllers/querySubmit"); const { getGoAgain } = require("./app/controllers/goAgain"); -const { - getNeighborhood, - postNeighborhood -} = require("./app/controllers/neighborhoodMap"); +const { getLocation, postLocation } = require("./app/controllers/location"); const { getUnsubscribe } = require("./app/controllers/unsubscribe"); const { getRealEstates } = require("./app/controllers/realEstates"); const { redirect } = require("./app/controllers/redirect"); @@ -147,14 +139,8 @@ app.get("/vrstanekretnine", getRealEstateTypes); app.post("/vrstanekretnine/:request_id", postRealEstateTypes); app.post("/vrstanekretnine", postRealEstateTypes); -app.get("/grad/:request_id", getRegion); -app.post("/grad/:request_id", postRegion); - -app.get("/mjesto/:request_id", getMunicipality); -app.post("/mjesto/:request_id", postMunicipality); - -app.get("/naselje/:request_id/:municipality", getNeighborhood); -app.post("/naselje/:request_id/:municipality", postNeighborhood); +app.get("/lokacija/:request_id", getLocation); +app.post("/lokacija/:request_id", postLocation); app.get("/povrsina/:request_id", getSize); app.post("/povrsina/:request_id", postSize);