Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature db update #22

Merged
merged 6 commits into from
Jan 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
src/data/*
data/*
.vscode
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon --ignore 'data/*' src/server.js",
"start-debug": "nodemon --inspect --ignore 'data/*' src/server.js",
"postinstall": "node src/install.js"
},
"repository": {
Expand Down
4 changes: 2 additions & 2 deletions src/adminPage/app/controllers/beverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ app.controller('beverageController', function($scope, $http, $window) {

$scope.title = "Beverage Overview";
$scope.icon = "fa-beer";

$scope.searchableGlobal = false;
$scope.searchableLocal = true;
$scope.enumerate = true;
Expand Down Expand Up @@ -142,7 +142,7 @@ app.controller('beverageController', function($scope, $http, $window) {
}
},
{
name: "count",
name: "stock",
displayname: "Currently in Stock:",
display: function(data) {
return data;
Expand Down
225 changes: 127 additions & 98 deletions src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
* Author: Sandro Speth
* Author: Tobias Wältken
*/

/* jslint esversion: 6 */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe create/decide on project wide jslint settings to enforce a uniform coding style

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be another issue

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is now #23


// Imports
const sqlite3 = require('sqlite3');
const express = require('express');
Expand All @@ -17,10 +20,8 @@ const dirname = fs.realpathSync('./');
// Database
var db = new sqlite3.Database(dirname + '/data/history.db');
// Arrays
var beverages = JSON.parse(fs.readFileSync(dirname + '/data/beverages.json', 'utf8'));
var auth = JSON.parse(fs.readFileSync(dirname + '/data/auth.json', 'utf8'));
// NodeJS HashMap
var users = new HashMap(JSON.parse(fs.readFileSync(dirname + '/data/users.json', 'utf8')));
var tokens = new HashMap();

