diff --git a/app/common/enums.js b/app/common/enums.js index b7a650c..b488b21 100644 --- a/app/common/enums.js +++ b/app/common/enums.js @@ -4,12 +4,13 @@ const AD_TYPE = { }; const AD_CATEGORY = { - CATEGORY_FLAT: "FLAT", - CATEGORY_HOUSE: "HOUSE", - CATEGORY_OFFICE: "OFFICE", - CATEGORY_LAND: "LAND", - CATEGORY_APARTMENT: "APARTMENT", - CATEGORY_GARAGE: "GARAGE" + FLAT: { id: "FLAT", title: "Stan", hasGardenSize: false }, + HOUSE: { id: "HOUSE", title: "Kuća", hasGardenSize: true }, + //OFFICE: { id: "OFFICE", title: "Kancelarija", hasGardenSize: false }, + //LAND: { id: "LAND", title: "Zemljište", hasGardenSize: true }, + APARTMENT: { id: "APARTMENT", title: "Apartman", hasGardenSize: false } + //GARAGE: { id: "GARAGE", title: "Garaža", hasGardenSize: false }, + //COTTAGE: { id: "COTTAGE", title: "Vikendica", hasGardenSize: true } }; const AD_STATUS = { diff --git a/app/config/appConfig.js b/app/config/appConfig.js index 288ee24..c56f93b 100644 --- a/app/config/appConfig.js +++ b/app/config/appConfig.js @@ -1,3 +1,6 @@ +"use strict"; +require("dotenv").config({ path: __dirname + "/./../../.env" }); + const APP_PORT = process.env.PORT || 5000; const APP_BASE_URL = process.env.APP_BASE_URL || "http://localhost"; @@ -11,10 +14,24 @@ const DEFAULT_TIMEZONE = "Europe/Sarajevo"; const CRAWLER_INTERVAL = parseInt(process.env.CRAWLER_INTERVAL) || 60; const STOP_CRAWLER = !!parseInt(process.env.STOP_CRAWLER); +const AWS_EMAIL_CONFIG = { + REGION: process.env.AWS_REGION || "", + CREDENTIALS: { + ACCESS_KEY_ID: process.env.AWS_KEY_ID || "", + SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || "" + }, + SOURCE_EMAIL: process.env.SOURCE_EMAIL || "" +}; + +const MAX_REAL_ESTATES_IN_EMAIL = + parseInt(process.env.MAX_REAL_ESTATES_IN_EMAIL) || 10; + module.exports = { APP_PORT, APP_URL, DEFAULT_TIMEZONE, CRAWLER_INTERVAL, - STOP_CRAWLER + STOP_CRAWLER, + AWS_EMAIL_CONFIG, + MAX_REAL_ESTATES_IN_EMAIL }; diff --git a/app/controllers/gardenSizes.js b/app/controllers/gardenSizes.js index 4fb5c8e..221e5a0 100644 --- a/app/controllers/gardenSizes.js +++ b/app/controllers/gardenSizes.js @@ -1,5 +1,5 @@ const { currentSearchRequest } = require("../helpers/url"); -const { getRealEstateTypeEnum } = require("../helpers/enums"); +const { AD_CATEGORY } = require("../common/enums"); const getGardenSize = (req, res) => { const title = "Koliko okućnice tražite ?"; @@ -28,7 +28,7 @@ const postGardenSize = async (req, res) => { const nextStepPage = req.query.nextStep || "cijena"; const nextStepUrl = `/${nextStepPage}/${searchRequest.id}`; - const realEstateType = getRealEstateTypeEnum(searchRequest.realEstateType); + const realEstateType = AD_CATEGORY[searchRequest.realEstateType]; if (realEstateType && realEstateType.hasGardenSize) { const gardenSizeMin = req.body.from || 0; const gardenSizeMax = req.body.to || 0; diff --git a/app/controllers/queryReview.js b/app/controllers/queryReview.js index ac4bd1f..6ea8bd8 100644 --- a/app/controllers/queryReview.js +++ b/app/controllers/queryReview.js @@ -1,9 +1,5 @@ const { currentSearchRequest } = require("../helpers/url"); -const { - realEstateTypes, - getEnumTypeTitle, - getRealEstateTypeEnum -} = require("../helpers/enums"); +const { AD_CATEGORY } = require("../common/enums"); const getQueryReview = async (req, res) => { const title = "Da li je ovo to što ste tražili ?"; @@ -25,13 +21,13 @@ const getQueryReview = async (req, res) => { priceMax } = searchRequest.dataValues; - const realEstateTypeObject = getRealEstateTypeEnum(realEstateType); + const realEstateTypeObject = AD_CATEGORY[realEstateType]; const enableGardenSizeEdit = realEstateTypeObject ? realEstateTypeObject.hasGardenSize : false; - const realEstateTypeTitle = realEstateType - ? getEnumTypeTitle(realEstateTypes, realEstateType) + const realEstateTypeTitle = realEstateTypeObject + ? realEstateTypeObject.title : "-"; const locationTitle = "Location description - PLACEHOLDER"; diff --git a/app/controllers/querySubmit.js b/app/controllers/querySubmit.js index 1768575..ecdeca1 100644 --- a/app/controllers/querySubmit.js +++ b/app/controllers/querySubmit.js @@ -1,6 +1,8 @@ const { currentSearchRequest } = require("../helpers/url"); const { isValidEmail } = require("../helpers/email"); -const { sendTemplatedEmail } = require("../helpers/awsEmail"); +const { + notifyForNewSearchRequest +} = require("../services/notificationService"); const getQuerySubmit = async (req, res) => { const title = "Upišite vaš e-mail"; @@ -42,7 +44,8 @@ const postQuerySubmit = async (req, res) => { searchRequest.subscribed = true; await searchRequest.save(); - sendTemplatedEmail(emailInput, searchRequest); + await notifyForNewSearchRequest(searchRequest); + res.redirect(nextStep); }; diff --git a/app/controllers/realEstateTypes.js b/app/controllers/realEstateTypes.js index 7b84247..3b5f864 100644 --- a/app/controllers/realEstateTypes.js +++ b/app/controllers/realEstateTypes.js @@ -1,10 +1,13 @@ const { currentSearchRequest } = require("../helpers/url"); const { createSearchRequest } = require("../helpers/db/searchRequest"); -const { realEstateTypes, getRealEstateTypeEnum } = require("../helpers/enums"); +const { AD_CATEGORY } = require("../common/enums"); const getRealEstateTypes = (req, res) => { const title = "Koju nekretninu tražite?"; + const realEstateTypes = Object.keys(AD_CATEGORY).map( + category => AD_CATEGORY[category] + ); res.render("realEstateType", { realEstateTypes, title }); }; diff --git a/app/controllers/realEstates.js b/app/controllers/realEstates.js index 24c05de..ce82765 100644 --- a/app/controllers/realEstates.js +++ b/app/controllers/realEstates.js @@ -1,10 +1,13 @@ -const { allMarketAlertsByRequest } = require("../helpers/db/dbHelper"); +"use strict"; +const { + findRealEstatesForSearchRequest +} = require("../helpers/db/searchRequestMatch"); const getRealEstates = async (req, res) => { - const request = req.params["request_id"]; - const realEstates = await allMarketAlertsByRequest(request); + const searchRequestId = req.params["searchRequestId"] || ""; + const realEstates = await findRealEstatesForSearchRequest(searchRequestId); - const title = "Ovo su nekretnine koje smo pronašli za vas"; + const title = "Nekretnine koje odgovaraju Vašim uslovima pretrage"; res.render("realEstates", { realEstates, title }); }; diff --git a/app/controllers/redirect.js b/app/controllers/redirect.js index b52a51e..6cf5d35 100644 --- a/app/controllers/redirect.js +++ b/app/controllers/redirect.js @@ -1,8 +1,8 @@ -const { getMarketAlertById } = require("../helpers/db/dbHelper"); +const { getRealEstateById } = require("../helpers/db/realEstate"); const redirect = async (req, res) => { const id = req.params["id"]; - const marketAlert = await getMarketAlertById(id); + const marketAlert = await getRealEstateById(id); if (marketAlert) { res.redirect(marketAlert.url); } else { diff --git a/app/controllers/sizes.js b/app/controllers/sizes.js index 8c2c843..288410c 100644 --- a/app/controllers/sizes.js +++ b/app/controllers/sizes.js @@ -1,5 +1,5 @@ const { currentSearchRequest } = require("../helpers/url"); -const { sizes, getRealEstateTypeEnum } = require("../helpers/enums"); +const { AD_CATEGORY } = require("../common/enums"); const getSize = (req, res) => { const title = "Od koliko kvadrata tražite nekretninu ?"; @@ -24,7 +24,7 @@ const getSize = (req, res) => { const postSize = async (req, res) => { const searchRequest = await currentSearchRequest(req); - const realEstateType = getRealEstateTypeEnum(searchRequest.realEstateType); + const realEstateType = AD_CATEGORY[searchRequest.realEstateType]; const sizeMin = req.body.from || 0; const sizeMax = req.body.to || 0; //TODO: Validation, check if real estate type is valid, ... diff --git a/app/crawler/crawl.js b/app/crawler/crawl.js index e77053c..65d94ad 100644 --- a/app/crawler/crawl.js +++ b/app/crawler/crawl.js @@ -5,8 +5,6 @@ All environment specific configuration is read here and passed to the crawlers and savers. */ - -require("dotenv").config(); const OlxCrawler = require("./specific/olx"); const { OLX_CONFIG } = require("./crawlerConfig"); const PostgresSaver = require("./savers/postgres"); diff --git a/app/crawler/crawlerConfig.js b/app/crawler/crawlerConfig.js index eb9133a..3b2abef 100644 --- a/app/crawler/crawlerConfig.js +++ b/app/crawler/crawlerConfig.js @@ -1,5 +1,5 @@ "use strict"; -require("dotenv").config({ path: "../../.env" }); +require("dotenv").config({ path: __dirname + "/./../../.env" }); const { CRAWLER_AD_TYPE, AD_CATEGORY } = require("../common/enums"); const olxCrawlerAdType = @@ -12,7 +12,7 @@ const olxParsedCrawlerAdCategories = ? process.env.OLX_CRAWLER_AD_CATEGORIES.split(",").map(category => category.trim() ) - : ["CATEGORY_FLAT", "CATEGORY_HOUSE"]; + : ["FLAT", "HOUSE"]; const olxIgnoredUsernames = process.env.OLX_IGNORED_USERNAMES !== undefined @@ -22,7 +22,9 @@ const olxIgnoredUsernames = : []; const transformedCrawlerAdCategories = olxParsedCrawlerAdCategories - .map(categoryName => AD_CATEGORY[categoryName]) + .map(categoryName => + AD_CATEGORY[categoryName] ? AD_CATEGORY[categoryName].id : undefined + ) .filter(category => !!category); const OLX_CONFIG = { diff --git a/app/crawler/specific/olx.js b/app/crawler/specific/olx.js index b10f55a..cbeacbc 100644 --- a/app/crawler/specific/olx.js +++ b/app/crawler/specific/olx.js @@ -22,12 +22,12 @@ const OLX_ENUMS = { [CRAWLER_AD_TYPE.ONLY_RENT]: "&vrsta=samoizdavanje" }, OLX_AD_CATEGORY: { - [AD_CATEGORY.CATEGORY_FLAT]: "&kategorija=23", - [AD_CATEGORY.CATEGORY_HOUSE]: "&kategorija=24", - [AD_CATEGORY.CATEGORY_LAND]: "&kategorija=29", - [AD_CATEGORY.CATEGORY_OFFICE]: "&kategorija=25", - [AD_CATEGORY.CATEGORY_APARTMENT]: "&kategorija=27", - [AD_CATEGORY.CATEGORY_GARAGE]: "&kategorija=30" + [AD_CATEGORY.FLAT.id]: "&kategorija=23", + [AD_CATEGORY.HOUSE.id]: "&kategorija=24", + //[AD_CATEGORY.LAND.id]: "&kategorija=29", + //[AD_CATEGORY.OFFICE.id]: "&kategorija=25", + [AD_CATEGORY.APARTMENT.id]: "&kategorija=27" + //[AD_CATEGORY.CATEGORY_GARAGE.id]: "&kategorija=30" }, MAX_DETAIL_FIELDS: 30, OLX_PUBLISHED_DATE_FORMAT: "DD.MM.YYYY. u HH:mm", @@ -38,10 +38,7 @@ class OlxCrawler { constructor( savers = [], crawlerAdTypes = CRAWLER_AD_TYPE.ALL, - crawlerAdCategories = [ - AD_CATEGORY.CATEGORY_FLAT, - AD_CATEGORY.CATEGORY_HOUSE - ], + crawlerAdCategories = [AD_CATEGORY.FLAT, AD_CATEGORY.HOUSE], maxPages = 1000, maxResultsPerPage = 100, ignoredUsernames = [], @@ -196,7 +193,7 @@ class OlxCrawler { } async scrapeAd(url) { - //console.log("Scraping : ", url); + // console.log("Scraping : ", url); try { const adPageSource = await fetch(url); const body = await adPageSource.text(); @@ -407,7 +404,7 @@ class OlxCrawler { url, agencyObjectId: olxId, originAgencyName: AD_AGENCY.OLX, - realEstateType: this.getAdCategoryId(category), + realEstateType: parsedCategory, adType: parsedAdType, title, price: parsedPrice, @@ -448,15 +445,15 @@ class OlxCrawler { getAdCategoryId(categoryText) { switch (categoryText) { case "Stanovi": - return AD_CATEGORY.CATEGORY_FLAT; + return AD_CATEGORY.FLAT.id; case "Zemljišta": - return AD_CATEGORY.CATEGORY_LAND; + return undefined; //AD_CATEGORY.LAND; case "Kuće": - return AD_CATEGORY.CATEGORY_HOUSE; + return AD_CATEGORY.HOUSE.id; case "Poslovni prostori": - return AD_CATEGORY.CATEGORY_OFFICE; + return undefined; //AD_CATEGORY.OFFICE; case "Apartmani": - return AD_CATEGORY.CATEGORY_APARTMENT; + return AD_CATEGORY.APARTMENT.id; default: return undefined; } diff --git a/app/helpers/awsEmail.js b/app/helpers/awsEmail.js deleted file mode 100644 index bb1c80c..0000000 --- a/app/helpers/awsEmail.js +++ /dev/null @@ -1,250 +0,0 @@ -const { APP_URL } = require("../config/appConfig"); -const { getRealEstateTypeEnum } = require("./enums"); -const { getRegionName, getMunicipalityName } = require("./codes"); -const { allRERequestByUiid } = require("./db/dbHelper"); -let AWS = require("aws-sdk"); -const TEMPLATE_NAME = "MarketAlertTemplate"; - -AWS.config.update({ - region: process.env.AMAZON_REGION, - credentials: { - accessKeyId: process.env.AMAZON_ACCES_KEY_ID, - secretAccessKey: process.env.AMAZON_SECRET_ACCESS_KEY - } -}); - -const sendTemplatedEmail = async (email, request) => { - const params = { - Destination: { - /* required */ - CcAddresses: [], - ToAddresses: [email] - }, - Message: { - /* required */ - Body: { - /* required */ - Html: { - Charset: "UTF-8", - Data: getGreetingsEmailHTML(request) - }, - Text: { - Charset: "UTF-8", - Data: getGreetingsEmailTextVersion(request) - } - }, - Subject: { - Charset: "UTF-8", - Data: `Javimi Potvrda: ${getSubject(request.realEstateType)}` - } - }, - Source: process.env.SOURCE_EMAIL /* required */, - ReplyToAddresses: [process.env.SOURCE_EMAIL] - }; - - const sendEmailPromise = new AWS.SES({ apiVersion: "2010-12-01" }) - .sendEmail(params) - .promise(); - await sendEmailPromise; -}; - -const getGreetingsEmailHTML = realEstateRequest => { - const realEstateType = getRealEstateTypeEnum( - realEstateRequest.realEstateType - ); - const gardenSize = realEstateType.hasGardenSize - ? `