diff --git a/README.md b/README.md index ff6fb13..6958b7f 100755 --- a/README.md +++ b/README.md @@ -152,14 +152,14 @@ Districts that are unwanted can be blacklisted here. This makes sense for provider that only offer limited filter functions like Kalaydo/Ebay. # API -While Fredy is running, you can make use of the rest api provided on port `9988` to get information about the current status of Fredy. -#### http://localhost:9988/ +While Fredy is running, you can make use of the rest api provided on port `9998` to get information about the current status of Fredy. +#### http://localhost:9998/ Gives you an overview of running search jobs, their included enabled provider, last execution and the number of listings, found by each provider. -#### http://localhost:9988/ping +#### http://localhost:9998/ping Should you ever need some health checks, this returns pong ;) -#### http://localhost:9988/jobs/:name +#### http://localhost:9998/jobs/:name Returns specific information about the job with the given name or `404` if the job could not be found. # Docker diff --git a/lib/FredyRuntime.js b/lib/FredyRuntime.js index 6b96338..c9aa76d 100755 --- a/lib/FredyRuntime.js +++ b/lib/FredyRuntime.js @@ -3,7 +3,7 @@ const { setKnownListings, getKnownListings, setNumberOfTotalFoundProviderListings, - getForTesting + getForTesting, } = require('./services/store'); const notify = require('./notification/notify'); @@ -79,7 +79,7 @@ class FredyRuntime { } _findNew(listings) { - const newListings = listings.filter(o => getKnownListings(this._jobKey, this._providerId).indexOf(o.id) === -1); + const newListings = listings.filter((o) => getKnownListings(this._jobKey, this._providerId).indexOf(o.id) === -1); if (newListings.length === 0) { throw new NoNewListingsError(); @@ -89,14 +89,14 @@ class FredyRuntime { } _notify(newListings) { - const sendNotifications = notify.send(this._providerId, newListings, this._notificationConfig); + const sendNotifications = notify.send(this._providerId, newListings, this._notificationConfig, this._jobKey); return Promise.all(sendNotifications).then(() => newListings); } _save(newListings) { setKnownListings(this._jobKey, this._providerId, [ ...getKnownListings(this._jobKey, this._providerId), - ...newListings.map(l => l.id) + ...newListings.map((l) => l.id), ]); return newListings; } diff --git a/lib/api/api.js b/lib/api/api.js index 056580b..0c667b8 100644 --- a/lib/api/api.js +++ b/lib/api/api.js @@ -1,24 +1,24 @@ const bodyParser = require('body-parser'); const config = require('../../conf/config'); const { getLastJobExecution, getLastProviderExecution, getTotalNumberOfListings } = require('../services/store'); -const PORT = 9988; +const PORT = 9998; const service = require('restana')(); service.use(bodyParser.json()); service.get('/', async (req, res) => { const result = {}; - Object.keys(config.jobs).forEach(job => { + Object.keys(config.jobs).forEach((job) => { result[job] = { lastExecution: getLastJobExecution(job), enabledProvider: Object.keys(config.jobs[job].provider) - .filter(providerKey => config.jobs[job].provider[providerKey].enabled) - .map(providerKey => { + .filter((providerKey) => config.jobs[job].provider[providerKey].enabled) + .map((providerKey) => { return { name: providerKey, lastExecution: getLastProviderExecution(job, providerKey), - totalFindings: getTotalNumberOfListings(job, providerKey) + totalFindings: getTotalNumberOfListings(job, providerKey), }; - }) + }), }; }); res.body = result; @@ -35,22 +35,22 @@ service.get('/jobs/:name', async (req, res) => { res.body = { lastExecution: getLastJobExecution(jobKey), enabledProvider: Object.keys(config.jobs[jobKey].provider) - .filter(providerKey => config.jobs[jobKey].provider[providerKey].enabled) - .map(providerKey => { + .filter((providerKey) => config.jobs[jobKey].provider[providerKey].enabled) + .map((providerKey) => { return { name: providerKey, url: config.jobs[jobKey].provider[providerKey].url, lastExecution: getLastProviderExecution(jobKey, providerKey), - totalFindings: getTotalNumberOfListings(jobKey, providerKey) + totalFindings: getTotalNumberOfListings(jobKey, providerKey), }; - }) + }), }; res.send(); }); -service.get('/ping', function(req, res) { +service.get('/ping', function (req, res) { res.body = { - pong: 'pong' + pong: 'pong', }; res.send(); }); diff --git a/lib/notification/adapter/console.js b/lib/notification/adapter/console.js index 22d4da5..52052a0 100755 --- a/lib/notification/adapter/console.js +++ b/lib/notification/adapter/console.js @@ -3,13 +3,14 @@ * @param serviceName e.g immoscout * @param newListings an array with newly found listings * @param notificationConfig config of this notification adapter + * @param jobKey name of the current job that is being executed */ -exports.send = (serviceName, newListings, notificationConfig) => { +exports.send = (serviceName, newListings, notificationConfig, jobKey) => { const { enabled } = notificationConfig.console; if (!enabled) { return [Promise.resolve()]; } /* eslint-disable no-console */ - return [Promise.resolve(console.info(`Found entry from service ${serviceName}:`, newListings))]; + return [Promise.resolve(console.info(`Found entry from service ${serviceName}, Job: ${jobKey}:`, newListings))]; /* eslint-enable no-console */ }; diff --git a/lib/notification/adapter/sendGrid.js b/lib/notification/adapter/sendGrid.js index 99844dd..c3542ca 100755 --- a/lib/notification/adapter/sendGrid.js +++ b/lib/notification/adapter/sendGrid.js @@ -5,9 +5,10 @@ const sgMail = require('@sendgrid/mail'); * @param serviceName e.g immoscout * @param newListings an array with newly found listings * @param notificationConfig config of this notification adapter + * * @param jobKey name of the current job that is being executed * @returns {Promise | void} */ -exports.send = (serviceName, newListings, notificationConfig) => { +exports.send = (serviceName, newListings, notificationConfig, jobKey) => { const { apiKey, enabled, receiver, from, templateId } = notificationConfig.sendGrid; if (!enabled) { return [Promise.resolve()]; @@ -17,9 +18,9 @@ exports.send = (serviceName, newListings, notificationConfig) => { templateId, to: receiver, from, - subject: `Service ${serviceName} found ${newListings.length} new listing(s)`, + subject: `Job ${jobKey} | Service ${serviceName} found ${newListings.length} new listing(s)`, dynamic_template_data: { - serviceName, + serviceName: `Job: (${jobKey}) | Service: ${serviceName}`, numberOfListings: newListings.length, listings: newListings, }, diff --git a/lib/notification/adapter/slack.js b/lib/notification/adapter/slack.js index 5c76831..ca00ecc 100755 --- a/lib/notification/adapter/slack.js +++ b/lib/notification/adapter/slack.js @@ -6,18 +6,19 @@ const msg = Slack.chat.postMessage; * @param serviceName e.g immoscout * @param newListings an array with newly found listings * @param notificationConfig config of this notification adapter + * * @param jobKey name of the current job that is being executed * @returns {Promise | void} */ -exports.send = (serviceName, newListings, notificationConfig) => { +exports.send = (serviceName, newListings, notificationConfig, jobKey) => { const { token, channel, enabled } = notificationConfig.slack; if (!enabled) { return [Promise.resolve()]; } - return newListings.map(payload => + return newListings.map((payload) => msg({ token, channel, - text: `*(${serviceName})* - ${payload.title}`, + text: `*(${serviceName} - ${jobKey})* - ${payload.title}`, attachments: [ { fallback: payload.title, @@ -28,23 +29,23 @@ exports.send = (serviceName, newListings, notificationConfig) => { { title: 'Price', value: payload.price, - short: false + short: false, }, { title: 'Size', value: payload.size, - short: false + short: false, }, { title: 'Address', value: payload.address, - short: false - } + short: false, + }, ], footer: 'Powered by Fredy', - ts: new Date().getTime() / 1000 - } - ] + ts: new Date().getTime() / 1000, + }, + ], }) ); }; diff --git a/lib/notification/adapter/telegram.js b/lib/notification/adapter/telegram.js index c1a7058..ff42ad4 100644 --- a/lib/notification/adapter/telegram.js +++ b/lib/notification/adapter/telegram.js @@ -1,33 +1,36 @@ const TelegramBot = require('tg-yarl'); -const opts = {parse_mode: 'Markdown'}; - +const opts = { parse_mode: 'Markdown' }; /** * sends new listings to telegram * @param serviceName e.g immoscout * @param newListings an array with newly found listings * @param notificationConfig config of this notification adapter + * * @param jobKey name of the current job that is being executed * @returns {Promise | void} */ -exports.send = (serviceName, newListings, notificationConfig) => { - const {enabled, token, chatId} = notificationConfig.telegram; - if (!enabled) { - return [Promise.resolve()]; - } +exports.send = (serviceName, newListings, notificationConfig, jobKey) => { + const { enabled, token, chatId } = notificationConfig.telegram; + if (!enabled) { + return [Promise.resolve()]; + } - const bot = new TelegramBot(token); + const bot = new TelegramBot(token); - let message = `Service _${serviceName}_ found _${newListings.length}_ new listings:\n\n`; + let message = `Job: ${jobKey} | Service _${serviceName}_ found _${newListings.length}_ new listings:\n\n`; - message += newListings.map(o => - `*${shorten(o.title.replace(/\*/g, ''), 45)}*\n` + - [o.address, o.price, o.size].join(' | ') + '\n' + - `[LINK](${o.link})\n\n`); + message += newListings.map( + (o) => + `*${shorten(o.title.replace(/\*/g, ''), 45)}*\n` + + [o.address, o.price, o.size].join(' | ') + + '\n' + + `[LINK](${o.link})\n\n` + ); - return bot.sendMessage(chatId, message, opts); + return bot.sendMessage(chatId, message, opts); }; function shorten(str, len = 30) { - return str.length > len ? str.substring(0, len) + '...' : str; -} \ No newline at end of file + return str.length > len ? str.substring(0, len) + '...' : str; +} diff --git a/lib/notification/notify.js b/lib/notification/notify.js index 56d276b..6147d33 100755 --- a/lib/notification/notify.js +++ b/lib/notification/notify.js @@ -2,15 +2,13 @@ const fs = require('fs'); const path = './adapter'; /** Read every integration existing in ./adapter **/ -const adapter = fs - .readdirSync('./lib/notification/adapter') - .map(integPath => require(`${path}/${integPath}`)); +const adapter = fs.readdirSync('./lib/notification/adapter').map((integPath) => require(`${path}/${integPath}`)); if (adapter.length === 0) { throw new Error('Please specify at least one notification provider'); } -exports.send = (serviceName, payload, notificationConfig) => { +exports.send = (serviceName, payload, notificationConfig, jobKey) => { //this is not being used in tests, therefor adapter are always set - return adapter.map(a => a.send(serviceName, payload, notificationConfig)); + return adapter.map((a) => a.send(serviceName, payload, notificationConfig, jobKey)); };