changes
This commit is contained in:
@@ -43,12 +43,14 @@ const QRSalt ="!SaltyMagic5392370662";
|
|||||||
// + Magic-link Login System
|
// + Magic-link Login System
|
||||||
// Setting to deactivate transfers globally
|
// Setting to deactivate transfers globally
|
||||||
// Mass-import of individual tickets
|
// Mass-import of individual tickets
|
||||||
// Cookie based QR code functionality
|
// + Cookie based QR code functionality
|
||||||
// Create Account (User)
|
// + Create Account (User)
|
||||||
// Change Password (User)
|
// + Change Password (User)
|
||||||
|
// Change most POST routes to end in redirect instead of render.
|
||||||
// Deactivate individual magic links (User)
|
// Deactivate individual magic links (User)
|
||||||
// Deactivate individual magic links (Admin)
|
// Deactivate individual magic links (Admin)
|
||||||
// See how much each camp/ticket has paid (Admin)
|
// See how much each camp/ticket has paid (Admin)
|
||||||
|
// Purchase individual open camping tickets
|
||||||
//
|
//
|
||||||
// ToDo, Later
|
// ToDo, Later
|
||||||
// + Use a templating engine
|
// + Use a templating engine
|
||||||
@@ -140,7 +142,7 @@ function MagicLinkValid(email,hash) {
|
|||||||
let users={};
|
let users={};
|
||||||
let tickets={};
|
let tickets={};
|
||||||
let camps={};
|
let camps={};
|
||||||
let settings={};
|
let settings={ "enable-transfers":true };
|
||||||
|
|
||||||
function InitDatabase() {
|
function InitDatabase() {
|
||||||
for (const key in users ) delete users[key];
|
for (const key in users ) delete users[key];
|
||||||
@@ -287,7 +289,7 @@ app.post('/moretickets', requireSuperUser, (req,res) => {
|
|||||||
|
|
||||||
app.get('/manytickets', requireLogin, (req,res) => {
|
app.get('/manytickets', requireLogin, (req,res) => {
|
||||||
let username=req.session.username;
|
let username=req.session.username;
|
||||||
const edit={ username:req.session.username, superuser:req.session.superuser, tickets: {} };
|
const edit={ username:req.session.username, superuser:req.session.superuser, tickets: {}, cantransfer:settings["enable-transfer"] };
|
||||||
for (const t in tickets) if (tickets[t].owner==username && tickets[t].status=="i") {
|
for (const t in tickets) if (tickets[t].owner==username && tickets[t].status=="i") {
|
||||||
edit.tickets[t]={};
|
edit.tickets[t]={};
|
||||||
edit.tickets[t].offered=tickets[t].offered;
|
edit.tickets[t].offered=tickets[t].offered;
|
||||||
@@ -302,7 +304,7 @@ app.get('/mytickets',requireLogin, async (req,res)=> {
|
|||||||
let claimed=0;
|
let claimed=0;
|
||||||
let owned=0;
|
let owned=0;
|
||||||
let theticket="";
|
let theticket="";
|
||||||
const edit={ username:req.session.username, superuser:req.session.superuser, tickets: {} };
|
const edit={ username:req.session.username, superuser:req.session.superuser, tickets: {}, cantransfer:settings["enable-transfer"] };
|
||||||
for (const t in tickets) {
|
for (const t in tickets) {
|
||||||
if (tickets[t].status=="i" && tickets[t].offered==username) { claimed++; tickets[t].owner=username; tickets[t].offered=""; } // LOG
|
if (tickets[t].status=="i" && tickets[t].offered==username) { claimed++; tickets[t].owner=username; tickets[t].offered=""; } // LOG
|
||||||
if (tickets[t].status=="i" && tickets[t].owner==username) {
|
if (tickets[t].status=="i" && tickets[t].owner==username) {
|
||||||
@@ -325,7 +327,8 @@ app.get('/mytickets',requireLogin, async (req,res)=> {
|
|||||||
const useurl=MainURL+'/useticket?t='+theticket+'&h='+hashQR(theticket,username);
|
const useurl=MainURL+'/useticket?t='+theticket+'&h='+hashQR(theticket,username);
|
||||||
const dataURL=await QRCode.toDataURL(useurl);
|
const dataURL=await QRCode.toDataURL(useurl);
|
||||||
return res.render("oneticket",{ username:username, superuser:req.session.superuser, message:message, magiclink:GetMagicLink(username),
|
return res.render("oneticket",{ username:username, superuser:req.session.superuser, message:message, magiclink:GetMagicLink(username),
|
||||||
ticket:theticket, offered:tickets[theticket].offered, paid:tickets[theticket].paid, qrcode:dataURL, useurl:useurl });
|
ticket:theticket, offered:tickets[theticket].offered, paid:tickets[theticket].paid, qrcode:dataURL, useurl:useurl,
|
||||||
|
cantransfer:settings["enable-transfer"] });
|
||||||
}
|
}
|
||||||
else return res.render("manytickets",edit);
|
else return res.render("manytickets",edit);
|
||||||
});
|
});
|
||||||
@@ -333,9 +336,9 @@ app.get('/mytickets',requireLogin, async (req,res)=> {
|
|||||||
app.get("/oneticket",requireLogin, async (req,res) => {
|
app.get("/oneticket",requireLogin, async (req,res) => {
|
||||||
let username=req.session.username;
|
let username=req.session.username;
|
||||||
let ticket=req.query.t;
|
let ticket=req.query.t;
|
||||||
console.log("Ticket ",tickets);
|
if (!tickets[ticket]) return res.render("error",{ username:username, superuser:req.session.superuser, message: "Ticket not found: "+ticket });
|
||||||
if (tickets[ticket]) console.log("Onwer ",tickets[ticket].owner);
|
if (req.session.superuser) username=tickets[ticket].owner;
|
||||||
if (!tickets[ticket] || tickets[ticket].owner!=username) return res.render("error", { username:username, superuser:req.session.superuser, message: "You are not the owner of ticket "+ticket });
|
else if (tickets[ticket].owner!=username) return res.render("error", { username:username, superuser:req.session.superuser, message: "You are not the owner of ticket "+ticket });
|
||||||
let offered=tickets[ticket].offered;
|
let offered=tickets[ticket].offered;
|
||||||
let message="";
|
let message="";
|
||||||
const hash0=crypto.createHash('sha256');
|
const hash0=crypto.createHash('sha256');
|
||||||
@@ -344,17 +347,18 @@ app.get("/oneticket",requireLogin, async (req,res) => {
|
|||||||
const useurl=MainURL+'/useticket?t='+ticket+'&h='+hashQR(ticket,username);
|
const useurl=MainURL+'/useticket?t='+ticket+'&h='+hashQR(ticket,username);
|
||||||
const dataURL=await QRCode.toDataURL(MainURL+'/useticket?t='+ticket+'&h='+hashQR(ticket,username));
|
const dataURL=await QRCode.toDataURL(MainURL+'/useticket?t='+ticket+'&h='+hashQR(ticket,username));
|
||||||
return res.render("oneticket", { username:username, superuser:req.session.superuser, message:message, magiclink:GetMagicLink(username),
|
return res.render("oneticket", { username:username, superuser:req.session.superuser, message:message, magiclink:GetMagicLink(username),
|
||||||
ticket:ticket, offered:tickets[ticket].offered, paid:tickets[ticket].paid, qrcode:dataURL, useurl:useurl });
|
ticket:ticket, offered:tickets[ticket].offered, paid:tickets[ticket].paid, qrcode:dataURL, useurl:useurl,
|
||||||
|
cantransfer:settings["enable-transfer"] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.post('/oneticket',requireLogin, async (req,res) => { // Make sure the ticket is owned by trhe logged in user!
|
app.post('/oneticket',requireLogin, async (req,res) => { // Make sure the ticket is owned by the logged in user!
|
||||||
let username=req.session.username;
|
let username=req.session.username;
|
||||||
let ticket=req.body.ticket;
|
let ticket=req.body.ticket;
|
||||||
if (!tickets[ticket] || tickets[ticket].owner!=username) return res.render("error", { username:username, superuser:req.session.superuser, message: "You are not the owner of ticket "+ticket });
|
if (!tickets[ticket] || tickets[ticket].owner!=username) return res.render("error", { username:username, superuser:req.session.superuser, message: "You are not the owner of ticket "+ticket });
|
||||||
let offered=req.body.offered;
|
let offered=req.body.offered;
|
||||||
let message="";
|
let message="";
|
||||||
if (tickets[ticket].owner==username && tickets[ticket].status=="i") {
|
if (req.session.cantransfer && tickets[ticket].owner==username && tickets[ticket].status=="i") {
|
||||||
tickets[ticket].offered=offered; // LOG
|
tickets[ticket].offered=offered; // LOG
|
||||||
EmailTickets(offered);
|
EmailTickets(offered);
|
||||||
}
|
}
|
||||||
@@ -363,8 +367,7 @@ app.post('/oneticket',requireLogin, async (req,res) => { // Make sure the ticket
|
|||||||
const hash=hash1.digest("base64").slice(0,6);
|
const hash=hash1.digest("base64").slice(0,6);
|
||||||
const dataURL=await QRCode.toDataURL(MainURL+'/useticket?t='+ticket+'&h='+hashQR(ticket,username));
|
const dataURL=await QRCode.toDataURL(MainURL+'/useticket?t='+ticket+'&h='+hashQR(ticket,username));
|
||||||
const useurl=MainURL+'/useticket?t='+ticket+'&h='+hashQR(ticket,username);
|
const useurl=MainURL+'/useticket?t='+ticket+'&h='+hashQR(ticket,username);
|
||||||
return res.render("oneticket", { username:username, superuser:req.session.superuser, message:message, magiclink:GetMagicLink(username),
|
return res.redirect("/");
|
||||||
ticket:ticket, offered:tickets[ticket].offered, paid:tickets[ticket].paid, qrcode:dataURL, useurl:useurl });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -375,20 +378,9 @@ app.post("/changestatus", requireSuperUser, (req,res) => {
|
|||||||
res.json({ message: 'Status received', status: req.body.status });
|
res.json({ message: 'Status received', status: req.body.status });
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post("/updateoffered", requireLogin, (req,res) => {
|
|
||||||
const ticket=req.body.ticket;
|
|
||||||
const offered=req.body.offered;
|
|
||||||
if (tickets[ticket].owner!=req.session.username) res.status(500).send("Ticket "+ticket+" owned by someone else");
|
|
||||||
else if (tickets[ticket].status=="u") res.status(500).send("Ticket "+ticket+" has already been used");
|
|
||||||
else if (tickets[ticket].status=="r") res.status(500).send("Ticket "+ticket+" was revoked");
|
|
||||||
else {
|
|
||||||
tickets[ticket].offered=offered; // LOG
|
|
||||||
res.json({ message: 'Updated owner of '+ticket+' to '+offered });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Need a SuperUser version of this
|
// Need a SuperUser version of this
|
||||||
app.post("/updateoffered2", requireLogin, (req,res) => {
|
app.post("/updateoffered2", requireLogin, (req,res) => {
|
||||||
|
if (!req.cantransfer) return res.render("error",{ message: "Transfer functionality has been disabled by the admin." });
|
||||||
const changes={};
|
const changes={};
|
||||||
for (ticket in req.body) if (tickets[ticket] && tickets[ticket].owner==req.session.username && req.body[ticket]!=tickets[ticket].offered) {
|
for (ticket in req.body) if (tickets[ticket] && tickets[ticket].owner==req.session.username && req.body[ticket]!=tickets[ticket].offered) {
|
||||||
if (!(req.body[ticket] in changes)) changes[req.body[ticket]]=0;
|
if (!(req.body[ticket] in changes)) changes[req.body[ticket]]=0;
|
||||||
@@ -399,7 +391,7 @@ app.post("/updateoffered2", requireLogin, (req,res) => {
|
|||||||
tickets[ticket].offered=req.body[ticket];
|
tickets[ticket].offered=req.body[ticket];
|
||||||
}
|
}
|
||||||
for (email in changes) EmailTickets(email);
|
for (email in changes) EmailTickets(email);
|
||||||
return res.redirect("manytickets");
|
return res.redirect("/manytickets");
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -437,15 +429,17 @@ app.post("/updateticketsu", requireSuperUser, (req,res) => {
|
|||||||
app.get("/useticket",(req,res) => {
|
app.get("/useticket",(req,res) => {
|
||||||
let ticket=req.query.t;
|
let ticket=req.query.t;
|
||||||
let hash=req.query.h;
|
let hash=req.query.h;
|
||||||
if (!tickets[ticket]) return res.status(500).send("Ticket "+ticket+" not found.");
|
if (!tickets[ticket]) return res.render("error", { message: "Ticket "+ticket+" not found." });
|
||||||
if (hashQR(ticket,tickets[ticket].owner)!=hash) return res.status(500).send("Ticket "+ticket+" was transferred to "+tickets[ticket].owner);
|
if (tickets[ticket].status!="i") return res.render("error", { message: "Ticket "+ticket+" has already been used." });
|
||||||
if (tickets[ticket].status!="i") return res.status(500).send("Ticket "+ticket+" has already been used.");
|
if (hashQR(ticket,tickets[ticket].owner)!=hash) return res.render("error", { message: "Ticket "+ticket+" was transferred to "+tickets[ticket].owner });
|
||||||
let paid_message=tickets[ticket].paid;
|
let paid_message=tickets[ticket].paid;
|
||||||
if (tickets[ticket].paid==0) paid_message="This ticket has not been paid for. Encourage a donation at the gate.";
|
if (tickets[ticket].paid==0) paid_message="<br>This ticket has not been paid for. Encourage a donation at the gate.";
|
||||||
if (settings['enable-ticket-use']) {
|
if (!settings['enable-ticket-use'])
|
||||||
tickets[ticket].status="u"; // LOG
|
return res.render("message", { message: "Your ticket is good, "+tickets[ticket].owner+". The server is not in Event Mode, so Ticket "+ticket+" is still valid."+paid_message });
|
||||||
return res.send("<h1>Welcome, "+tickets[ticket].owner+" to Falls on Fire!<br>Ticket "+ticket+" has now been used.</h1><br>"+paid_message);
|
if (req.cookies["fof_scanqr"]!="on")
|
||||||
} else return res.send("<h1>Your ticket is good, "+tickets[ticket].owner+"<br>The server is not in Event Mode, so Ticket "+ticket+" is still valid.<br>"+paid_message);
|
return res.render("message", { message: "Ticket "+ticket+" owned by "+tickets[ticket].owner+" is good, but scanning on this device has not been enabled."+paid_message });
|
||||||
|
tickets[ticket].status="u"; // LOG
|
||||||
|
return res.render("message", { message: "Welcome, "+tickets[ticket].owner+" to Falls on Fire! Ticket "+ticket+" has now been used."+paid_message });
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -606,29 +600,29 @@ app.get('/settings',requireSuperUser, (req,res) => {
|
|||||||
|
|
||||||
app.post('/wipedb',requireSuperUser, (req,res) => {
|
app.post('/wipedb',requireSuperUser, (req,res) => {
|
||||||
InitDatabase();
|
InitDatabase();
|
||||||
res.render('settings',{ username:req.session.username, superuser:req.session.superuser, message: "Wiped the database, but not the logfile." })
|
res.redirect("/");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/serialize',requireSuperUser, (req,res) => {
|
app.post('/serialize',requireSuperUser, async (req,res) => {
|
||||||
SerializeAll();
|
SerializeAll();
|
||||||
res.render('settings',{ username:req.session.username, superuser:req.session.superuser, message: "Wrote database to disk." })
|
return res.redirect("/settings");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/deserialize',requireSuperUser, (req,res) => {
|
app.post('/deserialize',requireSuperUser, (req,res) => {
|
||||||
DeserializeAll();
|
DeserializeAll();
|
||||||
res.render('settings',{ username:req.session.username, superuser:req.session.superuser, message: "Read database from disk." })
|
return res.redirect("/"); // Since we may be overwriting session
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/purge',requireSuperUser, (req,res) => {
|
app.post('/purge',requireSuperUser, (req,res) => {
|
||||||
let count=0;
|
let count=0;
|
||||||
for (const t in tickets) if (tickets[t].status=='r') { count++; delete tickets[t]; }
|
for (const t in tickets) if (tickets[t].status=='r') { count++; delete tickets[t]; }
|
||||||
res.render('settings',{ username:req.session.username, superuser:req.session.superuser, message: "Purged "+count+" revoked tickets" })
|
return res.redirect("/settings");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/update-setting', requireSuperUser, (req, res) => {
|
app.post('/update-setting', requireSuperUser, (req, res) => {
|
||||||
settings[req.body.name]=req.body.checked;
|
settings[req.body.name]=req.body.checked;
|
||||||
res.json({ success: true, message: 'Checkbox state updated successfully' });
|
res.json({ success: true, message: 'Checkbox state updated successfully' });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/pay0',requireLogin,(req,res) => {
|
app.post('/pay0',requireLogin,(req,res) => {
|
||||||
return res.render("pay",{ username:req.session.username, superuser:req.session.superuser, ticket:req.body.ticket, amount:req.body.amount });
|
return res.render("pay",{ username:req.session.username, superuser:req.session.superuser, ticket:req.body.ticket, amount:req.body.amount });
|
||||||
|
|||||||
@@ -1,33 +1,36 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Your Ticket</title>
|
<title>Your Ticket</title>
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<%- include('partials/nav') %>
|
<%- include('partials/nav') %>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
To use <%=ticket%>, visit this URL: <%=useurl%><br>
|
<% if (superuser) { %>
|
||||||
Or scan this QR Code:<br>
|
Note: This page is being displayed as Superuser.<br>
|
||||||
<img class="qrcode-image" width=300 height=300 src="<%=qrcode%>" alt="QR Code"><br>
|
<% } %>
|
||||||
<% if (paid==0) { %>
|
To use <%=ticket%>, visit this URL: <%=useurl%><br>
|
||||||
Tickets are pay-what-you-can, minimum $1, suggested $50.<br>
|
Or scan this QR Code:<br>
|
||||||
To pay for this ticket by credit card, enter an amount:
|
<img class="qrcode-image" width=300 height=300 src="<%=qrcode%>" alt="QR Code"><br>
|
||||||
<form id="pay" method="POST" action="/pay0">
|
<% if (paid==0) { %>
|
||||||
<input type="hidden" name="ticket" value="<%=ticket%>">
|
Tickets are pay-what-you-can, minimum $1, suggested $50.<br>
|
||||||
<input type="number" min="1.00" max="1000.00" step="0.01" placeholder="50.00" name="amount">
|
To pay for this ticket by credit card, enter an amount:
|
||||||
<button id="Submit" type="submit">Pay</button>
|
<form id="pay" method="POST" action="/pay0">
|
||||||
</form>
|
<input type="hidden" name="ticket" value="<%=ticket%>">
|
||||||
<% } else { %>
|
<input type="number" min="1.00" max="1000.00" step="0.01" placeholder="50.00" name="amount">
|
||||||
This ticket has already been paid for. ($<%=(paid/100).toFixed(2)%>)
|
<button id="Submit" type="submit">Pay</button>
|
||||||
<% } %>
|
</form>
|
||||||
<form id="editor" method="POST" action="/oneticket">
|
<% } else { %>
|
||||||
To transfer <%=ticket%>, enter the recipient's email address:<br>
|
This ticket has already been paid for. ($<%=(paid/100).toFixed(2)%>)
|
||||||
<input type="hidden" name="ticket" value="<%=ticket%>">
|
<% } %>
|
||||||
<input type="email" placeholder="yourfriend@xyz.com" value="<%=offered%>" name="offered">
|
<form id="editor" method="POST" action="/oneticket">
|
||||||
<button id="Submit" type="submit">Transfer</button>
|
To transfer <%=ticket%>, enter the recipient's email address:<br>
|
||||||
<br>
|
<input type="hidden" name="ticket" value="<%=ticket%>">
|
||||||
</form>
|
<input type="email" placeholder="yourfriend@xyz.com" value="<%=offered%>" name="offered">
|
||||||
</div>
|
<button id="Submit" type="submit">Transfer</button>
|
||||||
</body>
|
<br>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<input type="checkbox" class="setting" name="enable-email">Enable Email<br>
|
<input type="checkbox" class="setting" name="enable-email">Enable Email<br>
|
||||||
<input type="checkbox" class="setting" name="enable-ticket-use">Enable Ticket Use<br>
|
<input type="checkbox" class="setting" name="enable-ticket-use">Enable Ticket Use<br>
|
||||||
<input type="checkbox" class="setting" name="enable-credit-cards">Enable Credit Cards<br>
|
<input type="checkbox" class="setting" name="enable-credit-cards">Enable Credit Cards<br>
|
||||||
|
<input type="checkbox" class="setting" name="enable-transfers">Enable Transfers<br>
|
||||||
<form action='/purge' method='post'>
|
<form action='/purge' method='post'>
|
||||||
<button type="submit" >Purge Revoked Tickets</button>
|
<button type="submit" >Purge Revoked Tickets</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Reference in New Issue
Block a user