diff --git a/app/config/appConfig.js b/app/config/appConfig.js
index 4403fbd..3ccedbe 100644
--- a/app/config/appConfig.js
+++ b/app/config/appConfig.js
@@ -14,6 +14,8 @@ const DEFAULT_TIMEZONE = "Europe/Sarajevo";
const CRAWLER_INTERVAL = parseInt(process.env.CRAWLER_INTERVAL) || 60;
const STOP_CRAWLER = !!parseInt(process.env.STOP_CRAWLER);
+const CHECK_UP_DAYS = parseInt(process.env.CHECK_UP_DAYS) || 10;
+
const AWS_EMAIL_CONFIG = {
REGION: process.env.AWS_REGION || "",
CREDENTIALS: {
@@ -48,5 +50,6 @@ module.exports = {
MAX_REAL_ESTATES_IN_FIRST_EMAIL,
PRINT_CRAWLER_DEBUG,
API_MAP_KEY,
+ CHECK_UP_DAYS,
PROSTOR_LOGIN
};
diff --git a/app/helpers/db/searchRequestMatch.js b/app/helpers/db/searchRequestMatch.js
index 11d5cde..794711b 100644
--- a/app/helpers/db/searchRequestMatch.js
+++ b/app/helpers/db/searchRequestMatch.js
@@ -1,5 +1,8 @@
"use strict";
const db = require("../../models/index");
+const sequelize = require("sequelize");
+const Op = sequelize.Op;
+const { CHECK_UP_DAYS } = require("../../config/appConfig");
const findRealEstatesForSearchRequest = async searchRequestId => {
const query = {
@@ -40,6 +43,42 @@ const findNotNotifiedMatches = async () => {
return matchingRecords;
};
+const findAllRequestsForCheckUp = async () => {
+ //First we find IDs of search request that don't need to be emailed for check up - to EXCLUDE
+ //The ones that received notification for real estate CHECK_UP_DAYS days from now
+ const date = new Date();
+ const checkUpDate = date.getDate() - CHECK_UP_DAYS;
+ date.setDate(checkUpDate);
+ const dateQuery = {
+ createdAt: {
+ [Op.gte]: date
+ }
+ };
+
+ const excludedMatches = await db.SearchRequestMatch.findAll({
+ attributes: ["searchRequestId"],
+ where: dateQuery,
+ order: [["searchRequestId", "ASC"]]
+ });
+
+ const excludedRequestsAll = excludedMatches.map(match => {
+ return match.dataValues.searchRequestId;
+ });
+ //Removing duplicate search request id-s for optimization
+ const excludedRequests = [...new Set(excludedRequestsAll)];
+
+ const query = {
+ subscribed: true,
+ id: {
+ [Op.notIn]: excludedRequests
+ }
+ };
+ const allRequestsForCheckUp = await db.SearchRequest.findAll({
+ where: query
+ });
+
+ return allRequestsForCheckUp;
+};
const addMatches = async matchingRecords => {
return await db.SearchRequestMatch.bulkCreate(matchingRecords, {
@@ -50,5 +89,6 @@ const addMatches = async matchingRecords => {
module.exports = {
findRealEstatesForSearchRequest,
addMatches,
- findNotNotifiedMatches
+ findNotNotifiedMatches,
+ findAllRequestsForCheckUp
};
diff --git a/app/helpers/emailContentGenerator.js b/app/helpers/emailContentGenerator.js
index 5e745bc..5a76e9b 100644
--- a/app/helpers/emailContentGenerator.js
+++ b/app/helpers/emailContentGenerator.js
@@ -152,8 +152,42 @@ const generateEmailSubject = (numberOfRealEstates, singleRealEstateTitle) => {
return `Kivi: ${numberOfRealEstates} novih nekretnina`;
};
+const generateCheckUpEmail = searchRequest => {
+ const realEstateType = AD_CATEGORY[searchRequest.realEstateType];
+ const {
+ id,
+ gardenSizeMin,
+ gardenSizeMax,
+ sizeMin,
+ sizeMax,
+ priceMin,
+ priceMax
+ } = searchRequest;
+
+ const gardenSize = realEstateType.hasGardenSize
+ ? `
Kvadratura okućnice: Od ${gardenSizeMin} do ${gardenSizeMax} m2
`
+ : ``;
+
+ const emailFooter = generateEmailFooter(id);
+
+ return `Zdravo
+ Kivi tim traži nekretnine za Vas i kada to ne vidite.
+
+ Vaša trenutno aktivna pretraga je:
+
+
+
Tip nekretnine: ${realEstateType.title}
+
Kvadratura nekretnine: Od ${sizeMin} do ${sizeMax} m2
+ ${gardenSize}
+
Cijena: ${priceMin} do ${priceMax} KM
+
+
+ ${emailFooter}`;
+};
+
module.exports = {
generateNotificationEmail,
generateNewSearchRequestEmail,
- generateEmailSubject
+ generateEmailSubject,
+ generateCheckUpEmail
};
diff --git a/app/npmScripts/npmCheckUpNotify.js b/app/npmScripts/npmCheckUpNotify.js
new file mode 100644
index 0000000..b69cbf6
--- /dev/null
+++ b/app/npmScripts/npmCheckUpNotify.js
@@ -0,0 +1,6 @@
+"use strict";
+const { checkUpNotify } = require("../services/notificationService");
+//For testing pursposes
+(async () => {
+ await checkUpNotify();
+})();
diff --git a/app/services/notificationService.js b/app/services/notificationService.js
index 7a4a62a..15b8ce0 100644
--- a/app/services/notificationService.js
+++ b/app/services/notificationService.js
@@ -6,10 +6,12 @@ const {
const {
generateNotificationEmail,
generateNewSearchRequestEmail,
- generateEmailSubject
+ generateEmailSubject,
+ generateCheckUpEmail
} = require("../helpers/emailContentGenerator");
const {
findNotNotifiedMatches,
+ findAllRequestsForCheckUp,
findRealEstatesForSearchRequest
} = require("../helpers/db/searchRequestMatch");
const { sendEmail } = require("../services/emailService");
@@ -120,8 +122,26 @@ const notifyRequestsWithDailyOption = async () => {
await notifyMatches(matches, true);
};
+const checkUpNotify = async () => {
+ const searchRequestsForCheckUp = await findAllRequestsForCheckUp();
+
+ const asyncSendEmailActions = [];
+
+ for (const searchRequest of searchRequestsForCheckUp) {
+ const { email } = searchRequest.dataValues;
+ const emailSubject = `Kivi: Mi tražimo nekretnine za vas!`;
+ const emailContent = generateCheckUpEmail(searchRequest.dataValues);
+
+ const sendEmailPromise = sendEmail(email, emailSubject, emailContent);
+ asyncSendEmailActions.push(sendEmailPromise);
+ sendEmailPromise.catch(err => console.log("[Email Sending Failed]", err));
+ }
+ await Promise.all(asyncSendEmailActions);
+};
+
module.exports = {
notifyForNewRealEstates,
notifyForNewSearchRequest,
- notifyRequestsWithDailyOption
+ notifyRequestsWithDailyOption,
+ checkUpNotify
};
diff --git a/development.env b/development.env
index 150f8be..9c5389b 100644
--- a/development.env
+++ b/development.env
@@ -11,6 +11,7 @@ APP_BASE_URL=base url for the app
MAX_REAL_ESTATES_IN_EMAIL=Max number of real estates that will be shown in email, others will be truncated and URL with full list will be shwon
MAX_REAL_ESTATES_IN_FIRST_EMAIL=Max number of real estates that will be shown in first (welcome) email
+CHECK_UP_DAYS=Check up email is sent after this number of days without notification
#=============== GOOGLE ANALYTICS =============#
GA_ID=Google Analytics ID
diff --git a/index.js b/index.js
index 074099b..0669e7b 100644
--- a/index.js
+++ b/index.js
@@ -12,6 +12,7 @@ const {
} = require("./app/config/appConfig");
const routes = require("./app/routes");
const { crawlAll } = require("./app/crawler/crawl");
+const { checkUpNotify } = require("./app/services/notificationService");
const {
notifyForNewRealEstates
} = require("./app/services/notificationService");
@@ -45,4 +46,7 @@ const crawl = () => {
});
}
};
+
setInterval(crawl, CRAWLER_INTERVAL * 1000);
+
+setInterval(checkUpNotify, 1000 * 60 * 60 * 24);
diff --git a/package.json b/package.json
index 37eafa4..3bc99a7 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"docker-stop": "docker stop pg_marketalerts",
"crawl": "cd app/crawler && node npmCrawl.js",
"daily-notify": "cd app/npmScripts && node npmDailyNotify.js",
+ "checkup-notify": "cd app/npmScripts && node npmCheckUpNotify.js",
"test-search": "cd test && node searchTest.js",
"test-olx-scraper": "cd test && node olxScrapeTest.js",
"test-rental-scraper": "cd test && node rentalScrapeTest.js"