diff --git a/data/menu.json b/data/menu.json
index 046a19f..da6bdad 100644
--- a/data/menu.json
+++ b/data/menu.json
@@ -26,8 +26,8 @@
},
{
"name": "90er-Reis-Plattenscheibe",
- "price": 51.9,
- "desc": "Für Retrofreunde die seltene Platte \"Blue Eyes\" von \"Brooky Ryes\" bestückt mit 5 verschiedenen Reissorten dazu etwas Gemüse in Vinyl-Optik"
+ "desc": "Für Retrofreunde die seltene Platte \"Blue Eyes\" von \"Brooky Ryes\" bestückt mit 5 verschiedenen Reissorten dazu etwas Gemüse in Vinyl-Optik",
+ "price": 51.9
}
]
},
@@ -47,18 +47,18 @@
},
{
"name": "Üppige Suppe",
- "price": 2.2,
- "desc": "Üppige Suppe mit üppigem Gemüse gewuppt mit zerruppten Gestrüpp"
+ "desc": "Üppige Suppe mit üppigem Gemüse gewuppt mit zerruppten Gestrüpp",
+ "price": 2.2
},
{
"name": "Henker's Mahlzeit",
- "price": 6.8,
- "desc": "Roter Reis mit scharfem Chili mit tomaten und roter Paprika"
+ "desc": "Roter Reis mit scharfem Chili mit tomaten und roter Paprika",
+ "price": 6.8
},
{
"name": "Nudelsuppe",
- "price": 3.3,
- "desc": "Leissuppe mit liesigel Poltion klingliger Knödel"
+ "desc": "Leissuppe mit liesigel Poltion klingliger Knödel",
+ "price": 3.3
}
]
},
@@ -83,8 +83,8 @@
},
{
"name": "RisiBisi",
- "price": 17.3,
- "desc": "Lila Reis aus kontrolliertem Bio-Anbau mit knallgrünen erbsen, orangene Paprika und gelber Mais als Beilage mit sauerstoffarmem, blauem Schweinefleisch von glücklichen Tieren"
+ "desc": "Lila Reis aus kontrolliertem Bio-Anbau mit knallgrünen erbsen, orangene Paprika und gelber Mais als Beilage mit sauerstoffarmem, blauem Schweinefleisch von glücklichen Tieren",
+ "price": 17.3
},
{
"name": "Burger Duck",
@@ -119,8 +119,8 @@
},
{
"name": "Spagetti Reisonese",
- "price": 5.6,
- "desc": "Spaghetti mit Tomatensoße und Reis"
+ "desc": "Spaghetti mit Tomatensoße und Reis",
+ "price": 5.6
}
]
},
diff --git a/data/reservation.json b/data/reservation.json
new file mode 100644
index 0000000..55ab0a1
--- /dev/null
+++ b/data/reservation.json
@@ -0,0 +1,31 @@
+{
+ "items": [
+ {
+ "name": "Hans Bauer",
+ "desc": "Kleine Familienfeier zu meinem 80. Geburtstag",
+ "email": "hans@gmx.de",
+ "person": 20,
+ "time": "20:15",
+ "date": "16.05.2016",
+ "read": false
+ },
+ {
+ "name": "Micha Müller",
+ "desc": "Ich will meiner geliebten Ursula einen Heiratsantrag machen. Ich suche ein gemütliches Eckchen.",
+ "email": "micha@mueller.de",
+ "person": 3,
+ "time": "21:00",
+ "date": "14.3.2016",
+ "read": true
+ },
+ {
+ "name": "Spa Mer",
+ "desc": "Das ist eine versuchte Injection\r\nmit mehreren Zeilen.",
+ "email": "ano.ny@mus.com",
+ "person": 1337,
+ "time": "00:00",
+ "date": "01.01.2016",
+ "read": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/data/reservation.json.example b/data/reservation.json.example
new file mode 100644
index 0000000..55ab0a1
--- /dev/null
+++ b/data/reservation.json.example
@@ -0,0 +1,31 @@
+{
+ "items": [
+ {
+ "name": "Hans Bauer",
+ "desc": "Kleine Familienfeier zu meinem 80. Geburtstag",
+ "email": "hans@gmx.de",
+ "person": 20,
+ "time": "20:15",
+ "date": "16.05.2016",
+ "read": false
+ },
+ {
+ "name": "Micha Müller",
+ "desc": "Ich will meiner geliebten Ursula einen Heiratsantrag machen. Ich suche ein gemütliches Eckchen.",
+ "email": "micha@mueller.de",
+ "person": 3,
+ "time": "21:00",
+ "date": "14.3.2016",
+ "read": true
+ },
+ {
+ "name": "Spa Mer",
+ "desc": "Das ist eine versuchte Injection\r\nmit mehreren Zeilen.",
+ "email": "ano.ny@mus.com",
+ "person": 1337,
+ "time": "00:00",
+ "date": "01.01.2016",
+ "read": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/data/users.json b/data/users.json
new file mode 100644
index 0000000..aa70f1f
--- /dev/null
+++ b/data/users.json
@@ -0,0 +1,20 @@
+{
+ "Richard Reis": {
+ "pwd": "secret",
+ "rights": [
+ null,
+ true,
+ true,
+ true
+ ]
+ },
+ "Ursula Ulstein": {
+ "pwd": "ultimativ",
+ "rights": [
+ null,
+ true,
+ true,
+ false
+ ]
+ }
+}
\ No newline at end of file
diff --git a/data/users.json.example b/data/users.json.example
new file mode 100644
index 0000000..ee85ad0
--- /dev/null
+++ b/data/users.json.example
@@ -0,0 +1,20 @@
+{
+ "Richard Reis": {
+ "pwd": "secret",
+ "rights": [
+ null,
+ true,
+ true,
+ true
+ ]
+ },
+ "Ursula Ulstein": {
+ "pwd": "ultimativ",
+ "rights": [
+ null,
+ true,
+ true,
+ false
+ ]
+ },
+}
\ No newline at end of file
diff --git a/main.js b/main.js
index 5cb5c1b..4ac0172 100644
--- a/main.js
+++ b/main.js
@@ -4,7 +4,7 @@ var bodyParser = require('body-parser');
var session = require('express-session');
var loginMod = require('./modules/login');
var menuMod = require('./modules/menu');
-//var path = require('path');
+var reservationMod = require('./modules/reservation');
var fs = require('fs');
var app = express();
@@ -17,7 +17,7 @@ var app = express();
// **************************
app.set('view engine', 'jade');
-app.set('rundir', '.');
+app.set('rundir', __dirname);
app.set('views', app.get('rundir') + '/views');
@@ -46,7 +46,9 @@ app.use('/bin', express.static(app.get('rundir') + '/public'));
// INIT
// **************************
+loginMod.init(app.get('rundir') + '/data/users.json');
menuMod.init(app.get('rundir') + '/data/menu.json');
+reservationMod.init(app.get('rundir') + '/data/reservation.json');
@@ -87,22 +89,91 @@ app.post('/speisekarte', function(req, res) {
error = menuMod.updateValue(name, desc, price, nametag);
else if (action == menuMod.MenuAction.DELETE)
error = menuMod.deleteValue(nametag);
- console.log(error);
}
res.render('menu', {
title: 'Restaurant Reiskorn | Speisekarte',
loginName: loginMod.getName(req),
isAdmin: loginMod.hasAccess(req, loginMod.AdminRight.MENU),
- menuJSON: menuMod.getJSON()
+ menuJSON: menuMod.getJSON(),
+ statusMessage: menuMod.getStatusMessage(error, action, nametag)
});
});
app.get('/kontakt', function(req, res) {
+ var showItem = null;
+ var nametag = req.query.nametag;
+ if (loginMod.hasAccess(req, loginMod.AdminRight.RESERVATION)) {
+ var action = reservationMod.determineAction(nametag);
+ if (action == reservationMod.MenuAction.SHOW) {
+ showItem = reservationMod.showValue(nametag);
+ }
+ }
res.render('contact', {
title: 'Restaurant Reiskorn | Kontakt',
loginName: loginMod.getName(req),
- menuJSON: menuMod.getJSON()
+ isAdmin: loginMod.hasAccess(req, loginMod.AdminRight.RESERVATION),
+ menuJSON: menuMod.getJSON(),
+ editItem: showItem,
+ listItem: reservationMod.getJSON()["items"]
+ });
+});
+
+app.post('/kontakt', function(req, res) {
+ var nametag = req.body.nametag;
+ var name = req.body.name;
+ var desc = req.body.desc;
+ var email = req.body.email;
+ var person = req.body.person;
+ var time = req.body.time;
+ var date = req.body.date;
+
+ var action = reservationMod.determineAction(nametag);
+ var error = 0;
+ var showItem = null;
+
+ if (action == reservationMod.MenuAction.CREATE) {
+ error = reservationMod.addValue(name, desc, person, email, date, time, nametag);
+ if (error) {
+ showItem = {
+ name: name,
+ desc: desc,
+ email: email,
+ person: person,
+ time: time,
+ date: date
+ };
+ }
+ }
+ else if (loginMod.hasAccess(req, loginMod.AdminRight.RESERVATION)) {
+ if (action == reservationMod.MenuAction.UPDATE) {
+ error = reservationMod.updateValue(name, desc, person, email, date, time, nametag);
+ if (error) {
+ showItem = {
+ name: name,
+ desc: desc,
+ email: email,
+ person: person,
+ time: time,
+ date: date,
+ id: nametag
+ };
+ }
+ }
+ else if (action == reservationMod.MenuAction.DELETE)
+ error = reservationMod.deleteValue(nametag);
+ else if (action == reservationMod.MenuAction.READ)
+ error = reservationMod.readValue(nametag);
+ }
+
+ res.render('contact', {
+ title: 'Restaurant Reiskorn | Kontakt',
+ loginName: loginMod.getName(req),
+ isAdmin: loginMod.hasAccess(req, loginMod.AdminRight.RESERVATION),
+ menuJSON: menuMod.getJSON(),
+ editItem: showItem,
+ listItem: reservationMod.getJSON()["items"],
+ statusMessage: reservationMod.getStatusMessage(error, action)
});
});
@@ -147,5 +218,5 @@ var server = app.listen(3000, function() {
var host = server.address().address;
var port = server.address().port;
- console.log('Example app listening at http://%s:%s', host, port);
+ console.log('App listening at http://%s:%s', host, port);
});
\ No newline at end of file
diff --git a/modules/login.js b/modules/login.js
index c168298..60f5580 100644
--- a/modules/login.js
+++ b/modules/login.js
@@ -1,20 +1,20 @@
-var admins = {
- "Richard Reis": {
- pwd: "secret",
- rights: {
- 1: true,
- 2: true,
- 3: true
- }
- },
- "Ursula Ulstein": {
- pwd: "ultimativ",
- rights: {
- 1: true,
- 2: true,
- 3: false
- }
- },
+var fs = require('fs');
+
+var admins = {};
+
+var FILENAME = false;
+
+module.exports.init = function(userfile) {
+ FILENAME = userfile;
+ module.exports.loadFile();
+}
+
+module.exports.loadFile = function() {
+ if (!FILENAME) throw "No file for user JSON specified";
+ fs.readFile(FILENAME, 'utf8', function(err, data) {
+ if (err) throw err;
+ admins = JSON.parse(data);
+ });
}
module.exports.AdminRight = {
diff --git a/modules/menu.js b/modules/menu.js
index 27ef2ed..b18b455 100644
--- a/modules/menu.js
+++ b/modules/menu.js
@@ -8,7 +8,28 @@ var menuJSON = {
var REGEX_CREATE = /^[fd]-[0-9]+-new$/;
var REGEX_UPDATE = /^[fd]-[0-9]+-[0-9]+$/;
var REGEX_DELETE = /^[fd]-[0-9]+-[0-9]+-del$/;
-var REGEX_FLOAT = /^(\-|\+)?([0-9]+(\.[0-9]+)?)$/;
+
+var REGEX_FLOAT = /^([0-9]+(\.[0-9]+)?)$/;
+
+var LANG = {};
+LANG["ACTIONS"] = {
+ 1: "Das Ertellen des Menüeintrags",
+ 2: "Das Aktualisieren der Informationen",
+ 3: "Das Löschen des Menüeintrags"
+};
+LANG["ERROR_MESSAGES"] = {
+ 1: "Das Feld \"Name\" darf nicht leer sein.",
+ 2: "Das Feld \"Beschreibung\" darf nicht leer sein.",
+ 4: "Das Feld \"Preis\" darf nicht leer und muss eine positive Zahl sein.",
+ 8: "Beim Verarbeiten der Anfrage ist ein interner Fehler aufgetreten."
+};
+LANG["MESSAGES"] = {
+ "success": "%action% war erfolgreich.",
+ "failure": "%action% konnte nicht durchgeführt werden."
+};
+LANG["INTERNAL"] = {
+ "noinput": "No input file for menu JSON specified!"
+};
var FILENAME = false;
@@ -18,7 +39,7 @@ module.exports.init = function(menufile) {
}
module.exports.loadFile = function() {
- if (!FILENAME) throw "No file for menu JSON specified";
+ if (!FILENAME) throw LANG["MESSAGES"]["noinput"];
fs.readFile(FILENAME, 'utf8', function(err, data) {
if (err) throw err;
menuJSON = JSON.parse(data);
@@ -26,7 +47,7 @@ module.exports.loadFile = function() {
}
module.exports.saveJSON = function() {
- if (!FILENAME) throw "No file for menu JSON specified";
+ if (!FILENAME) throw LANG["MESSAGES"]["noinput"];
fs.writeFile(FILENAME, JSON.stringify(menuJSON, null, 4), function(err) {
if(err) {
console.log(err);
@@ -50,6 +71,36 @@ module.exports.ErrorCode = {
NOFLOAT_PRICE: 4,
WRONG_ACTION: 8
}
+module.exports.ErrorCode["MAX"] = sum(module.exports.ErrorCode);
+
+module.exports.getStatusMessage = function(errorCode, action, nametag) {
+ if (action) {
+ var position = splitNameTag(nametag, action);
+ if (!errorCode) {
+ return {
+ type: "success",
+ message: LANG["MESSAGES"]["success"].replace("%action%", LANG["ACTIONS"][action]),
+ reasons: null,
+ anchor: menuJSON[position.category][position.section]["anchor"]
+ }
+ } else {
+ var reasons = [];
+ for (var i = 1; i < module.exports.ErrorCode["MAX"]; i=i*2) {
+ if (errorCode & i) { // bit-wise comparing
+ reasons.push(LANG["ERROR_MESSAGES"][i]);
+ }
+ }
+ return {
+ type: "danger",
+ message: LANG["MESSAGES"]["failure"].replace("%action%", LANG["ACTIONS"][action]),
+ reasons: reasons,
+ anchor: menuJSON[position.category][position.section]["anchor"]
+ }
+ }
+ } else {
+ return null;
+ }
+}
module.exports.determineAction = function(nametag) {
if (nametag && REGEX_CREATE.test(nametag)) { // new
@@ -136,6 +187,16 @@ var filterFloat = function(value) {
return NaN;
}
+function sum(obj) {
+ var sum = 0;
+ for(var el in obj) {
+ if(obj.hasOwnProperty(el)) {
+ sum += parseFloat(obj[el]);
+ }
+ }
+ return sum;
+}
+
var splitNameTag = function(nametag, action) {
if (action) { // create, update & delete
var splitArr = nametag.split("-");
diff --git a/modules/reservation.js b/modules/reservation.js
new file mode 100644
index 0000000..f4558fb
--- /dev/null
+++ b/modules/reservation.js
@@ -0,0 +1,272 @@
+var fs = require('fs');
+
+var reservationJSON = {
+ "items": []
+};
+
+var REGEX_CREATE = /^new$/;
+var REGEX_UPDATE = /^[0-9]+$/;
+var REGEX_DELETE = /^[0-9]+-del$/;
+var REGEX_SHOW = /^[0-9]+-edit$/;
+var REGEX_READ = /^[0-9]+-read$/;
+
+var REGEX_INT = /^(\-|\+)?([0-9]+)$/;
+var REGEX_EMAIL = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+var REGEX_TIME = /^(([01][0-9]|2[0-4]):[0-5][0-9])$/;
+var REGEX_DATE = /^(([0-2][0-9]|3[01]).(0[0-9]|1[012]).[0-9]{4})$/;
+
+var LANG = {};
+LANG["ACTIONS"] = {
+ 1: "Das Reservieren",
+ 2: "Das Aktualisieren der Informationen",
+ 3: "Das Löschen der Reservierung",
+ 4: "Das Anzeigen der Inforationen",
+ 5: "Das Setzen des Gelesen-Status"
+};
+LANG["ERROR_MESSAGES"] = {
+ 1: "Das Feld \"Name\" darf nicht leer sein.",
+ 2: "Das Feld \"Kommentar\" darf nicht leer sein.",
+ 4: "Das Feld \"Anzahl der Personen\" darf nicht leer und muss eine ganze, positive Zahl sein.",
+ 8: "Das Feld \"Datum\" darf nicht leer sein und muss einem gültigen Datum im Format TT.MM.JJJJ entsprechen.",
+ 16: "Das Feld \"Uhrzeit\" darf nicht leer sein und muss einer gültigen Uhrzeit im Format HH:MM entsprechen.",
+ 32: "Das Feld \"E-Mail\" darf nicht leer und muss eine gültige E-Mail-Adresse sein.",
+ 64: "Beim Verarbeiten der Anfrage ist ein interner Fehler aufgetreten."
+};
+LANG["MESSAGES"] = {
+ "success": "%action% war erfolgreich.",
+ "failure": "%action% konnte nicht durchgeführt werden."
+};
+LANG["INTERNAL"] = {
+ "noinput": "No input file for reservation JSON specified!"
+};
+
+var FILENAME = false;
+
+module.exports.init = function(reservationfile) {
+ FILENAME = reservationfile;
+ module.exports.loadFile();
+}
+
+module.exports.loadFile = function() {
+ if (!FILENAME) throw LANG["MESSAGES"]["noinput"];
+ fs.readFile(FILENAME, 'utf8', function(err, data) {
+ if (err) throw err;
+ reservationJSON = JSON.parse(data);
+ });
+}
+
+module.exports.saveJSON = function() {
+ if (!FILENAME) throw LANG["MESSAGES"]["noinput"];
+ fs.writeFile(FILENAME, JSON.stringify(reservationJSON, null, 4), function(err) {
+ if(err) {
+ console.log(err);
+ return false;
+ }
+ });
+ return true;
+}
+
+module.exports.MenuAction = {
+ ERROR: 0,
+ CREATE: 1,
+ UPDATE: 2,
+ DELETE: 3,
+ SHOW: 4,
+ READ: 5
+}
+
+module.exports.ErrorCode = {
+ SUCCESS: 0,
+ NOSTRING_NAME: 1,
+ NOSTRING_DESC: 2,
+ NONUMBER_PERS: 4,
+ NODATE_DATE: 8,
+ NOTIME_TIME: 16,
+ NOEMAIL_MAIL: 32,
+ WRONG_ACTION: 64
+}
+module.exports.ErrorCode["MAX"] = sum(module.exports.ErrorCode);
+
+module.exports.getStatusMessage = function(errorCode, action) {
+ if (action) {
+ if (!errorCode) {
+ return {
+ type: "success",
+ message: LANG["MESSAGES"]["success"].replace("%action%", LANG["ACTIONS"][action]),
+ reasons: null
+ }
+ } else {
+ var reasons = [];
+ for (var i = 1; i < module.exports.ErrorCode["MAX"]; i=i*2) {
+ if (errorCode & i) { // bit-wise comparing
+ reasons.push(LANG["ERROR_MESSAGES"][i]);
+ }
+ }
+ return {
+ type: "danger",
+ message: LANG["MESSAGES"]["failure"].replace("%action%", LANG["ACTIONS"][action]),
+ reasons: reasons
+ }
+ }
+ } else {
+ return null;
+ }
+}
+
+module.exports.determineAction = function(nametag) {
+ if (nametag && REGEX_CREATE.test(nametag)) { // new
+ return module.exports.MenuAction.CREATE;
+ } else if (nametag && REGEX_UPDATE.test(nametag)) { // update
+ return module.exports.MenuAction.UPDATE;
+ } else if (nametag && REGEX_DELETE.test(nametag)) { // delete
+ return module.exports.MenuAction.DELETE;
+ } else if (nametag && REGEX_SHOW.test(nametag)) { // show
+ return module.exports.MenuAction.SHOW;
+ } else if (nametag && REGEX_READ.test(nametag)) { // read
+ return module.exports.MenuAction.READ;
+ }
+ return module.exports.MenuAction.ERROR;
+}
+
+module.exports.checkValidity = function(name, desc, person, email, date, time) {
+ var errorCode = 0;
+
+ if (!name || !(typeof name === 'string' || name instanceof String))
+ errorCode += module.exports.ErrorCode.NOSTRING_NAME;
+ if (!desc || !(typeof desc === 'string' || desc instanceof String))
+ errorCode += module.exports.ErrorCode.NOSTRING_DESC;
+ if (isNaN(filterInt(person)))
+ errorCode += module.exports.ErrorCode.NONUMBER_PERS;
+ if (!REGEX_EMAIL.test(email))
+ errorCode += module.exports.ErrorCode.NOEMAIL_MAIL;
+ if (!REGEX_DATE.test(date))
+ errorCode += module.exports.ErrorCode.NODATE_DATE;
+ if (!REGEX_TIME.test(time))
+ errorCode += module.exports.ErrorCode.NOTIME_TIME;
+
+ return errorCode;
+}
+
+module.exports.addValue = function(name, desc, person, email, date, time, nametag) {
+ var errorCode = module.exports.checkValidity(name, desc, person, email, date, time);
+ var action = module.exports.determineAction(nametag);
+ if (action !== module.exports.MenuAction.CREATE) {
+ errorCode += module.exports.ErrorCode.WRONG_ACTION;
+ }
+ if (!errorCode) {
+ person = filterInt(person);
+ reservationJSON["items"].push({
+ name: name,
+ desc: desc,
+ email: email,
+ person: person,
+ time: time,
+ date: date,
+ read: false
+ });
+ module.exports.saveJSON();
+ }
+ return errorCode;
+}
+
+module.exports.updateValue = function(name, desc, person, email, date, time, nametag) {
+ var errorCode = module.exports.checkValidity(name, desc, person, email, date, time);
+ var action = module.exports.determineAction(nametag);
+ if (action !== module.exports.MenuAction.UPDATE) {
+ errorCode += module.exports.ErrorCode.WRONG_ACTION;
+ }
+ if (!errorCode) {
+ person = filterInt(person);
+ var position = splitNameTag(nametag, action);
+ reservationJSON["items"][position.id] = {
+ name: name,
+ desc: desc,
+ email: email,
+ person: person,
+ time: time,
+ date: date,
+ read: true
+ };
+ module.exports.saveJSON();
+ }
+ return errorCode;
+}
+
+module.exports.deleteValue = function(nametag) {
+ var errorCode = module.exports.ErrorCode.SUCCESS;
+ var action = module.exports.determineAction(nametag);
+ if (action !== module.exports.MenuAction.DELETE) {
+ errorCode += module.exports.ErrorCode.WRONG_ACTION;
+ }
+ if (!errorCode) {
+ var position = splitNameTag(nametag, action);
+ reservationJSON["items"].splice(position.id, 1);
+ module.exports.saveJSON();
+ }
+ return errorCode;
+}
+
+module.exports.showValue = function(nametag) {
+ var errorCode = module.exports.ErrorCode.SUCCESS;
+ var action = module.exports.determineAction(nametag);
+ if (action !== module.exports.MenuAction.SHOW) {
+ errorCode += module.exports.ErrorCode.WRONG_ACTION;
+ }
+ if (!errorCode) {
+ var position = splitNameTag(nametag, action);
+ result = reservationJSON["items"][position.id];
+ result.id = position.id;
+ return result;
+ }
+ return errorCode;
+}
+
+module.exports.readValue = function(nametag) {
+ var errorCode = module.exports.ErrorCode.SUCCESS;
+ var action = module.exports.determineAction(nametag);
+ if (action !== module.exports.MenuAction.READ) {
+ errorCode += module.exports.ErrorCode.WRONG_ACTION;
+ }
+ if (!errorCode) {
+ var position = splitNameTag(nametag, action);
+ reservationJSON["items"][position.id]["read"] = !reservationJSON["items"][position.id]["read"];
+ module.exports.saveJSON();
+ }
+ return errorCode;
+}
+
+module.exports.getJSON = function() {
+ return reservationJSON;
+}
+
+var filterInt = function(value) {
+ if(REGEX_INT.test(value))
+ return Number(value);
+ return NaN;
+}
+
+function sum(obj) {
+ var sum = 0;
+ for(var el in obj) {
+ if(obj.hasOwnProperty(el)) {
+ sum += parseFloat(obj[el]);
+ }
+ }
+ return sum;
+}
+
+var splitNameTag = function(nametag, action) {
+ if (action) { // create, update, show, read & delete
+ var splitArr = nametag.split("-");
+ var result = {};
+ result.type = action;
+ if (action == module.exports.MenuAction.CREATE) { // create
+ result.id = null;
+ } else { // update, show, read & delete
+ result.id = parseInt(splitArr[0]);
+ }
+ return result;
+ } else {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/public/css/style.css b/public/css/style.css
index bb0e42c..2ff735d 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -81,7 +81,6 @@ textarea {
#carousel-home_carousel {
max-width: 1170px;
margin: auto;
- padding: 0 15px;
}
.btn {
@@ -119,4 +118,21 @@ textarea {
#loginDropdown {
min-width: 300px;
}
+}
+
+/* reservation form */
+
+@media only screen and (min-width : 992px) {
+ .no-padding-md {
+ padding: 0;
+ }
+}
+
+/*
+Carousel Fix
+*/
+
+.carousel-fullwidth {
+ padding-left: 0;
+ padding-right: 0;
}
\ No newline at end of file
diff --git a/views/contact.jade b/views/contact.jade
index 2ce3958..25cef16 100644
--- a/views/contact.jade
+++ b/views/contact.jade
@@ -1,4 +1,97 @@
extends ./wrapper
+
+mixin reservation-form(id, name, desc, email, person, time, date, message)
+ .row
+ form.col-md-10.col-md-offset-1.orange(method="post",action="/kontakt")
+ if message
+ +status-message(message.type, message.message, message.reasons)
+ .row
+ .col-md-6
+ +input-val("name","id-name","Max Mustermann","Name:","name",name)
+ +input-val("number","id-person","2","Anzahl der Personen:","person",person)
+ .col-md-6.no-padding-md
+ .row
+ .col-sm-6
+ +input-val("date","id-date","TT.MM.JJJJ","Datum:","date",date)
+ .col-sm-6
+ +input-val("datetime-local","id-time","HH:MM","Uhrzeit:","time",time)
+ .row
+ .col-md-12
+ +input-val("email","id-mail","max.mustermann@mail.de","E-Mail-Adresse:","email",email)
+ .row
+ .col-md-12
+ +textarea-val("id-desc","Weitere Kontaktdaten, Spezielle Essens-, Platzwünsche, ...","Kommentare:","desc",desc,"7")
+ .row
+ .col-md-3.col-md-offset-3.text-center
+ input(type='hidden',name='nametag',value='#{id}')
+ if id="new"
+ button(type="submit",class="btn btn-success") Reservieren
+ else
+ button(type="submit",class="btn btn-success") Reservierung ändern
+ .col-md-3.text-center
+ button(type="reset",class="btn btn-danger") Eingaben löschen
+
+mixin reservation-list(entries, message)
+ .row
+ if entries.length
+ .col-md-10.col-md-offset-1.stripe
+ if message
+ +status-message(message.type, message.message, message.reasons)
+ each entry, index in entries
+ +reservation-entry(entry.name, entry.desc, entry.person, entry.time, entry.date, entry.read, entry.email, index)
+ else
+ .col-md-10.col-md-offset-1.orange Keine Reservierungen vorhanden.
+
+mixin reservation-entry(name, desc, person, time, date, read, email, index)
+ .row
+ .col-md-1
+ form(style="display:inline",method="post",action="")
+ input(type='hidden',name='nametag',value="#{index+'-del'}")
+ button.btn.btn-sm.btn-danger(type="submit")
+ +icon("remove")
+ span.hidden-md.hidden-lg Entfernen
+ form(style="display:inline",method="get",action="")
+ input(type='hidden',name='nametag',value="#{index+'-edit'}")
+ button.btn.btn-sm.btn-primary(type="submit")
+ +icon("edit")
+ span.hidden-md.hidden-lg Bearbeiten
+ form(style="display:inline",method="post",action="")
+ input(type='hidden',name='nametag',value="#{index+'-read'}")
+ button.btn.btn-sm.btn-info(type="submit")
+ if read
+ +icon("check")
+ span.hidden-md.hidden-lg Als ungelesen markieren
+ else
+ +icon("unchecked")
+ span.hidden-md.hidden-lg Als gelesen markieren
+ .col-md-7
+ span.lead= name
+ br
+ span.small !{desc.substr(0, 300).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/\n/g, '
')}
+ .col-md-4
+ .row
+ .col-md-12= person
+ .row
+ .col-md-12= time
+ .row
+ .col-md-12= date
+ .row
+ .col-md-12= email
+
+
+
+mixin reservation(item, list, isadmin, message)
+ if isadmin
+ if item
+ +reservation-form(item.id, item.name, item.desc, item.email, item.person, item.time, item.date, message)
+ else
+ +reservation-list(list, message)
+ else
+ if item
+ +reservation-form("new", item.name, item.desc, item.email, item.person, item.time, item.date, message)
+ else
+ +reservation-form("new", "", "", "", "", "", "", message)
+
block vars
- var pageTitle = 'Kontakt'
block content
@@ -6,25 +99,7 @@ block content
a(name="reservierung")
h1 Reservierung
.container
- .row
- .col-md-10.col-md-offset-1.orange
- .row
- .col-md-6
- +input("name","id-name","Max Mustermann","Name:")
- +input("number","id-person","2","Anzahl der Personen:")
- .col-md-6
- +input("datetime-local","id-date","TT.MM.JJJJ HH:MM","Datum und Uhrzeit des Besuchs:")
- +input("email","id-mail","max.mustermann@mail.de","E-Mail-Adresse:")
- .row
- .col-md-12
- .form-group
- label(for="id-desc") Kommentare:
- textarea(id="id-desc",class="form-control",type="datetime-local",placeholder="Weitere Kontaktdaten, Spezielle Essens-, Platzwünsche, ...",rows="7")
- .row
- .col-md-2.col-md-offset-4
- button(type="submit",class="btn btn-success") Submit
- .col-md-2
- button(type="reset",class="btn btn-danger") Submit
+ +reservation(editItem, listItem, isAdmin, statusMessage)
a(name="anfahrt")
h1 Anfahrt
.container
@@ -46,7 +121,7 @@ block content
p
| 030 110 112 1337
br
- a(href='reis@korn.de') reis@korn.de
+ a(href='mailto://reis@korn.de') reis@korn.de
a(name="impressum")
h1 Impressum
.container
diff --git a/views/index.jade b/views/index.jade
index b7ad40f..81fd5a0 100644
--- a/views/index.jade
+++ b/views/index.jade
@@ -2,45 +2,47 @@ extends ./wrapper
block vars
- var pageTitle = 'Home'
block content
- +carousel("home_carousel",[
- {
- image:"/bin/image/restaurant-1-chairs.jpg",
- h1:"Romantisches Dinner",
- p:"Wie wäre es mit einem Kerzenabend zu zweit?",
- button:{
- caption:"Reservieren",
- url:"/kontakt#reservieren"
- }
- },
- {
- image:"/bin/image/restaurant-2-hall.jpg",
- h1:"Konferenzraum",
- p:"Viel Platz für über 200 Gäste",
- button:{
- caption:"Reservieren",
- url:"/kontakt#reservieren"
- }
- },
- {
- image:"/bin/image/restaurant-3-pillar.jpg",
- h1:"Gemütliche Räumlichkeiten",
- p:"Bei schlechten Wetter verträumt im fernen Osten",
- button:{
- caption:"Anfahrt",
- url:"/kontakt#anfahrt"
- }
- },
- {
- image:"/bin/image/restaurant-4-buffet.jpg",
- h1:"Buffet",
- p:"Vielfältige Auswahl an Speisen und Getränken",
- button:{
- caption:"Speisekarte",
- url:"/speisekarte"
- }
- }
- ])
.container
+ .row
+ .col-md-12.carousel-fullwidth
+ +carousel("home_carousel",[
+ {
+ image:"/bin/image/restaurant-1-chairs.jpg",
+ h1:"Romantisches Dinner",
+ p:"Wie wäre es mit einem Kerzenabend zu zweit?",
+ button:{
+ caption:"Reservieren",
+ url:"/kontakt#reservieren"
+ }
+ },
+ {
+ image:"/bin/image/restaurant-2-hall.jpg",
+ h1:"Konferenzraum",
+ p:"Viel Platz für über 200 Gäste",
+ button:{
+ caption:"Reservieren",
+ url:"/kontakt#reservieren"
+ }
+ },
+ {
+ image:"/bin/image/restaurant-3-pillar.jpg",
+ h1:"Gemütliche Räumlichkeiten",
+ p:"Bei schlechten Wetter verträumt im fernen Osten",
+ button:{
+ caption:"Anfahrt",
+ url:"/kontakt#anfahrt"
+ }
+ },
+ {
+ image:"/bin/image/restaurant-4-buffet.jpg",
+ h1:"Buffet",
+ p:"Vielfältige Auswahl an Speisen und Getränken",
+ button:{
+ caption:"Speisekarte",
+ url:"/speisekarte"
+ }
+ }
+ ])
.row
.col-md-6.graygray
+img-responsive-center("/bin/image/rice-world.png","Welt voller Reis")
diff --git a/views/menu.jade b/views/menu.jade
index 239a3fe..6902aba 100644
--- a/views/menu.jade
+++ b/views/menu.jade
@@ -1,19 +1,19 @@
extends ./wrapper
-mixin menu-item-adm(name, desc, price, prefix, newItem)
+mixin menu-item-adm(name, anchor, desc, price, prefix, newItem)
.row
.col-md-1
if newItem
button.btn.btn-sm.btn-success(type="submit",form="#{prefix}")
+icon("ok")
else
- form(style="display:inline",method="post",action="")
+ form(style="display:inline",method="post",action="#{'/speisekarte#' + anchor}")
input(type='hidden',name='nametag',value="#{prefix + '-del'}")
button.btn.btn-sm.btn-danger(type="submit")
+icon("remove")
button.btn.btn-sm.btn-primary(type="submit",form="#{prefix}")
+icon("edit")
- form.col-md-11(id="#{prefix}",method="post",action="")
+ form.col-md-11(id="#{prefix}",method="post",action="#{'/speisekarte#' + anchor}")
.col-md-9
input(type='hidden',name='nametag',value='#{prefix}')
+input-val-simple("text",prefix + "-name","Name","name","name",name)
@@ -32,16 +32,20 @@ mixin menu-item(name, desc, price)
p.text-right #{price.toFixed(2).replace(/(\d)(?=(\d{3})+\,)/g, '$1,').replace(/^(.*)\.(.*)$/g, '$1,$2€')}
-mixin menu-cat(name, anchor, content, adm, prefix)
+mixin menu-cat(name, anchor, content, adm, prefix, message)
a(name= anchor)
h2= name
.container
.row
.col-md-10.col-md-offset-1.stripe
+ if anchor
+ if message
+ if anchor==message.anchor
+ +status-message(message.type, message.message, message.reasons)
if adm
each val, index in content
- +menu-item-adm(val.name, val.desc, val.price, prefix + "-" + index, "")
- +menu-item-adm("", "", "", prefix + "-new", "x")
+ +menu-item-adm(val.name, anchor, val.desc, val.price, prefix + "-" + index, "")
+ +menu-item-adm("", anchor, "", "", prefix + "-new", "x")
else
each val, index in content
+menu-item(val.name, val.desc, val.price)
@@ -49,7 +53,7 @@ mixin menu-cat(name, anchor, content, adm, prefix)
mixin menu-part(part, adm, prefix)
each val, index in part
- +menu-cat(val.name, val.anchor, val.items, adm, prefix + "-" + index)
+ +menu-cat(val.name, val.anchor, val.items, adm, prefix + "-" + index, statusMessage)
block vars
- var pageTitle = 'Speisekarte'
diff --git a/views/wrapper.jade b/views/wrapper.jade
index 1f25fb7..d27e926 100644
--- a/views/wrapper.jade
+++ b/views/wrapper.jade
@@ -3,6 +3,11 @@ doctype html
extends ../node_modules/jade-bootstrap/_bootstrap
+mixin textarea-val(id,placeholder,label,name,value,rows)
+ .form-group
+ label(for="#{id}") #{label}
+ textarea.form-control(id="#{id}",placeholder="#{placeholder}",name="#{name}",rows="#{rows}")= value
+
mixin input-val(type,id,placeholder,label,name,value)
.form-group
label(for="#{id}") #{label}
@@ -13,6 +18,13 @@ mixin input-val-simple(type,id,placeholder,label,name,value)
input.form-control(type="#{type}",id="#{id}",placeholder="#{placeholder}",name="#{name}",value="#{value}")
+mixin status-message(type, message, reasons)
+ div(class="alert alert-#{type}" role="alert")= message
+ if reasons
+ ul
+ each val in reasons
+ li= val
+
mixin navbar-main(style)
@@ -50,7 +62,8 @@ mixin loginBox
.col-sm-7.text-center
a.btn.btn-default(href="/login#admin") Admin-Panel
-
+
+
block styles
//link(rel="stylesheet",type="text/css",href="/bin/bootstrap/css/bootstrap.min.css")
link(rel="stylesheet",type="text/css",href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css")