Merge branch 'checkup-email' into 'master'
Added check up email that everything works. See merge request saburly/marketalarm/web!89
This commit was merged in pull request #89.
This commit is contained in:
@@ -14,6 +14,8 @@ const DEFAULT_TIMEZONE = "Europe/Sarajevo";
|
|||||||
const CRAWLER_INTERVAL = parseInt(process.env.CRAWLER_INTERVAL) || 60;
|
const CRAWLER_INTERVAL = parseInt(process.env.CRAWLER_INTERVAL) || 60;
|
||||||
const STOP_CRAWLER = !!parseInt(process.env.STOP_CRAWLER);
|
const STOP_CRAWLER = !!parseInt(process.env.STOP_CRAWLER);
|
||||||
|
|
||||||
|
const CHECK_UP_DAYS = parseInt(process.env.CHECK_UP_DAYS) || 10;
|
||||||
|
|
||||||
const AWS_EMAIL_CONFIG = {
|
const AWS_EMAIL_CONFIG = {
|
||||||
REGION: process.env.AWS_REGION || "",
|
REGION: process.env.AWS_REGION || "",
|
||||||
CREDENTIALS: {
|
CREDENTIALS: {
|
||||||
@@ -48,5 +50,6 @@ module.exports = {
|
|||||||
MAX_REAL_ESTATES_IN_FIRST_EMAIL,
|
MAX_REAL_ESTATES_IN_FIRST_EMAIL,
|
||||||
PRINT_CRAWLER_DEBUG,
|
PRINT_CRAWLER_DEBUG,
|
||||||
API_MAP_KEY,
|
API_MAP_KEY,
|
||||||
|
CHECK_UP_DAYS,
|
||||||
PROSTOR_LOGIN
|
PROSTOR_LOGIN
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
const db = require("../../models/index");
|
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 findRealEstatesForSearchRequest = async searchRequestId => {
|
||||||
const query = {
|
const query = {
|
||||||
@@ -40,6 +43,42 @@ const findNotNotifiedMatches = async () => {
|
|||||||
|
|
||||||
return matchingRecords;
|
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 => {
|
const addMatches = async matchingRecords => {
|
||||||
return await db.SearchRequestMatch.bulkCreate(matchingRecords, {
|
return await db.SearchRequestMatch.bulkCreate(matchingRecords, {
|
||||||
@@ -50,5 +89,6 @@ const addMatches = async matchingRecords => {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
findRealEstatesForSearchRequest,
|
findRealEstatesForSearchRequest,
|
||||||
addMatches,
|
addMatches,
|
||||||
findNotNotifiedMatches
|
findNotNotifiedMatches,
|
||||||
|
findAllRequestsForCheckUp
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -152,8 +152,42 @@ const generateEmailSubject = (numberOfRealEstates, singleRealEstateTitle) => {
|
|||||||
return `Kivi: ${numberOfRealEstates} novih nekretnina`;
|
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
|
||||||
|
? `<div><strong>Kvadratura okućnice: Od ${gardenSizeMin} do ${gardenSizeMax} m2</strong></div>`
|
||||||
|
: ``;
|
||||||
|
|
||||||
|
const emailFooter = generateEmailFooter(id);
|
||||||
|
|
||||||
|
return `<h3>Zdravo</h3>
|
||||||
|
<div><strong>Kivi tim traži nekretnine za Vas i kada to ne vidite.</strong></div>
|
||||||
|
<br />
|
||||||
|
<div>Vaša trenutno aktivna pretraga je:</div>
|
||||||
|
<br/>
|
||||||
|
<div>
|
||||||
|
<div><strong>Tip nekretnine: </strong>${realEstateType.title}</div>
|
||||||
|
<div><strong>Kvadratura nekretnine:</strong> Od ${sizeMin} do ${sizeMax} m2</div>
|
||||||
|
${gardenSize}
|
||||||
|
<div><strong>Cijena:</strong> ${priceMin} do ${priceMax} KM</div>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
${emailFooter}`;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
generateNotificationEmail,
|
generateNotificationEmail,
|
||||||
generateNewSearchRequestEmail,
|
generateNewSearchRequestEmail,
|
||||||
generateEmailSubject
|
generateEmailSubject,
|
||||||
|
generateCheckUpEmail
|
||||||
};
|
};
|
||||||
|
|||||||
6
app/npmScripts/npmCheckUpNotify.js
Normal file
6
app/npmScripts/npmCheckUpNotify.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
"use strict";
|
||||||
|
const { checkUpNotify } = require("../services/notificationService");
|
||||||
|
//For testing pursposes
|
||||||
|
(async () => {
|
||||||
|
await checkUpNotify();
|
||||||
|
})();
|
||||||
@@ -6,10 +6,12 @@ const {
|
|||||||
const {
|
const {
|
||||||
generateNotificationEmail,
|
generateNotificationEmail,
|
||||||
generateNewSearchRequestEmail,
|
generateNewSearchRequestEmail,
|
||||||
generateEmailSubject
|
generateEmailSubject,
|
||||||
|
generateCheckUpEmail
|
||||||
} = require("../helpers/emailContentGenerator");
|
} = require("../helpers/emailContentGenerator");
|
||||||
const {
|
const {
|
||||||
findNotNotifiedMatches,
|
findNotNotifiedMatches,
|
||||||
|
findAllRequestsForCheckUp,
|
||||||
findRealEstatesForSearchRequest
|
findRealEstatesForSearchRequest
|
||||||
} = require("../helpers/db/searchRequestMatch");
|
} = require("../helpers/db/searchRequestMatch");
|
||||||
const { sendEmail } = require("../services/emailService");
|
const { sendEmail } = require("../services/emailService");
|
||||||
@@ -120,8 +122,26 @@ const notifyRequestsWithDailyOption = async () => {
|
|||||||
await notifyMatches(matches, true);
|
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 = {
|
module.exports = {
|
||||||
notifyForNewRealEstates,
|
notifyForNewRealEstates,
|
||||||
notifyForNewSearchRequest,
|
notifyForNewSearchRequest,
|
||||||
notifyRequestsWithDailyOption
|
notifyRequestsWithDailyOption,
|
||||||
|
checkUpNotify
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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_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
|
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 =============#
|
#=============== GOOGLE ANALYTICS =============#
|
||||||
GA_ID=Google Analytics ID
|
GA_ID=Google Analytics ID
|
||||||
|
|
||||||
|
|||||||
4
index.js
4
index.js
@@ -12,6 +12,7 @@ const {
|
|||||||
} = require("./app/config/appConfig");
|
} = require("./app/config/appConfig");
|
||||||
const routes = require("./app/routes");
|
const routes = require("./app/routes");
|
||||||
const { crawlAll } = require("./app/crawler/crawl");
|
const { crawlAll } = require("./app/crawler/crawl");
|
||||||
|
const { checkUpNotify } = require("./app/services/notificationService");
|
||||||
const {
|
const {
|
||||||
notifyForNewRealEstates
|
notifyForNewRealEstates
|
||||||
} = require("./app/services/notificationService");
|
} = require("./app/services/notificationService");
|
||||||
@@ -45,4 +46,7 @@ const crawl = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setInterval(crawl, CRAWLER_INTERVAL * 1000);
|
setInterval(crawl, CRAWLER_INTERVAL * 1000);
|
||||||
|
|
||||||
|
setInterval(checkUpNotify, 1000 * 60 * 60 * 24);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"docker-stop": "docker stop pg_marketalerts",
|
"docker-stop": "docker stop pg_marketalerts",
|
||||||
"crawl": "cd app/crawler && node npmCrawl.js",
|
"crawl": "cd app/crawler && node npmCrawl.js",
|
||||||
"daily-notify": "cd app/npmScripts && node npmDailyNotify.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-search": "cd test && node searchTest.js",
|
||||||
"test-olx-scraper": "cd test && node olxScrapeTest.js",
|
"test-olx-scraper": "cd test && node olxScrapeTest.js",
|
||||||
"test-rental-scraper": "cd test && node rentalScrapeTest.js"
|
"test-rental-scraper": "cd test && node rentalScrapeTest.js"
|
||||||
|
|||||||
Reference in New Issue
Block a user