mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6bb3c44d4 | ||
|
|
a3471a091a | ||
|
|
b5a96afcc8 | ||
|
|
3903ab59cf | ||
|
|
8fe7cec2a1 | ||
|
|
97deea6f5b |
@@ -11,7 +11,7 @@ If _Fredy_ finds matching results, it will send them to you via Slack, Email, Te
|
|||||||
# Sponsorship [](https://github.com/sponsors/orangecoding)
|
# Sponsorship [](https://github.com/sponsors/orangecoding)
|
||||||
If you like my work, consider becoming a sponsor. I'm not expecting anybody to pay for _Fredy_ or any other Open Source Project I'm maintaining, however keep in mind, I'm doing all of this in my spare time :) Thanks.
|
If you like my work, consider becoming a sponsor. I'm not expecting anybody to pay for _Fredy_ or any other Open Source Project I'm maintaining, however keep in mind, I'm doing all of this in my spare time :) Thanks.
|
||||||
|
|
||||||
<img src="https://github.com/orangecoding/fredy/blob/master/doc/jetbrains.png" width="200">
|
[](https://jb.gg/OpenSourceSupport)
|
||||||
|
|
||||||
_Fredy_ is supported by JetBrains under Open Source Support Program
|
_Fredy_ is supported by JetBrains under Open Source Support Program
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ export const send = ({ serviceName, newListings, notificationConfig, jobKey }) =
|
|||||||
const job = getJob(jobKey);
|
const job = getJob(jobKey);
|
||||||
const jobName = job == null ? jobKey : job.name;
|
const jobName = job == null ? jobKey : job.name;
|
||||||
const promises = newListings.map((newListing) => {
|
const promises = newListings.map((newListing) => {
|
||||||
const message = `Address: ${newListing.address} Size: ${newListing.size.replace(/2m/g, '$m^2$')} Price: ${
|
const message = `
|
||||||
newListing.price
|
Address: ${newListing.address}
|
||||||
}`;
|
Size: ${newListing.size.replace(/2m/g, '$m^2$')}
|
||||||
|
Price: ${newListing.price}
|
||||||
|
Link: ${newListing.link}`;
|
||||||
return fetch(server, {
|
return fetch(server, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
|||||||
@@ -1,50 +1,73 @@
|
|||||||
import { markdown2Html } from '../../services/markdown.js';
|
import {markdown2Html} from '../../services/markdown.js';
|
||||||
import { getJob } from '../../services/storage/jobStorage.js';
|
import {getJob} from '../../services/storage/jobStorage.js';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
|
|
||||||
export const send = ({ serviceName, newListings, notificationConfig, jobKey }) => {
|
export const send = ({serviceName, newListings, notificationConfig, jobKey}) => {
|
||||||
const { token, user, device } = notificationConfig.find((adapter) => adapter.id === config.id).fields;
|
const {token, user, device} = notificationConfig.find((adapter) => adapter.id === config.id).fields;
|
||||||
const job = getJob(jobKey);
|
const job = getJob(jobKey);
|
||||||
const jobName = job == null ? jobKey : job.name;
|
const jobName = job == null ? jobKey : job.name;
|
||||||
const promises = newListings.map((newListing) => {
|
const promises = newListings.map((newListing) => {
|
||||||
const title = `${jobName} at ${serviceName}: ${newListing.title}`;
|
const title = `${jobName} at ${serviceName}: ${newListing.title}`;
|
||||||
const message = `Address: ${newListing.address}\nSize: ${newListing.size}\nPrice: ${newListing.price}\nLink: ${newListing.link}`;
|
const message = `Address: ${newListing.address}\nSize: ${newListing.size}\nPrice: ${newListing.price}\nLink: ${newListing.link}`;
|
||||||
return fetch('https://api.pushover.net/1/messages.json', {
|
return fetch('https://api.pushover.net/1/messages.json', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
token: token,
|
token: token,
|
||||||
user: user,
|
user: user,
|
||||||
message: message,
|
message: message,
|
||||||
device: device,
|
device: device,
|
||||||
title: title,
|
title: title,
|
||||||
}),
|
}),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises)
|
||||||
|
.then((responses) => {
|
||||||
|
// Convert all responses to JSON
|
||||||
|
return Promise.all(responses.map((response) => response.json()));
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
// Check for errors in the data
|
||||||
|
const error = data
|
||||||
|
.map((item) => (item.errors != null && item.errors.length > 0 ? item.errors.join(', ') : null))
|
||||||
|
.filter((err) => err !== null);
|
||||||
|
|
||||||
|
if (error.length > 0) {
|
||||||
|
// Reject with the combined error messages
|
||||||
|
return Promise.reject(error.join('; '));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return Promise.resolve();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
id: 'pushover',
|
id: 'pushover',
|
||||||
name: 'Pushover',
|
name: 'Pushover',
|
||||||
readme: markdown2Html('lib/notification/adapter/pushover.md'),
|
readme: markdown2Html('lib/notification/adapter/pushover.md'),
|
||||||
description: 'Fredy will send new listings to your mobile using Pushover.',
|
description: 'Fredy will send new listings to your mobile using Pushover.',
|
||||||
fields: {
|
fields: {
|
||||||
token: {
|
token: {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
label: 'API token',
|
label: 'API token',
|
||||||
description: 'Your application\'s API token.',
|
description: 'Your application\'s API token.',
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: 'text',
|
||||||
|
label: 'User key',
|
||||||
|
description: 'Your user/group key.',
|
||||||
|
},
|
||||||
|
device: {
|
||||||
|
type: 'text',
|
||||||
|
label: 'Device name',
|
||||||
|
description: 'The device name to send your notification to. Messages may be addressed to multiple specific devices by joining them with a comma.',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
user: {
|
|
||||||
type: 'text',
|
|
||||||
label: 'User key',
|
|
||||||
description: 'Your user/group key.',
|
|
||||||
},
|
|
||||||
device: {
|
|
||||||
type: 'text',
|
|
||||||
label: 'Device name',
|
|
||||||
description: 'The device name to send your notification to. Messages may be addressed to multiple specific devices by joining them with a comma.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ let appliedBlackList = [];
|
|||||||
|
|
||||||
function normalize(o) {
|
function normalize(o) {
|
||||||
const id = buildHash(o.id, o.price);
|
const id = buildHash(o.id, o.price);
|
||||||
return Object.assign(o, {id});
|
const link = `https://www.wg-gesucht.de${o.link}`;
|
||||||
|
return Object.assign(o, { id, link });
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyBlacklist(o) {
|
function applyBlacklist(o) {
|
||||||
|
|||||||
28
package.json
28
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fredy",
|
"name": "fredy",
|
||||||
"version": "11.0.1",
|
"version": "11.0.4",
|
||||||
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
|
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node prod.js",
|
"start": "node prod.js",
|
||||||
@@ -50,12 +50,12 @@
|
|||||||
"Firefox ESR"
|
"Firefox ESR"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@douyinfe/semi-ui": "2.72.3",
|
"@douyinfe/semi-ui": "2.75.0",
|
||||||
"@rematch/core": "2.2.0",
|
"@rematch/core": "2.2.0",
|
||||||
"@rematch/loading": "2.1.2",
|
"@rematch/loading": "2.1.2",
|
||||||
"@sendgrid/mail": "8.1.4",
|
"@sendgrid/mail": "8.1.4",
|
||||||
"@vitejs/plugin-react": "4.3.4",
|
"@vitejs/plugin-react": "4.3.4",
|
||||||
"better-sqlite3": "^11.7.2",
|
"better-sqlite3": "^11.8.1",
|
||||||
"body-parser": "1.20.3",
|
"body-parser": "1.20.3",
|
||||||
"cheerio": "^1.0.0",
|
"cheerio": "^1.0.0",
|
||||||
"cookie-session": "2.1.0",
|
"cookie-session": "2.1.0",
|
||||||
@@ -66,11 +66,11 @@
|
|||||||
"lowdb": "6.0.1",
|
"lowdb": "6.0.1",
|
||||||
"markdown": "^0.5.0",
|
"markdown": "^0.5.0",
|
||||||
"mixpanel": "^0.18.0",
|
"mixpanel": "^0.18.0",
|
||||||
"nanoid": "5.0.9",
|
"nanoid": "5.1.2",
|
||||||
"node-fetch": "3.3.2",
|
"node-fetch": "3.3.2",
|
||||||
"node-mailjet": "6.0.6",
|
"node-mailjet": "6.0.6",
|
||||||
"package-up": "^5.0.0",
|
"package-up": "^5.0.0",
|
||||||
"puppeteer": "^23.11.1",
|
"puppeteer": "^24.2.1",
|
||||||
"puppeteer-extra": "^3.3.6",
|
"puppeteer-extra": "^3.3.6",
|
||||||
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
||||||
"query-string": "9.1.1",
|
"query-string": "9.1.1",
|
||||||
@@ -88,21 +88,21 @@
|
|||||||
"vite": "5.4.11"
|
"vite": "5.4.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.26.0",
|
"@babel/core": "7.26.9",
|
||||||
"@babel/eslint-parser": "7.25.9",
|
"@babel/eslint-parser": "7.26.8",
|
||||||
"@babel/preset-env": "7.26.0",
|
"@babel/preset-env": "7.26.9",
|
||||||
"@babel/preset-react": "7.26.3",
|
"@babel/preset-react": "7.26.3",
|
||||||
"chai": "5.1.2",
|
"chai": "5.2.0",
|
||||||
"eslint": "8.56.0",
|
"eslint": "8.56.0",
|
||||||
"eslint-config-prettier": "8.8.0",
|
"eslint-config-prettier": "8.8.0",
|
||||||
"eslint-plugin-react": "7.37.3",
|
"eslint-plugin-react": "7.37.4",
|
||||||
"esmock": "2.6.9",
|
"esmock": "2.7.0",
|
||||||
"history": "5.3.0",
|
"history": "5.3.0",
|
||||||
"husky": "9.1.7",
|
"husky": "9.1.7",
|
||||||
"less": "4.2.1",
|
"less": "4.2.2",
|
||||||
"lint-staged": "15.3.0",
|
"lint-staged": "15.4.3",
|
||||||
"mocha": "10.8.2",
|
"mocha": "10.8.2",
|
||||||
"prettier": "3.4.2",
|
"prettier": "3.5.2",
|
||||||
"redux-logger": "3.0.6"
|
"redux-logger": "3.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,38 @@
|
|||||||
import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js';
|
import * as similarityCache from '../../lib/services/similarity-check/similarityCache.js';
|
||||||
import { get } from '../mocks/mockNotification.js';
|
import {get} from '../mocks/mockNotification.js';
|
||||||
import { mockFredy, providerConfig } from '../utils.js';
|
import {mockFredy, providerConfig} from '../utils.js';
|
||||||
import { expect } from 'chai';
|
import {expect} from 'chai';
|
||||||
import * as provider from '../../lib/provider/immonet.js';
|
import * as provider from '../../lib/provider/immonet.js';
|
||||||
|
|
||||||
describe('#immonet testsuite()', () => {
|
describe('#immonet testsuite()', () => {
|
||||||
after(() => {
|
after(() => {
|
||||||
similarityCache.stopCacheCleanup();
|
similarityCache.stopCacheCleanup();
|
||||||
});
|
});
|
||||||
provider.init(providerConfig.immonet, [], []);
|
provider.init(providerConfig.immonet, [], []);
|
||||||
it('should test immonet provider', async () => {
|
it('should test immonet provider', async () => {
|
||||||
const Fredy = await mockFredy();
|
const Fredy = await mockFredy();
|
||||||
return await new Promise((resolve) => {
|
return await new Promise((resolve) => {
|
||||||
const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'immonet', similarityCache);
|
const fredy = new Fredy(provider.config, null, provider.metaInformation.id, 'immonet', similarityCache);
|
||||||
fredy.execute().then((listing) => {
|
fredy.execute().then((listing) => {
|
||||||
expect(listing).to.be.a('array');
|
expect(listing).to.be.a('array');
|
||||||
const notificationObj = get();
|
const notificationObj = get();
|
||||||
expect(notificationObj).to.be.a('object');
|
expect(notificationObj).to.be.a('object');
|
||||||
expect(notificationObj.serviceName).to.equal('immonet');
|
expect(notificationObj.serviceName).to.equal('immonet');
|
||||||
notificationObj.payload.forEach((notify) => {
|
notificationObj.payload.forEach((notify) => {
|
||||||
/** check the actual structure **/
|
/** check the actual structure **/
|
||||||
expect(notify.id).to.be.a('string');
|
expect(notify.id).to.be.a('string');
|
||||||
expect(notify.price).to.be.a('string');
|
expect(notify.price).to.be.a('string');
|
||||||
expect(notify.size).to.be.a('string');
|
expect(notify.size).to.be.a('string');
|
||||||
expect(notify.title).to.be.a('string');
|
expect(notify.title).to.be.a('string');
|
||||||
expect(notify.link).to.be.a('string');
|
expect(notify.link).to.be.a('string');
|
||||||
expect(notify.address).to.be.a('string');
|
expect(notify.address).to.be.a('string');
|
||||||
|
|
||||||
/** check the values if possible **/
|
expect(notify.size).that.does.include('m²');
|
||||||
expect(notify.price).that.does.include('€');
|
expect(notify.title).to.be.not.empty;
|
||||||
expect(notify.size).that.does.include('m²');
|
expect(notify.address).to.be.not.empty;
|
||||||
expect(notify.title).to.be.not.empty;
|
});
|
||||||
expect(notify.address).to.be.not.empty;
|
resolve();
|
||||||
});
|
});
|
||||||
resolve();
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user