Commit 2ad1a286 authored by Benjamin Bouvier's avatar Benjamin Bouvier
Browse files

Add ESLint validation and fix the server;

parent 6cf4df10
# node_modules ignored by default
# ignore files compiled
build/
# ignore vendor JS files
client/flux/
client/vendor/
This diff is collapsed.
.PHONY: all build dev install-node-deps run install install-debian-deps install-debian
.PHONY: all build dev lint run run-cozy install-node-deps install install-debian-deps install-debian lint
all: build
......@@ -8,9 +8,8 @@ build:
dev: build
./scripts/dev.sh
# npm install also causes a build, see package.json
install-node-deps:
npm install
lint:
./scripts/lint.sh
run: install-node-deps
node bin/kresus.js
......@@ -18,6 +17,10 @@ run: install-node-deps
run-cozy: install-node-deps
node build/server/index.js
# npm install also causes a build, see package.json
install-node-deps:
npm install
install:
npm -g install
......
#!/bin/bash
./node_modules/eslint/bin/eslint.js ./server
import * as path from 'path-extra';
import americano from 'americano';
import i18n from 'cozy-i18n-helper';
const nodeEnv = process.env.NODE_ENV;
process.kresus = process.kresus || {};
process.kresus.prod = typeof nodeEnv !== 'undefined' && ["production", "prod"].indexOf(nodeEnv) !== -1;
process.kresus.prod = typeof nodeEnv !== 'undefined' &&
['production', 'prod'].indexOf(nodeEnv) !== -1;
process.kresus.dev = !process.kresus.prod;
process.kresus.standalone = process.kresus.standalone || false;
// Config is loaded from americano, which doesn't support babel default export.
module.exports = {
common: [
americano.bodyParser({limit: '10mb'}),
americano.bodyParser({ limit: '10mb' }),
americano.methodOverride(),
americano.errorHandler({
dumpExceptions: true,
showStack: true
}),
americano.static(__dirname + '/../client', {
americano.static(path.join(__dirname, '..', 'client'), {
maxAge: 86400000
}),
i18n.middleware
......
......@@ -2,9 +2,9 @@ import Access from '../models/access';
import Account from '../models/account';
import AccountManager from '../lib/accounts-manager';
import Errors from './errors';
import getErrorCode from './errors';
import {makeLogger, sendErr, asyncErr} from '../helpers';
import { makeLogger, sendErr, asyncErr } from '../helpers';
let log = makeLogger('controllers/accesses');
......@@ -15,12 +15,12 @@ export async function preloadAccess(req, res, next, accessId) {
try {
let access = await Access.find(accessId);
if (!access) {
throw { status: 404, message: "bank access not found" };
throw { status: 404, message: 'bank access not found' };
}
req.preloaded = { access };
next();
} catch (err) {
return asyncErr(res, err, "when finding bank access");
return asyncErr(res, err, 'when finding bank access');
}
}
......@@ -30,14 +30,14 @@ export async function create(req, res) {
let params = req.body;
if (!params.bank || !params.login || !params.password)
return sendErr(res, "missing parameters", 400, "missing parameters");
return sendErr(res, 'missing parameters', 400, 'missing parameters');
let access;
let createdAccess = false, retrievedAccounts = false;
try {
let similarAccesses = await Access.allLike(params);
if (similarAccesses.length) {
throw { status: 409, code: Errors('BANK_ALREADY_EXISTS') }
throw { status: 409, code: getErrorCode('BANK_ALREADY_EXISTS') };
}
access = await Access.create(params);
......@@ -52,12 +52,12 @@ export async function create(req, res) {
await manager.retrieveOperationsByAccess(access);
res.sendStatus(201);
} catch (err) {
log.error("The access process creation failed, cleaning up...");
log.error('The access process creation failed, cleaning up...');
// Silently swallow errors here, we don't want to catch errors in error
// code.
if (retrievedAccounts) {
log.info("\tdeleting accounts...");
log.info('\tdeleting accounts...');
let accounts = await Account.byAccess(access);
for (let acc of accounts) {
await acc.destroy();
......@@ -65,11 +65,11 @@ export async function create(req, res) {
}
if (createdAccess) {
log.info("\tdeleting access...");
log.info('\tdeleting access...');
await access.destroy();
}
return asyncErr(res, err, "when creating a bank access");
return asyncErr(res, err, 'when creating a bank access');
}
}
......@@ -79,10 +79,11 @@ export async function create(req, res) {
export async function fetchOperations(req, res) {
try {
// Fetch operations
await commonAccountManager.retrieveOperationsByAccess(req.preloaded.access);
let access = req.preloaded.access;
await commonAccountManager.retrieveOperationsByAccess(access);
res.sendStatus(200);
} catch(err) {
return asyncErr(res, err, "when fetching operations");
} catch (err) {
return asyncErr(res, err, 'when fetching operations');
}
}
......@@ -90,10 +91,11 @@ export async function fetchOperations(req, res) {
// client as well.
export async function fetchAccounts(req, res) {
try {
await commonAccountManager.retrieveAccountsByAccess(req.preloaded.access);
let access = req.preloaded.access;
await commonAccountManager.retrieveAccountsByAccess(access);
fetchOperations(req, res);
} catch (err) {
return asyncErr(res, err, "when fetching accounts");
return asyncErr(res, err, 'when fetching accounts');
}
}
......@@ -103,8 +105,8 @@ export async function destroy(req, res) {
try {
await req.preloaded.access.destroy();
res.sendStatus(204);
} catch(err) {
return asyncErr(res, err, "when deleting bank access");
} catch (err) {
return asyncErr(res, err, 'when deleting bank access');
}
}
......@@ -114,13 +116,12 @@ export async function update(req, res) {
let access = req.body;
if (!access.password)
return sendErr(res, "missing password", 400, "missing password");
return sendErr(res, 'missing password', 400, 'missing password');
try {
await req.preloaded.access.updateAttributes(access);
res.sendStatus(200);
} catch(err) {
return asyncErr(res, err, "when updating bank access");
} catch (err) {
return asyncErr(res, err, 'when updating bank access');
}
}
......@@ -3,7 +3,7 @@ import Operation from '../models/operation';
import Access from '../models/access';
import Alert from '../models/alert';
import {makeLogger, sendErr, asyncErr} from '../helpers';
import { makeLogger, asyncErr } from '../helpers';
let log = makeLogger('controllers/accounts');
......@@ -12,19 +12,19 @@ export async function preloadAccount(req, res, next, accountID) {
try {
let account = await Account.find(accountID);
if (!account) {
throw {status: 404, message:"Bank account not found"};
throw { status: 404, message: 'Bank account not found' };
}
req.preloaded = {account};
req.preloaded = { account };
next();
} catch(err) {
return asyncErr(res, err, "when preloading a bank account");
} catch (err) {
return asyncErr(res, err, 'when preloading a bank account');
}
}
// Destroy an account and all its operations, alerts, and accesses if no other
// accounts are bound to this access.
export async function DestroyWithOperations(account) {
export async function destroyWithOperations(account) {
log.info(`Removing account ${account.title} from database...`);
log.info(`\t-> Destroy operations for account ${account.title}`);
......@@ -36,9 +36,9 @@ export async function DestroyWithOperations(account) {
log.info(`\t-> Destroy account ${account.title}`);
await account.destroy();
let accounts = await Account.byAccess({id: account.bankAccess});
let accounts = await Account.byAccess({ id: account.bankAccess });
if (accounts && accounts.length === 0) {
log.info("\t-> No other accounts bound: destroying access.");
log.info('\t-> No other accounts bound: destroying access.');
await Access.destroy(account.bankAccess);
}
}
......@@ -47,10 +47,10 @@ export async function DestroyWithOperations(account) {
// Delete account, operations and alerts.
export async function destroy(req, res) {
try {
await DestroyWithOperations(req.preloaded.account);
await destroyWithOperations(req.preloaded.account);
res.sendStatus(204);
} catch(err) {
return asyncErr(res, err, "when destroying an account");
} catch (err) {
return asyncErr(res, err, 'when destroying an account');
}
}
......@@ -58,9 +58,10 @@ export async function destroy(req, res) {
// Get operations of a given bank account
export async function getOperations(req, res) {
try {
let operations = await Operation.byBankSortedByDate(req.preloaded.account);
let account = req.preloaded.account;
let operations = await Operation.byBankSortedByDate(account);
res.status(200).send(operations);
} catch(err) {
return asyncErr(res, err, "when getting operations for a given bank account");
} catch (err) {
return asyncErr(res, err, 'when getting operations for a bank account');
}
}
import Account from '../models/account';
import Alert from '../models/alert';
import {asyncErr, sendErr} from '../helpers';
import { asyncErr, sendErr } from '../helpers';
export async function loadAlert(req, res, next, alertId) {
try {
let alert = await Alert.find(alertId);
if (!alert) {
throw {status: 404, message: "bank alert not found"};
throw { status: 404, message: 'bank alert not found' };
}
req.preloaded = req.preloaded || {};
req.preloaded.alert = alert;
next();
} catch(err) {
} catch (err) {
return asyncErr(res, err, 'when preloading alert');
}
}
......@@ -22,19 +22,20 @@ export async function create(req, res) {
let newAlert = req.body;
if (!newAlert ||
typeof newAlert.bankAccount !== 'string' ||
typeof newAlert.type !== 'string')
{
return sendErr(res, "when creating an alert", 400, 'missing parameters');
typeof newAlert.type !== 'string') {
return sendErr(res, 'when creating an alert', 400,
'missing parameters');
}
try {
let alert = await Alert.create(newAlert);
if (!await Account.byAccountNumber(newAlert.bankAccount)) {
throw {status: 404, message: "bank account not found"};
let account = await Account.byAccountNumber(newAlert.bankAccount);
if (!account) {
throw { status: 404, message: 'bank account not found' };
}
res.status(201).send(alert);
} catch(err) {
return asyncErr(res, err, "when creating an alert");
} catch (err) {
return asyncErr(res, err, 'when creating an alert');
}
}
......@@ -42,7 +43,7 @@ export async function destroy(req, res) {
try {
await req.preloaded.alert.destroy();
res.sendStatus(204);
} catch(err) {
} catch (err) {
return asyncErr(res, err, 'when deleting a bank alert');
}
}
......@@ -51,8 +52,7 @@ export async function update(req, res) {
try {
let alert = await req.preloaded.alert.updateAttributes(req.body);
res.status(200).send(alert);
} catch(err) {
return asyncErr(res, err, "when updating a bank alert");
} catch (err) {
return asyncErr(res, err, 'when updating a bank alert');
}
}
......@@ -8,13 +8,13 @@ import OperationType from '../models/operationtype';
import Config from '../models/config';
import Cozy from '../models/cozyinstance';
import {makeLogger, sendErr, asyncErr} from '../helpers';
import { makeLogger, sendErr, asyncErr } from '../helpers';
let log = makeLogger('controllers/all');
const ERR_MSG_LOADING_ALL = 'Error when loading all Kresus data';
async function GetAllData() {
async function getAllData() {
let ret = {};
ret.accounts = await Account.all();
ret.alerts = await Alert.all();
......@@ -29,70 +29,70 @@ async function GetAllData() {
export async function all(req, res) {
try {
let ret = await GetAllData();
let ret = await getAllData();
res.status(200).send(ret);
} catch(err) {
} catch (err) {
err.code = ERR_MSG_LOADING_ALL;
return asyncErr(res, err, "when loading all data");
return asyncErr(res, err, 'when loading all data');
}
}
// Strip away Couchdb/pouchdb metadata.
function CleanMeta(obj) {
obj._id = undefined;
obj._rev = undefined;
function cleanMeta(obj) {
delete obj._id;
delete obj._rev;
}
// Sync function
function CleanData(all) {
function cleanData(world) {
// Bank information is static and shouldn't be exported.
delete all.banks;
delete world.banks;
// Cozy information is very tied to the instance.
if (all.cozy)
delete all.cozy;
if (world.cozy)
delete world.cozy;
let accessMap = {};
let nextAccessId = 0;
all.accesses = all.accesses || [];
for (let a of all.accesses) {
world.accesses = world.accesses || [];
for (let a of world.accesses) {
accessMap[a.id] = nextAccessId;
a.id = nextAccessId++;
// Strip away password
a.password = undefined;
CleanMeta(a);
delete a.password;
cleanMeta(a);
}
all.accounts = all.accounts || [];
for (let a of all.accounts) {
world.accounts = world.accounts || [];
for (let a of world.accounts) {
a.bankAccess = accessMap[a.bankAccess];
// Strip away id
a.id = undefined;
CleanMeta(a);
delete a.id;
cleanMeta(a);
}
let categoryMap = {};
let nextCatId = 0;
all.categories = all.categories || [];
for (let c of all.categories) {
world.categories = world.categories || [];
for (let c of world.categories) {
categoryMap[c.id] = nextCatId;
c.id = nextCatId++;
CleanMeta(c);
cleanMeta(c);
}
let opTypeMap = {};
let nextOpTypeId = 0;
all.operationtypes = all.operationtypes || [];
for (let o of all.operationtypes) {
world.operationtypes = world.operationtypes || [];
for (let o of world.operationtypes) {
opTypeMap[o.id] = nextOpTypeId;
o.id = nextOpTypeId++;
CleanMeta(o);
cleanMeta(o);
}
all.operations = all.operations || [];
for (let o of all.operations) {
world.operations = world.operations || [];
for (let o of world.operations) {
if (typeof o.categoryId !== 'undefined') {
let cid = o.categoryId;
......@@ -111,76 +111,78 @@ function CleanData(all) {
}
// Strip away id
o.id = undefined;
CleanMeta(o);
delete o.id;
cleanMeta(o);
}
all.settings = all.settings || [];
for (let s of all.settings) {
s.id = undefined;
CleanMeta(s);
world.settings = world.settings || [];
for (let s of world.settings) {
delete s.id;
cleanMeta(s);
}
all.alerts = all.alerts || [];
for (let a of all.alerts) {
a.id = undefined;
CleanMeta(a);
world.alerts = world.alerts || [];
for (let a of world.alerts) {
delete a.id;
cleanMeta(a);
}
return all;
return world;
}
module.exports.export = async function(req, res) {
try {
let ret = await GetAllData();
let ret = await getAllData();
ret.accesses = await Access.all();
ret = CleanData(ret);
ret = cleanData(ret);
res.setHeader('Content-Type', 'application/json');
res.status(200).send(JSON.stringify(ret, null, ' '));
} catch (err) {
err.code = ERR_MSG_LOADING_ALL;
return asyncErr(res, err, "when exporting data");
return asyncErr(res, err, 'when exporting data');
}
}
};
module.exports.import = async function(req, res) {
if (!req.body.all)
return sendErr(res, "missing parameter all", 400, "missing parameter 'all' in the file");
let all = req.body.all;
all.accesses = all.accesses || [];
all.accounts = all.accounts || [];
all.alerts = all.alerts || [];
all.categories = all.categories || [];
all.operationtypes = all.operationtypes || [];
all.operations = all.operations || [];
all.settings = all.settings || [];
return sendErr(res, 'missing parameter all', 400,
"missing parameter 'all' in the file");
let world = req.body.all;
world.accesses = world.accesses || [];
world.accounts = world.accounts || [];
world.alerts = world.alerts || [];
world.categories = world.categories || [];
world.operationtypes = world.operationtypes || [];
world.operations = world.operations || [];
world.settings = world.settings || [];
try {
log.info(`Importing:
accesses: ${all.accesses.length}
accounts: ${all.accounts.length}
alerts: ${all.alerts.length}
categories: ${all.categories.length}
operation-types: ${all.operationtypes.length}
settings: ${all.settings.length}
operations: ${all.operations.length}
accesses: ${world.accesses.length}
accounts: ${world.accounts.length}
alerts: ${world.alerts.length}
categories: ${world.categories.length}
operation-types: ${world.operationtypes.length}
settings: ${world.settings.length}
operations: ${world.operations.length}
`);
log.info('Import accesses...');
let accessMap = {};
for (let access of all.accesses) {
for (let access of world.accesses) {
let accessId = access.id;
access.id = undefined;
delete access.id;
let created = await Access.create(access);
accessMap[accessId] = created.id;
}
log.info('Done.');
log.info('Import accounts...');
for (let account of all.accounts) {
for (let account of world.accounts) {
if (!accessMap[account.bankAccess]) {
throw { status: 400, message: `unknown bank access ${account.bankAccess}` }
throw { status: 400,
message: `unknown bank access ${account.bankAccess}` };
}
account.bankAccess = accessMap[account.bankAccess];
await Account.create(account);
......@@ -195,11 +197,12 @@ module.exports.import = async function(req, res) {
}
let categoryMap = {};
for (let category of all.categories) {
for (let category of world.categories) {
let catId = category.id;
category.id = undefined;
delete category.id;
if (existingCategoriesMap.has(category.title)) {
categoryMap[catId] = existingCategoriesMap.get(category.title).id;
let existing = existingCategoriesMap.get(category.title);
categoryMap[catId]