/**
Expand All @@ -43,11 +44,6 @@ function contains(array, item) {
return bool;
}

// Actual wrong method
function isTimePassed(date) {
return !(+(new Date(new Date(date).getTime() + 30000)) > +(new Date()));
}

/**
* This function wraps a given middleware function with a check for the user
* tokens in the request to reduce code clutter.
Expand Down Expand Up @@ -152,31 +148,31 @@ api.get('/token', adminAccess(function (req, res) {
api.post('/orders', userAccess(function (req, res) {
let user = req.query.user;
let beverage = req.query.beverage;

if (user == undefined || beverage == undefined ||
user === '' || beverage === '' || !contains(users.keys(), user) || !contains(beverages, beverage)) {
user === '' || beverage === '') {
res.status(400).end('Fail to order the beverage for the user');
return;
} else {
let cost = 0;
for (i = 0; i < beverages.length; i++) {
if (beverages[i].name === beverage) {
cost = beverages[i].price;
beverages[i].count--;
fs.writeFile(dirname + '/data/beverages.json', JSON.stringify(beverages), 'utf8', function(error) {
console.log('[API] [FAIL] can\'t write /data/beverages.json');
});
break;
let stmt = db.prepare("SELECT price, stock FROM Beverages WHERE name = ?;");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name it stmt0 for consistency with stmt1, stmt2 and stmt3 ;-)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be new issue

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#26

stmt.get(beverage, function(err, result) {
if (result == undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check err first to allow for better error handling as well as catching database errors and other anomalies.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is already a issue (#16, #17). I think a new pull request / issue for additional functionality/ error handling is better than to bloat this PR

console.log('[API] [FAIL] can\'t find beverage '+beverage);
return;
}
}

users.get(user).balance -= cost;
fs.writeFile(dirname + '/data/users.json', JSON.stringify(users), 'utf8');

var stmt = db.prepare("INSERT INTO History(id, user, reason, amount, timestamp) VALUES (?, ?, ?, ?, ?);");
stmt.run(uuidv4(), user, beverage, -cost, new Date().toUTCString());
stmt.finalize();

let cost = result.price;

let stmt1 = db.prepare("UPDATE Beverages SET stock = stock-1 WHERE name = ?;");
stmt1.run(beverage);

let stmt2 = db.prepare("UPDATE Users SET balance = balance - ? WHERE name = ?;");
stmt2.run(cost, user);

var stmt3 = db.prepare("INSERT INTO History(id, user, reason, amount, beverage, beverage_count) VALUES (?, ?, ?, ?, ?, ?);");
stmt3.run(uuidv4(), user, beverage, -cost, beverage, 1);
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[important] missing the check if the given username exists!
[minor] missing error checking

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checking if user exists is needed in more than one method and should be as simple as a method call. The problem is, that sql statements work with callbacks. I don't have a good solution yet for this. => should be a new issue

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#24



res.sendStatus(200);
}
}));
Expand All @@ -189,7 +185,8 @@ api.get('/orders', userAccess(function (req, res) {
}

let histories = [];
db.each("SELECT id, user, reason, amount, timestamp FROM History LIMIT " + limit, function(err, row) {
var stmt = db.prepare("SELECT id, user, reason, amount, beverage, beverage_count, timestamp FROM History ORDER BY timestamp DESC LIMIT ?;");
stmt.each(limit, function(err, row) {
histories.push(row);
}, function() {
res.status(200).end(JSON.stringify(histories));
Expand All @@ -199,15 +196,16 @@ api.get('/orders', userAccess(function (req, res) {
api.get('/orders/:userId', userAccess(function (req, res) {
let userId = req.params.userId;
let limit = req.query.limit;
if (userId === undefined || userId === '' || !users.has(userId)) {
if (userId === undefined || userId === '') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing the check if the given username exists!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#24

res.status(404).end('User not found');
return;
} else {
if (limit === undefined) {
limit = 1000;
}
let userHistories = [];
db.each("SELECT id, user, reason, amount, timestamp FROM History WHERE user = '" + userId + "' LIMIT " + limit, function(err, row) {
var stmt = db.prepare("SELECT id, user, reason, amount, beverage, beverage_count, timestamp FROM History WHERE user = ? ORDER BY timestamp DESC LIMIT ?;");
stmt.each(userId, limit, function(err, row) {
userHistories.push(row);
}, function() {
res.status(200).end(JSON.stringify(userHistories));
Expand All @@ -216,51 +214,82 @@ api.get('/orders/:userId', userAccess(function (req, res) {
}));

api.delete('/orders/:orderId', function (req, res) {
// FIXME think about using userAccess, adminAcces or keep it locally when
// solving Issue#5 (https://github.com/spethso/Drinklist/issues/5)
let orderId = req.params.orderId;
let token = req.header('X-Auth-Token');
if (!tokens.has(token)) {
console.log('[API] [WARN] Wrong token ' + token);
res.status(403).end('Forbidden');
return;
}
//if (!tokens.get(token).root) {
// res.status(401).end('Unauthorized');
// return;
//}
if (orderId != undefined && orderId != '') {
let deleted = true; //TODO check for error in sql

var stmt = db.prepare("DELETE FROM History WHERE id == ?;");
stmt.run(orderId);
stmt.finalize();
let stmt = db.prepare("SELECT timestamp > (DATETIME('now', '-30 seconds', 'localtime')) as fresh, id, user, amount, beverage, beverage_count, timestamp FROM History WHERE id = ? LIMIT 1;");
stmt.get(orderId, function(err, result) {
if (result == undefined) {
// no order to delete!
return;
}

if (deleted) {
res.sendStatus(200);
} else {
res.sendStatus(400);
}
if (result.fresh == false && !tokens.get(token).root) {
// too late to delete
res.sendStatus(400);
return;
}

function updateUserAndBeverage(result) {
if (result.amount !== 0 && result.user !== '') {
let stmt = db.prepare("UPDATE Users SET balance = balance - ? WHERE name = ?;");
stmt.run(result.amount, result.user);
}

if (result.beverage !== '') {
let stmt = db.prepare("UPDATE Beverages SET stock = stock + ? WHERE name = ?");
stmt.run(result.beverage_count, result.beverage);
}
}

if (result.fresh) {
updateUserAndBeverage(result);
var stmt = db.prepare("DELETE FROM History WHERE id = ?;");
stmt.run(orderId);
stmt.finalize();
res.sendStatus(200);
} else {
let stmt = db.prepare("SELECT * FROM History WHERE reason = ? LIMIT 1;");
stmt.get(result.id, function(err, existing) {
if (existing == undefined) { // prevent double undo
updateUserAndBeverage(result);
let stmt = db.prepare("INSERT INTO History(id, user, reason, amount, beverage, beverage_count) VALUES (?, ?, ?, ?, ?, ?);");
stmt.run(uuidv4(), result.user, result.id, -result.amount, result.beverage, -result.beverage_count);
res.sendStatus(200);
} else {
// double undo error code here...
res.sendStatus(500);
}
});
}
});
} else {
res.sendStatus(400);
}
});

api.get('/beverages', userAccess(function (req, res) {
res.status(200).end(JSON.stringify(beverages));
let beverages = [];
var stmt = db.prepare("SELECT name, stock, price FROM Beverages ORDER BY name;");
stmt.each(function(err, row) {
beverages.push(row);
}, function() {
res.status(200).end(JSON.stringify(beverages));
});
}));

api.post('/beverages', adminAccess(function (req, res) {
let bev = req.query.beverage;
let price = req.query.price;
if (bev != undefined && price != undefined && bev != '') {
let beverage = {
name: bev,
price: price,
count: 0
};
beverages.push(beverage);
fs.writeFile(dirname + '/data/beverages.json', JSON.stringify(beverages), 'utf8');
let stmt = db.prepare("INSERT INTO Beverages (name, price) VALUES (?, ?)");
stmt.run(bev, price);
res.sendStatus(200);
} else {
throw new Error('Test Error');
Expand All @@ -272,19 +301,13 @@ api.patch('/beverages/:beverage', adminAccess(function (req, res) {
let price = req.query.price;
let count = req.query.count;
if (bev != undefined && bev != '') {
for (let i = 0; i < beverages.length; i++) {
let beverage = beverages[i];
console.log(beverage);
if (beverage.name == bev) {
if (price != undefined) {
beverage.price = price;
}
if (count != undefined) {
beverage.count += new Number(count);
}
fs.writeFile(dirname + '/data/beverages.json', JSON.stringify(beverages), 'utf8');
break;
}
if (price != undefined) {
let stmt = db.prepere("UPDATE Beverages SET price = ? WHERE name = ?;");
stmt.run(parseInt(price), bev);
}
if (count != undefined) {
let stmt = db.prepere("UPDATE Beverages SET stock = stock + ? WHERE name = ?;");
stmt.run(parseInt(count), bev);
}
res.sendStatus(200);
} else {
Expand All @@ -295,16 +318,8 @@ api.patch('/beverages/:beverage', adminAccess(function (req, res) {
api.delete('/beverages/:beverage', adminAccess(function (req, res) {
let bev = req.params.beverage;
if (bev != undefined && bev != '') {
let index = 0;
for (let i = 0; i < beverages.length; i++) {
let beverage = beverages[i];
if (beverage.name == bev) {
index = i;
break;
}
}
beverages.splice(index, 1);
fs.writeFile(dirname + '/data/beverages.json', JSON.stringify(beverages), 'utf8');
let stmt = db.prepare("DELETE FROM Beverages WHERE name = ?;");
stmt.run(bev);
res.sendStatus(200);
} else {
res.sendStatus(400);
Expand All @@ -313,31 +328,46 @@ api.delete('/beverages/:beverage', adminAccess(function (req, res) {

api.get('/users', userAccess(function (req, res) {
let token = req.header('X-Auth-Token');

let users = [];
var stmt = db.prepare("SELECT name FROM Users ORDER BY name;");
var stmtAdmin = db.prepare("SELECT name, balance FROM Users ORDER BY name;");
if (!tokens.get(token).root) {
res.status(200).end(JSON.stringify(users.keys()));
stmt.each(function(err, row) {
users.push(row.name);
}, function() {
res.status(200).end(JSON.stringify(users));
});
} else {
res.status(200).end(JSON.stringify(users.values()));
stmtAdmin.each(function(err, row) {
users.push(row);
}, function() {
res.status(200).end(JSON.stringify(users));
});
}
}));

api.get('/users/:userId', userAccess(function (req, res) {
let userId = req.params.userId;
if (userId === undefined || userId === '' || !users.has(userId)) {
var stmt = db.prepare("SELECT name, balance FROM Users WHERE name = ?;");
if (userId === undefined || userId === '') {
res.status(404).end('User not found');
} else {
res.status(200).end(JSON.stringify(users.get(userId)));
stmt.get(userId, function(err, result) {
if (result == undefined) {
res.status(404).end('User not found');
return;
}
res.status(200).end(JSON.stringify(result));
});
}
}));

api.post('/users/:userId', adminAccess(function (req, res) {
let userId = req.params.userId;
if (userId != undefined && userId != '') {
let user = {
name: userId,
balance: 0
};
users.set(userId, user);
fs.writeFile(dirname + '/data/users.json', JSON.stringify(users), 'utf8');
let stmt = db.prepare("INSERT INTO Users (name) VALUES (?);");
stmt.run(userId);
res.sendStatus(200);
} else {
res.sendStatus(400);
Expand All @@ -346,11 +376,10 @@ api.post('/users/:userId', adminAccess(function (req, res) {

api.delete('/users/:userId', adminAccess(function (req, res) {
let userId = req.params.userId;
if (userId != undefined && userId != '' && users.has(userId)) {
let user = users.get(userId);
users.remove(userId);
fs.writeFile(dirname + '/data/users.json', JSON.stringify(users), 'utf8');
res.status(200).send(JSON.stringify(user));
if (userId != undefined && userId != '') {
let stmt = db.prepare("DELETE FROM Users WHERE name = ?;");
stmt.run(userId);
res.sendStatus(200);
} else {
res.sendStatus(400);
}
Expand All @@ -361,15 +390,15 @@ api.patch('/users/:userId', adminAccess(function (req, res) {
let amount = req.query.amount;
let reason = req.query.reason;
if (userId != undefined && amount != undefined && reason != undefined
&& userId != '' && reason != '' && amount != '' && users.has(userId)) {
&& userId != '' && reason != '' && amount != '') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add user check

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#24

amount = new Number(amount);
var stmt = db.prepare("INSERT INTO History(id, user, reason, amount, timestamp) VALUES (?, ?, ?, ?, ?);");
stmt.run(uuidv4(), userId, reason, amount, new Date().toUTCString());

var stmt = db.prepare("INSERT INTO History(id, user, reason, amount) VALUES (?, ?, ?, ?);");
stmt.run(uuidv4(), userId, reason, amount);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename stmt to stmt0 to stay consistent

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#26

stmt.finalize();

users.get(userId).balance += amount;
fs.writeFile(dirname + '/data/users.json', JSON.stringify(users), 'utf8');
let stmt2 = db.prepare("UPDATE Users SET balance = balance + ? WHERE name = ?;");
stmt2.run(amount, userId);
res.sendStatus(200);
} else {
res.sendStatus(400);
Expand All @@ -388,4 +417,4 @@ api.post('/logout', function (req, res) {
api.use(function (err, req, res, next) {
console.error(err.stack);
res.status(500).send('We messed up, sry!');
});
});
Loading