Making Fredy an ESM project (#70)

Making Fredy an ESM project
This commit is contained in:
Christian Kellner
2023-03-13 13:42:43 +01:00
committed by GitHub
parent 7d0ec72a0c
commit 2c5eceb0c1
69 changed files with 862 additions and 1567 deletions

View File

@@ -1,44 +1,36 @@
const { notificationAdapterRouter } = require('./routes/notificationAdapterRouter');
const { authInterceptor, cookieSession, adminInterceptor } = require('./security');
const { generalSettingsRouter } = require('./routes/generalSettingsRoute');
const { analyticsRouter } = require('./routes/analyticsRouter');
const { providerRouter } = require('./routes/providerRouter');
const { loginRouter } = require('./routes/loginRoute');
const config = require('../../conf/config.json');
const { userRouter } = require('./routes/userRoute');
const { jobRouter } = require('./routes/jobRouter');
const bodyParser = require('body-parser');
const service = require('restana')();
const files = require('serve-static');
const path = require('path');
const staticService = files(path.join(__dirname, '../../ui/public'));
import { notificationAdapterRouter } from './routes/notificationAdapterRouter.js';
import { authInterceptor, cookieSession, adminInterceptor } from './security.js';
import { generalSettingsRouter } from './routes/generalSettingsRoute.js';
import { analyticsRouter } from './routes/analyticsRouter.js';
import { providerRouter } from './routes/providerRouter.js';
import { loginRouter } from './routes/loginRoute.js';
import { config } from '../utils.js';
import { userRouter } from './routes/userRoute.js';
import { jobRouter } from './routes/jobRouter.js';
import bodyParser from 'body-parser';
import restana from 'restana';
import files from 'serve-static';
import path from 'path';
import { getDirName } from '../utils.js';
const service = restana();
const staticService = files(path.join(getDirName(), '../../ui/public'));
const PORT = config.port || 9998;
service.use(bodyParser.json());
service.use(cookieSession());
service.use(staticService);
service.use('/api/admin', authInterceptor());
service.use('/api/jobs', authInterceptor());
// /admin can only be accessed when user is having admin permissions
service.use('/api/admin', adminInterceptor());
service.use('/api/jobs/notificationAdapter', notificationAdapterRouter);
service.use('/api/admin/generalSettings', generalSettingsRouter);
service.use('/api/jobs/provider', providerRouter);
service.use('/api/jobs/insights', analyticsRouter);
service.use('/api/admin/users', userRouter);
service.use('/api/jobs', jobRouter);
service.use('/api/login', loginRouter);
/* eslint-disable no-console */
service.start(PORT).then(() => {
console.info(`Started API service on port ${PORT}`);
});
/* eslint-enable no-console */

View File

@@ -1,12 +1,10 @@
const service = require('restana')();
import restana from 'restana';
import * as listingStorage from '../../services/storage/listingsStorage.js';
const service = restana();
const analyticsRouter = service.newRouter();
const listingStorage = require('../../services/storage/listingsStorage');
analyticsRouter.get('/:jobId', async (req, res) => {
const { jobId } = req.params;
res.body = listingStorage.getListingProviderDataForAnalytics(jobId) || {};
res.send();
});
exports.analyticsRouter = analyticsRouter;
export { analyticsRouter };

View File

@@ -1,18 +1,16 @@
const service = require('restana')();
import restana from 'restana';
import { config, getDirName } from '../../utils.js';
import fs from 'fs';
const service = restana();
const generalSettingsRouter = service.newRouter();
const config = require('../../../conf/config.json');
const fs = require('fs');
generalSettingsRouter.get('/', async (req, res) => {
res.body = Object.assign({}, config);
res.send();
});
generalSettingsRouter.post('/', async (req, res) => {
const settings = req.body;
try {
fs.writeFileSync(`${__dirname}/../../../conf/config.json`, JSON.stringify(settings));
fs.writeFileSync(`${getDirName()}/../conf/config.json`, JSON.stringify(settings));
} catch (err) {
console.error(err);
res.send(new Error('Error while trying to write settings.'));
@@ -20,5 +18,4 @@ generalSettingsRouter.post('/', async (req, res) => {
}
res.send();
});
exports.generalSettingsRouter = generalSettingsRouter;
export { generalSettingsRouter };

View File

@@ -1,12 +1,12 @@
const service = require('restana')();
import restana from 'restana';
import fetch from 'node-fetch';
import * as jobStorage from '../../services/storage/jobStorage.js';
import * as userStorage from '../../services/storage/userStorage.js';
import * as immoscoutProvider from '../../provider/immoscout.js';
import { config } from '../../utils.js';
import { isAdmin } from '../security.js';
const service = restana();
const jobRouter = service.newRouter();
const fetch = require('node-fetch');
const jobStorage = require('../../services/storage/jobStorage');
const userStorage = require('../../services/storage/userStorage');
const immoscoutProvider = require('../../provider/immoscout');
const config = require('../../../conf/config.json');
const { isAdmin } = require('../security');
function doesJobBelongsToUser(job, req) {
const userId = req.session.currentUser;
if (userId == null) {
@@ -16,22 +16,16 @@ function doesJobBelongsToUser(job, req) {
if (user == null) {
return false;
}
return user.isAdmin || job.userId === job.userId;
}
jobRouter.get('/', async (req, res) => {
const isUserAdmin = isAdmin(req);
//show only the jobs which belongs to the user (or all of the user is an admin)
res.body = jobStorage.getJobs().filter((job) => isUserAdmin || job.userId === req.session.currentUser);
res.send();
});
jobRouter.get('/processingTimes', async (req, res) => {
let scrapingAntData = null;
if (config.scrapingAnt.apiKey != null && config.scrapingAnt.apiKey.length > 0) {
try {
const response = await fetch(`https://api.scrapingant.com/v1/usage?x-api-key=${config.scrapingAnt.apiKey}`);
@@ -40,16 +34,13 @@ jobRouter.get('/processingTimes', async (req, res) => {
console.error('Could not query plan data from scraping ant.', Exception);
}
}
res.body = {
interval: config.interval,
lastRun: config.lastRun || null,
scrapingAntData,
};
res.send();
});
jobRouter.post('/', async (req, res) => {
const { provider, notificationAdapter, name, blacklist = [], jobId, enabled } = req.body;
if (
@@ -77,7 +68,6 @@ jobRouter.post('/', async (req, res) => {
}
res.send();
});
jobRouter.delete('', async (req, res) => {
const { jobId } = req.body;
try {
@@ -93,7 +83,6 @@ jobRouter.delete('', async (req, res) => {
}
res.send();
});
jobRouter.put('/:jobId/status', async (req, res) => {
const { status } = req.body;
const { jobId } = req.params;
@@ -113,5 +102,4 @@ jobRouter.put('/:jobId/status', async (req, res) => {
}
res.send();
});
exports.jobRouter = jobRouter;
export { jobRouter };

View File

@@ -1,8 +1,8 @@
const service = require('restana')();
import restana from 'restana';
import * as userStorage from '../../services/storage/userStorage.js';
import * as hasher from '../../services/security/hash.js';
const service = restana();
const loginRouter = service.newRouter();
const userStorage = require('../../services/storage/userStorage');
const hasher = require('../../services/security/hash');
loginRouter.get('/user', async (req, res) => {
const currentUserId = req.session.currentUser;
const currentUser = currentUserId == null ? null : userStorage.getUser(currentUserId);
@@ -16,17 +16,13 @@ loginRouter.get('/user', async (req, res) => {
}
res.send();
});
loginRouter.post('/', async (req, res) => {
const { username, password } = req.body;
const user = userStorage.getUsers(true).find((user) => user.username === username);
if (user == null) {
res.send(401);
return;
}
if (user.password === hasher.hash(password)) {
req.session.currentUser = user.id;
userStorage.setLastLoginToNow({ userId: user.id });
@@ -35,13 +31,10 @@ loginRouter.post('/', async (req, res) => {
} else {
console.error(`User ${username} tried to login, but password was wrong.`);
}
res.send(401);
});
loginRouter.post('/logout', async (req, res) => {
req.session = null;
res.send(200);
});
exports.loginRouter = loginRouter;
export { loginRouter };

View File

@@ -1,13 +1,13 @@
const fs = require('fs');
const service = require('restana')();
import fs from 'fs';
import restana from 'restana';
const service = restana();
const notificationAdapterRouter = service.newRouter();
const notificationAdapterList = fs.readdirSync('./lib//notification/adapter').filter((file) => file.endsWith('.js'));
const notificationAdapter = notificationAdapterList.map((pro) => {
return require(`../../notification/adapter/${pro}`);
});
const notificationAdapter = await Promise.all(
notificationAdapterList.map(async (pro) => {
return await import(`../../notification/adapter/${pro}`);
})
);
notificationAdapterRouter.post('/try', async (req, res) => {
const { id, fields } = req.body;
const adapter = notificationAdapter.find((adapter) => adapter.config.id === id);
@@ -24,7 +24,6 @@ notificationAdapterRouter.post('/try', async (req, res) => {
enabled: true,
id,
});
try {
await adapter.send({
serviceName: 'TestCall',
@@ -40,16 +39,13 @@ notificationAdapterRouter.post('/try', async (req, res) => {
notificationConfig,
jobKey: 'TestJob',
});
res.send();
} catch (Exception) {
res.send(new Error(Exception));
}
});
notificationAdapterRouter.get('/', async (req, res) => {
res.body = notificationAdapter.map((adapter) => adapter.config);
res.send();
});
exports.notificationAdapterRouter = notificationAdapterRouter;
export { notificationAdapterRouter };

View File

@@ -1,16 +1,15 @@
const fs = require('fs');
const service = require('restana')();
import fs from 'fs';
import restana from 'restana';
const service = restana();
const providerRouter = service.newRouter();
const providerList = fs.readdirSync('./lib/provider').filter((file) => file.endsWith('.js'));
const provider = providerList.map((pro) => {
return require(`../../provider/${pro}`).metaInformation;
});
const provider = await Promise.all(
providerList.map(async (pro) => {
return await import(`../../provider/${pro}`);
})
);
providerRouter.get('/', async (req, res) => {
res.body = provider;
res.body = provider.map((p) => p.metaInformation);
res.send();
});
exports.providerRouter = providerRouter;
export { providerRouter };

View File

@@ -1,33 +1,27 @@
const service = require('restana')();
import restana from 'restana';
import * as userStorage from '../../services/storage/userStorage.js';
import * as jobStorage from '../../services/storage/jobStorage.js';
const service = restana();
const userRouter = service.newRouter();
const userStorage = require('../../services/storage/userStorage');
const jobStorage = require('../../services/storage/jobStorage');
function checkIfAnyAdminAfterRemovingUser(userIdToBeRemoved, allUser) {
return allUser.filter((user) => user.id !== userIdToBeRemoved && user.isAdmin).length > 0;
}
function checkIfUserToBeRemovedIsLoggedIn(userIdToBeRemoved, req) {
return req.session.currentUser === userIdToBeRemoved;
}
const nullOrEmpty = (str) => str == null || str.length === 0;
userRouter.get('/', async (req, res) => {
res.body = userStorage.getUsers(false);
res.send();
});
userRouter.get('/:userId', async (req, res) => {
const { userId } = req.params;
res.body = userStorage.getUser(userId);
res.send();
});
userRouter.delete('/', async (req, res) => {
const { userId } = req.body;
const allUser = userStorage.getUsers(false);
if (!checkIfAnyAdminAfterRemovingUser(userId, allUser)) {
res.send(new Error('You are trying to remove the last admin user. This is prohibited.'));
return;
@@ -36,14 +30,11 @@ userRouter.delete('/', async (req, res) => {
res.send(new Error('You are trying to remove yourself. This is prohibited.'));
return;
}
//TODO: Remove also analytics
jobStorage.removeJobsByUserId(userId);
userStorage.removeUser(userId);
res.send();
});
userRouter.post('/', async (req, res) => {
const { username, password, password2, isAdmin, userId } = req.body;
if (password !== password2) {
@@ -55,22 +46,18 @@ userRouter.post('/', async (req, res) => {
return;
}
const allUser = userStorage.getUsers(false);
if (!isAdmin && !checkIfAnyAdminAfterRemovingUser(userId, allUser)) {
res.send(
new Error('You cannot change the admin flag for this user as otherwise, there is no other user in the system')
);
return;
}
userStorage.upsertUser({
userId,
username,
password,
isAdmin,
});
res.send();
});
exports.userRouter = userRouter;
export { userRouter };

View File

@@ -1,15 +1,12 @@
const userStorage = require('../services/storage/userStorage');
const cookieSession = require('cookie-session');
const { nanoid } = require('nanoid');
import * as userStorage from '../services/storage/userStorage.js';
import cookieSession from 'cookie-session';
import { nanoid } from 'nanoid';
const unauthorized = (res) => {
return res.send(401);
};
const isUnauthorized = (req) => {
return req.session.currentUser == null;
};
const isAdmin = (req) => {
if (!isUnauthorized(req)) {
const user = userStorage.getUser(req.session.currentUser);
@@ -17,7 +14,6 @@ const isAdmin = (req) => {
}
return false;
};
const authInterceptor = () => {
return (req, res, next) => {
if (isUnauthorized(req)) {
@@ -27,7 +23,6 @@ const authInterceptor = () => {
}
};
};
const adminInterceptor = () => {
return (req, res, next) => {
if (!isAdmin(req)) {
@@ -37,8 +32,7 @@ const adminInterceptor = () => {
}
};
};
exports.cookieSession = (userId) => {
const cookieSession$0 = (userId) => {
return cookieSession({
name: 'fredy-admin-session',
keys: ['fredy', 'super', 'fancy', 'key', nanoid()],
@@ -46,8 +40,8 @@ exports.cookieSession = (userId) => {
maxAge: 8 * 60 * 60 * 1000, // 8 hours
});
};
exports.adminInterceptor = adminInterceptor;
exports.authInterceptor = authInterceptor;
exports.isUnauthorized = isUnauthorized;
exports.isAdmin = isAdmin;
export { cookieSession$0 as cookieSession };
export { adminInterceptor };
export { authInterceptor };
export { isUnauthorized };
export { isAdmin };