Added formated subject to bulk email
This commit is contained in:
@@ -34,3 +34,9 @@ this will create and run postgres image and then execute migrations
|
|||||||
|
|
||||||
5. Run app
|
5. Run app
|
||||||
`npm start` or `npm run start-mon` to run app with automatic restart on code change
|
`npm start` or `npm run start-mon` to run app with automatic restart on code change
|
||||||
|
|
||||||
|
|
||||||
|
### AWS SES
|
||||||
|
|
||||||
|
- AWS SES credentials are handled with env vratiables
|
||||||
|
- Notification emails are sent in batches of 50, by using SES templates
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
const dotenv = require('dotenv').config();
|
const dotenv = require('dotenv').config();
|
||||||
const { getRealEstateTypeEnum } = require('./enums');
|
const { getRealEstateTypeEnum } = require('./enums');
|
||||||
const { getRegionName, getMunicipalityName } = require('./codes');
|
const { getRegionName, getMunicipalityName } = require('./codes');
|
||||||
|
const db = require('../models/index');
|
||||||
|
const { allRERequestByUiid } = require('./db/dbHelper');
|
||||||
var AWS = require('aws-sdk');
|
var AWS = require('aws-sdk');
|
||||||
const TEMPLATE_NAME = "MarketAlertTemplate"
|
const TEMPLATE_NAME = "MarketAlertTemplateDevelop"
|
||||||
|
|
||||||
AWS.config.update({
|
AWS.config.update({
|
||||||
region: process.env.AMAZON_REGION,
|
region: process.env.AMAZON_REGION,
|
||||||
@@ -97,26 +99,78 @@ const sendBulkEmail = async (marketAlerts) => {
|
|||||||
try {
|
try {
|
||||||
|
|
||||||
destinations = []
|
destinations = []
|
||||||
groupedEmails = [];
|
groupedRERequests = [];
|
||||||
|
|
||||||
|
|
||||||
|
let RERequestUuids = marketAlerts.map(marketAlert => marketAlert.request);
|
||||||
|
// console.log(RERequestUuids)
|
||||||
|
RERequestUuids = Array.from(new Set(RERequestUuids));
|
||||||
|
// console.log(RERequestUuids)
|
||||||
|
RERequestUuids = RERequestUuids.map(marketAlert => {
|
||||||
|
return { uniqueId: marketAlert }
|
||||||
|
});
|
||||||
|
// RERequestUuids = Array.from(new Set(RERequestUuids));
|
||||||
|
// console.log(RERequestUuids)
|
||||||
|
// const RERequests = await
|
||||||
|
const RERequest = await allRERequestByUiid(RERequestUuids);
|
||||||
|
// const requestDataValues = RERequest.map(RERequest => {
|
||||||
|
// var formatedRequest = {};
|
||||||
|
// formatedRequest[RERequest.uniqueId] = {
|
||||||
|
// realEstateType: RERequest.realEstateType,
|
||||||
|
// region: RERequest.region,
|
||||||
|
// municipality: RERequest.municipality
|
||||||
|
// };
|
||||||
|
// return formatedRequest;
|
||||||
|
// })
|
||||||
|
const requestDataValues = [];
|
||||||
|
RERequest.forEach(RERequest => {
|
||||||
|
var formatedRequest = {};
|
||||||
|
formatedRequest[RERequest.uniqueId] =
|
||||||
|
requestDataValues[RERequest.uniqueId] = {
|
||||||
|
realEstateType: RERequest.realEstateType,
|
||||||
|
region: RERequest.region,
|
||||||
|
municipality: RERequest.municipality
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// console.log(requestDataValues);
|
||||||
|
|
||||||
|
|
||||||
marketAlerts.forEach(marketAlert => {
|
marketAlerts.forEach(marketAlert => {
|
||||||
if (!groupedEmails[marketAlert.email]) {
|
// console.log(marketAlert);
|
||||||
groupedEmails[marketAlert.email] = [];
|
// const RERequest = await currentRERequest(marketAlert.request);
|
||||||
groupedEmails[marketAlert.email].push({ url: marketAlert.url, title: marketAlert.title });
|
if (!groupedRERequests[marketAlert.request]) {
|
||||||
} else {
|
groupedRERequests[marketAlert.request] = [];
|
||||||
groupedEmails[marketAlert.email].push({ url: marketAlert.url, title: marketAlert.title });
|
|
||||||
}
|
}
|
||||||
|
// console.log(requestDataValues[marketAlert.request]);
|
||||||
|
console.log("MarketAlertEmail");
|
||||||
|
console.log(marketAlert.email);
|
||||||
|
|
||||||
|
groupedRERequests[marketAlert.request].push({
|
||||||
|
|
||||||
|
url: marketAlert.url,
|
||||||
|
title: marketAlert.title,
|
||||||
|
email: marketAlert.email,
|
||||||
|
requestData: {
|
||||||
|
realEstateType: requestDataValues[marketAlert.request].realEstateType,
|
||||||
|
region: requestDataValues[marketAlert.request].region,
|
||||||
|
municipality: requestDataValues[marketAlert.request].municipality
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
for (email in groupedEmails) {
|
for (request in groupedRERequests) {
|
||||||
|
// {{realestateType}}, {{region}}, {{municipality}}
|
||||||
|
|
||||||
const url = groupedEmails[email];
|
const marketAlert = groupedRERequests[request];
|
||||||
let repData = `{ "marketAlertUrl":[${toAWSArray(url)}], "favoriteanimal":"yak" }`
|
console.log("RequestlertEmail");
|
||||||
|
console.log(request.email);
|
||||||
|
console.log(request);
|
||||||
|
let repData = `{ "marketAlertUrl":[${toAWSArray(marketAlert)}], "realestateType":"${request.realEstateType}", "region":"${request.region}", "municipality":"${request.municipality}" }`
|
||||||
|
|
||||||
destinations.push({
|
destinations.push({
|
||||||
Destination: {
|
Destination: {
|
||||||
ToAddresses: [
|
ToAddresses: [
|
||||||
email
|
request.email
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
ReplacementTemplateData: repData
|
ReplacementTemplateData: repData
|
||||||
@@ -124,7 +178,7 @@ const sendBulkEmail = async (marketAlerts) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
console.log("AWS EMAIL : Bulk email replacement data:");
|
console.log("AWS EMAIL : Bulk email replacement data:");
|
||||||
console.log(destinations);
|
// console.log(destinations);
|
||||||
|
|
||||||
var params = {
|
var params = {
|
||||||
Destinations:
|
Destinations:
|
||||||
@@ -152,6 +206,7 @@ const sendBulkEmail = async (marketAlerts) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toAWSArray = (urlArray) => {
|
const toAWSArray = (urlArray) => {
|
||||||
|
console.log(urlArray);
|
||||||
let arrayString = ""
|
let arrayString = ""
|
||||||
urlArray.forEach(element => {
|
urlArray.forEach(element => {
|
||||||
const formatetdTitle = element.title.replace(/"/g, "");
|
const formatetdTitle = element.title.replace(/"/g, "");
|
||||||
@@ -179,8 +234,8 @@ const getNotificationEmailText = () => {
|
|||||||
const createMarketAlertEmailTemplate = async () => {
|
const createMarketAlertEmailTemplate = async () => {
|
||||||
const marketAlertTemplate = {
|
const marketAlertTemplate = {
|
||||||
Template: {
|
Template: {
|
||||||
TemplateName: "MarketAlertTemplate",
|
TemplateName: TEMPLATE_NAME,
|
||||||
SubjectPart: "Javi mi obavijest",
|
SubjectPart: "Javi mi obavijest: {{realestateType}}, {{region}}, {{municipality}}",
|
||||||
TextPart: getNotificationEmailText(),
|
TextPart: getNotificationEmailText(),
|
||||||
HtmlPart: getNotificationEmailHtml()
|
HtmlPart: getNotificationEmailHtml()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ module.exports = class OlxCrawler {
|
|||||||
this.maxResults = maxResults;
|
this.maxResults = maxResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
async indexSingle(url, email) {
|
async indexSingle(url, email, uuid) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
const body = await res.text();
|
const body = await res.text();
|
||||||
@@ -81,6 +81,7 @@ module.exports = class OlxCrawler {
|
|||||||
|
|
||||||
const parsedPrice = parsePrice(price);
|
const parsedPrice = parsePrice(price);
|
||||||
|
|
||||||
|
console.log(location);
|
||||||
const locationArray = location.split(",");
|
const locationArray = location.split(",");
|
||||||
const region = locationArray[0];
|
const region = locationArray[0];
|
||||||
const municipality = locationArray[1];
|
const municipality = locationArray[1];
|
||||||
@@ -88,6 +89,7 @@ module.exports = class OlxCrawler {
|
|||||||
const data = {
|
const data = {
|
||||||
realEstateType: this.getCategoryId(realEstateType),
|
realEstateType: this.getCategoryId(realEstateType),
|
||||||
email: email,
|
email: email,
|
||||||
|
uuid: uuid,
|
||||||
olxId: olxId,
|
olxId: olxId,
|
||||||
// category: category,
|
// category: category,
|
||||||
url,
|
url,
|
||||||
@@ -138,7 +140,7 @@ module.exports = class OlxCrawler {
|
|||||||
for (let i = 0; i < hrefs.length; i++) {
|
for (let i = 0; i < hrefs.length; i++) {
|
||||||
console.log(`indexing: ${hrefs[i]}`);
|
console.log(`indexing: ${hrefs[i]}`);
|
||||||
|
|
||||||
const singleData = await this.indexSingle(hrefs[i], olxUrl.email);
|
const singleData = await this.indexSingle(hrefs[i], olxUrl.email, olxUrl.uuid);
|
||||||
|
|
||||||
if (singleData) {
|
if (singleData) {
|
||||||
results.push(singleData);
|
results.push(singleData);
|
||||||
@@ -223,7 +225,8 @@ module.exports = class OlxCrawler {
|
|||||||
|
|
||||||
const olxUrl = {
|
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}`,
|
url: `https://www.olx.ba/pretraga?${realsestateType}&id=2&stanje=0&vrstapregleda=tabela&sort_order=desc&${region}&${municipality}&${priceMin}&${priceMax}&vrsta=samoprodaja&${sizeMin}&${sizeMax}`,
|
||||||
email: request.email
|
email: request.email,
|
||||||
|
uuid: request.uniqueId
|
||||||
}
|
}
|
||||||
console.log(olxUrl.url);
|
console.log(olxUrl.url);
|
||||||
urls.push(olxUrl);
|
urls.push(olxUrl);
|
||||||
|
|||||||
@@ -11,6 +11,20 @@ const allRERequest = async () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all subscribed RealEstateRequests by UUID
|
||||||
|
*/
|
||||||
|
const allRERequestByUiid = async (requestArray) => {
|
||||||
|
|
||||||
|
const Op = db.Sequelize.Op;
|
||||||
|
return await db.RealEstateRequest.findAll({
|
||||||
|
where: {
|
||||||
|
subscribed: true,
|
||||||
|
[Op.or]: requestArray
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all , or all depending on notified bolean marketalerts, and order them by email
|
* Find all , or all depending on notified bolean marketalerts, and order them by email
|
||||||
*
|
*
|
||||||
@@ -50,5 +64,6 @@ const findPointInsideBoundingBox = async (latLng, email) => {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
allRERequest,
|
allRERequest,
|
||||||
allMarketAlerts,
|
allMarketAlerts,
|
||||||
|
allRERequestByUiid,
|
||||||
findPointInsideBoundingBox
|
findPointInsideBoundingBox
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
up: (queryInterface, Sequelize) => {
|
||||||
|
return queryInterface.addColumn(
|
||||||
|
'MarketAlerts',
|
||||||
|
'request',
|
||||||
|
{
|
||||||
|
type: Sequelize.STRING
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
down: (queryInterface, Sequelize) => {
|
||||||
|
return queryInterface.removeColumn(
|
||||||
|
'MarketAlerts',
|
||||||
|
'request'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -13,6 +13,7 @@ module.exports = (sequelize, DataTypes) => {
|
|||||||
realEstateType : DataTypes.STRING,
|
realEstateType : DataTypes.STRING,
|
||||||
notified : DataTypes.BOOLEAN,
|
notified : DataTypes.BOOLEAN,
|
||||||
title : DataTypes.STRING,
|
title : DataTypes.STRING,
|
||||||
|
request: DataTypes.STRING,
|
||||||
|
|
||||||
email: {
|
email: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ async function crawlAll() {
|
|||||||
size: result.size,
|
size: result.size,
|
||||||
price: result.price,
|
price: result.price,
|
||||||
email: result.email,
|
email: result.email,
|
||||||
|
request: result.uuid,
|
||||||
// lastDate: DataTypes.STRING,
|
// lastDate: DataTypes.STRING,
|
||||||
municipality: result.municipality,
|
municipality: result.municipality,
|
||||||
region: result.region,
|
region: result.region,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ async function processNotifications() {
|
|||||||
await sendBulkEmail(marketAlerts);
|
await sendBulkEmail(marketAlerts);
|
||||||
} else {
|
} else {
|
||||||
console.log("NOTIFICATION SERVICE: No new alerts");
|
console.log("NOTIFICATION SERVICE: No new alerts");
|
||||||
return;
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.MarketAlert.update(
|
await db.MarketAlert.update(
|
||||||
@@ -26,6 +26,7 @@ async function processNotifications() {
|
|||||||
process.exit();
|
process.exit();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("NOTIFICATION SERVICE: could not send notifications reason: ", e);
|
console.log("NOTIFICATION SERVICE: could not send notifications reason: ", e);
|
||||||
|
process.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user