2 Commits
0.1 ... 1.0

Author SHA1 Message Date
Sebastian Seedorf
0c6564db3b Readme aktualisiert 2016-03-28 19:45:56 +02:00
Sebastian Seedorf
62ff08624d Statusmeldungen hinzugefügt; Reservierungen funktionabel; kleine Bugfixes 2016-03-28 17:04:55 +02:00
15 changed files with 781 additions and 105 deletions

View File

@@ -0,0 +1,60 @@
# Restaurant Reiskorn
## Installation
1. Herunterladen des aktuellen [Release](https://gogs.sebse.de/Caesar2011/html5-restaurant/releases).
2. Starten der `main.js` im Hauptprojekt-Ordner.
- `node path/to/main.js`
- Relative und absolute Pfade erlaubt
## Dateistruktur
### data
- Daten zur Speicherung der
- Reservierungen
- Speisekarte
- Benutzerliste
- Mit jeweiligen Beispielwerten zum manuellen Einladen
### modules
- eigene nodejs-Module
- entspricht im MVC-Modell einem Model
- CRUD-Routinen
- Reservierungen
- Speisekarte
- Benutzerliste
### node_modules
- von npm installierte Pakete
### public
- Client-Assets
- CSS
- Client-JS
- Bilder
- Bootstrap/AngularJS
- werden über HTML nachgeladen
### views
- JADE-Views
- HTML-Template-Engine
## Requests
| Min. Vers. | Methode | URI | Parameter | Beschreibung | Benötige Rechte |
| --- | --- | --- | --- | --- | --- | --- |
| 0.1 | GET | / | keine | Zeigt die Startseite an | keine |
| 0.1 | GET | /speisekarte | keine | Zeigt die Speisekarte an | keine (Bearbeitungsfunktionen mit MENU) |
| 0.1 | POST | /speisekarte | nametag:<br> `[f\|d]-[Index in der Liste "food"/"drinks"]-new`<br>name:<br> `[Name des Gerichts]`<br>desc:<br> `[Beschreibung des Menüeintrags]` | Hinzufügen eines Menüeintrags | MENU |
| 0.1 | POST | /speisekarte | nametag:<br> `[f\|d]-[Index in der Liste "food"/"drinks"]-[Index in der Liste "items"]`<br>name:<br> `[Name des Gerichts]`<br>desc:<br> `[Beschreibung des Menüeintrags]` | Aktualisieren der Informationen eines Eintrages | MENU |
| 0.1 | POST | /speisekarte | nametag: `[f\|d]-[Index in der Liste "food"/"drinks"]-[Index in der Liste "items"]-del` | Löschen eines Eintages aus der Speisekarte | MENU |
| 0.1 | GET | /kontakt | keine | Zeigt die Kontaktseite an | keine:<br> Reservierungsformular<br>RESERVATION:<br>Liste aller eingegangenen Reservierungen |
| 1.0 | GET | /kontakt | nametag:<br> `[Index der Reservierung]` | Öffnet das Fenster zum Bearbeiten eines Eintages | RESERVATION |
| 1.0 | POST | /kontakt | nametag:<br> `new`<br>name:<br> `[Name des Reservierenden]`<br>desc:<br> `[Kommentarfeld]`<br>email:<br> `[gülige E-Mail-Adresse]`<br>person:<br> `[positive, natürliche Zahl]`<br>time:<br> `^(([01][0-9]\|2[0-4]):[0-5][0-9])$`<br>date:<br> `^(([0-2][0-9]\|3[01]).(0[0-9]\|1[012]).[0-9]{4})$` | Hinzufügen einer Reservierung | keine |
| 1.0 | POST | /kontakt | nametag:<br> `[Index der Reservierung]`<br>name:<br> `[Name des Reservierenden]`<br>desc:<br> `[Kommentarfeld]`<br>email:<br> `[gülige E-Mail-Adresse]`<br>person:<br> `[positive, natürliche Zahl]`<br>time:<br> `^(([01][0-9]\|2[0-4]):[0-5][0-9])$`<br>date:<br> `^(([0-2][0-9]\|3[01]).(0[0-9]\|1[012]).[0-9]{4})$` | Aktualisieren der Informationen einer Reservierung | RESERVATION |
| 1.0 | POST | /kontakt | nametag:<br> `[Index der Reservierung]-del` | Löschen einer Reservierung aus der Liste | RESERVATION |

View File

@@ -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
}
]
},

31
data/reservation.json Normal file
View File

@@ -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 <b>versuchte</b> Injection\r\nmit mehreren Zeilen.",
"email": "ano.ny@mus.com",
"person": 1337,
"time": "00:00",
"date": "01.01.2016",
"read": true
}
]
}

View File

@@ -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 <b>versuchte</b> Injection\r\nmit mehreren Zeilen.",
"email": "ano.ny@mus.com",
"person": 1337,
"time": "00:00",
"date": "01.01.2016",
"read": true
}
]
}

20
data/users.json Normal file
View File

@@ -0,0 +1,20 @@
{
"Richard Reis": {
"pwd": "secret",
"rights": [
null,
true,
true,
true
]
},
"Ursula Ulstein": {
"pwd": "ultimativ",
"rights": [
null,
true,
true,
false
]
}
}

20
data/users.json.example Normal file
View File

@@ -0,0 +1,20 @@
{
"Richard Reis": {
"pwd": "secret",
"rights": [
null,
true,
true,
true
]
},
"Ursula Ulstein": {
"pwd": "ultimativ",
"rights": [
null,
true,
true,
false
]
},
}

83
main.js
View File

@@ -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);
});

View File

@@ -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 = {

View File

@@ -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("-");

272
modules/reservation.js Normal file
View File

@@ -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;
}
}

View File

@@ -81,7 +81,6 @@ textarea {
#carousel-home_carousel {
max-width: 1170px;
margin: auto;
padding: 0 15px;
}
.btn {
@@ -120,3 +119,20 @@ textarea {
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;
}

View File

@@ -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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/\n/g, '<br/>')}
.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

View File

@@ -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")

View File

@@ -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'

View File

@@ -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)
@@ -51,6 +63,7 @@ mixin loginBox
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")