2024-12-05 13:05:35 -05:00
const express = require ( 'express' ) ;
const bodyParser = require ( 'body-parser' ) ;
const session = require ( 'express-session' ) ;
const QRCode = require ( 'qrcode' ) ;
const crypto = require ( 'crypto' ) ;
2024-12-09 15:11:22 -05:00
const path = require ( 'path' ) ;
2024-12-05 13:05:35 -05:00
const app = express ( ) ;
app . set ( 'view engine' , 'ejs' ) ;
app . use ( express . json ( ) ) ;
2024-12-19 15:57:33 -05:00
app . use ( express . static ( 'public' ) ) ;
2024-12-05 13:05:35 -05:00
const PORT = 3000 ;
2024-12-28 00:07:12 -05:00
const PWSalt = "!SaltyMagic7283715374" ;
const EmailSalt = "!SaltyMagic3562196239" ;
const QRSalt = "!SaltyMagic5392370662" ;
2024-12-05 13:05:35 -05:00
//
// ToDo, Actions:
// + Login with Password
// + Login with Token
// + Email Link
2024-12-27 08:49:34 -05:00
// + Display Many Tickets (User)
// + Display One Ticket (User)
// + Camp Editor
2024-12-05 13:05:35 -05:00
// + Use Ticket
2024-12-27 08:49:34 -05:00
// + Claim Any Tickets
2024-12-28 00:07:12 -05:00
// + Purge Revoked Function (Admin)
// + Issue Tickets from Camp Admin Page
// See how much each camp/ticket has paid (Admin)
// Send email when new tickets are issued/offered
2024-12-05 13:05:35 -05:00
//
// ToDo, Later
2024-12-19 15:57:33 -05:00
// + Use a templating engine
// + Store password hashed and salted
2024-12-05 13:05:35 -05:00
// Make all HTML look nice
// Logging and Replay system
2024-12-28 00:07:12 -05:00
// Stripe Integration
2024-12-05 13:05:35 -05:00
//
2024-12-28 00:07:12 -05:00
//
// Login workflow:
// There is always an implicit magic link that allows anyone to log in with their email address and hash(GlobalSalt+PerUserSalty+Email), except if the user sets a password for himself.
// We store a per-user salt, initially the empty string, in case we need to invalidate particular users' magic links.
//
//
// Commands
// ISSUE campname email
// USE ticket
// STATUS ticket i/u/r
// CLAIM ticket email
//
function hashEmail ( email ) {
const hash0 = crypto . createHash ( 'sha256' ) ;
const usersalt = email in users ? ( linksalt in users [ email ] ? users [ email ] . linksalt : "" ) : "" ;
const hash1 = hash0 . update ( email + EmailSalt + usersalt ) ;
const hash = hash1 . digest ( "base64" ) ;
return ( hash ) ;
}
2024-12-05 13:05:35 -05:00
function hashPW ( pw ) {
const hash0 = crypto . createHash ( 'sha256' ) ;
const hash1 = hash0 . update ( pw + PWSalt ) ;
const hash = hash1 . digest ( "base64" ) ;
return ( hash ) ;
}
2024-12-14 23:26:38 -05:00
function hashQR ( t , ownername ) {
2024-12-05 13:05:35 -05:00
const hash0 = crypto . createHash ( 'sha256' ) ;
2024-12-14 23:26:38 -05:00
const hash1 = hash0 . update ( t + QRSalt + ownername ) ;
2024-12-05 13:05:35 -05:00
const hash = hash1 . digest ( "base64" ) . slice ( 0 , 6 ) ;
return ( hash ) ;
}
//
// In-memory data structures
//
// There are two ways to log in: with a username/password or with a token.
//
2024-12-28 00:07:12 -05:00
const users = { "teppy@egenesis.com" : { password : hashPW ( "x6321872X.1" ) , superuser : true , linksalt : "" } ,
"fallsonfire@gmail.com" : { password : hashPW ( "indiantreeonfire" ) , superuser : false , linksalt : "boobsarefun" }
2024-12-05 13:05:35 -05:00
} ;
2024-12-26 00:33:23 -05:00
// Status can be "i"=issued, "u"=used, "r"=revoked"
const tickets = { "habitat-1" : { owner : "teppyx@egenesis.com" , offered : "" , paid : 0.00 , status : "i" } ,
"habitat-2" : { owner : "teppyx@egenesis.com" , offered : "" , paid : 0.00 , status : "u" } ,
"habitat-3" : { owner : "ginachen94@gmail.com" , offered : "teppyx@egenesis.com" , paid : 0.00 , status : "i" } ,
"habitat-4" : { owner : "teppyx@egenesis.com" , offered : "noahstern00@gmail.com" , paid : 0.00 , status : "i" } ,
"habitat-5" : { owner : "teppyx@egenesis.com" , offered : "" , paid : 0.00 , status : "r" } ,
"habitat-6" : { owner : "teppyx@egenesis.com" , offered : "" , paid : 0.00 , status : "i" } ,
2024-12-05 13:05:35 -05:00
} ;
2024-12-21 00:29:45 -05:00
const camps = { "habitat" : { leader : "teppy@egenesis.com" , lastid : 6 } } ;
2024-12-09 15:11:22 -05:00
2024-12-05 13:05:35 -05:00
// Middleware setup
app . use ( bodyParser . urlencoded ( { extended : true } ) ) ;
app . use ( session ( {
secret : 'supersecretkey' ,
resave : false ,
saveUninitialized : false ,
} ) ) ;
// Middleware to protect routes
function requireLogin ( req , res , next ) {
2024-12-19 15:57:33 -05:00
if ( req . session . username ) return next ( ) ;
2024-12-26 00:33:23 -05:00
req . session . returnTo = req . originalUrl ;
2024-12-19 15:57:33 -05:00
return res . redirect ( '/login' ) ;
2024-12-09 15:11:22 -05:00
}
2024-12-05 13:05:35 -05:00
2024-12-09 15:11:22 -05:00
function requireSuperUser ( req , res , next ) {
2024-12-19 15:57:33 -05:00
if ( req . session . superuser ) return next ( ) ;
req . session . returnTo = req . originalUrl ;
return res . redirect ( '/login' ) ;
2024-12-09 15:11:22 -05:00
}
2024-12-05 13:05:35 -05:00
2024-12-09 15:11:22 -05:00
app . get ( '/styles.css' , ( req , res ) => {
res . setHeader ( 'Content-Type' , 'text/css' ) ;
res . sendFile ( path . join ( _ _dirname , 'public' , 'styles.css' ) ) ;
} ) ;
2024-12-05 13:05:35 -05:00
function generateSecureToken ( length = 8 ) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' ;
let token = '' ;
const array = new Uint8Array ( length ) ;
crypto . getRandomValues ( array ) ;
for ( let i = 0 ; i < length ; i ++ ) {
token += characters . charAt ( array [ i ] % characters . length ) ;
}
return token ;
}
2024-12-28 00:07:12 -05:00
2024-12-05 13:05:35 -05:00
const postmark = require ( 'postmark' ) ;
const client = new postmark . ServerClient ( 'f45bcb9f-6556-4420-9e21-05d16739b5e8' ) ;
app . get ( '/emaillink' , ( req , res ) => {
res . send ( `
< h1 > Email me a login link < / h 1 >
< form method = "POST" action = "/emaillink" >
< label > Email Address : < input name = "email" > < / l a b e l >
< button type = "submit" > Submit < / b u t t o n > `
)
2024-12-19 15:57:33 -05:00
} ) ;
2024-12-05 13:05:35 -05:00
2024-12-21 00:29:45 -05:00
app . get ( '/camps' , requireSuperUser , ( req , res ) => {
const camplist = { } ;
for ( const c in camps ) {
camplist [ c ] = { leader : camps [ c ] . leader , issued : 0 , claimed : 0 , used : 0 } ;
}
for ( const t in tickets ) {
const parts = t . split ( "-" ) ;
2024-12-26 00:33:23 -05:00
const campname = parts [ 0 ] ;
2024-12-21 00:29:45 -05:00
const ticketnum = Number ( parts [ 1 ] ) ;
2024-12-26 00:33:23 -05:00
if ( tickets [ t ] . status != "r" ) {
camplist [ campname ] . issued += 1 ;
if ( tickets [ t ] . owner != "" ) camplist [ campname ] . claimed += 1 ;
if ( tickets [ t ] . status == "u" ) camplist [ campname ] . used += 1 ;
}
2024-12-21 00:29:45 -05:00
}
2024-12-28 00:07:12 -05:00
return res . render ( "camps" , { username : req . session . username , superuser : req . session . superuser , camps : camplist } ) ;
2024-12-21 00:29:45 -05:00
} )
2024-12-26 00:33:23 -05:00
app . post ( "/camps" , requireSuperUser , ( req , res ) => {
console . log ( "New camp: " ) ;
const campname = req . body . campname ;
const leader = req . body . leader ;
const qty = Number ( req . body . qty ) ;
camps [ campname ] ? ? = { leader : leader , lastid : 0 } ;
for ( let i = 0 ; i < qty ; i ++ ) {
2024-12-28 00:07:12 -05:00
camps [ campname ] . lastid += 1 ; // LOG
tickets [ campname + '-' + camps [ campname ] . lastid ] = { owner : "" , offered : leader , status : "i" } ; // LOG
2024-12-26 00:33:23 -05:00
}
return res . redirect ( "/camps" ) ;
} )
2024-12-21 00:29:45 -05:00
2024-12-26 00:33:23 -05:00
app . get ( '/camplead' , requireLogin , ( req , res ) => {
let username = req . session . username ;
2024-12-28 00:07:12 -05:00
const edit = { username : username , superuser : req . session . superuser , tickets : { } } ;
for ( const t in tickets ) if ( tickets [ t ] . owner == username && tickets [ t ] . status != 'r' ) {
2024-12-26 00:33:23 -05:00
edit . tickets [ t ] = { } ;
edit . tickets [ t ] . owner = tickets [ t ] . owner ;
edit . tickets [ t ] . offered = tickets [ t ] . offered ;
2024-12-28 00:07:12 -05:00
edit . tickets [ t ] . used = tickets [ t ] . status == 'u' ;
2024-12-19 15:57:33 -05:00
}
2024-12-26 00:33:23 -05:00
return res . render ( "camplead" , edit ) ;
} )
app . get ( '/editcamp' , requireSuperUser , ( req , res ) => {
let campname = req . query . campname ;
2024-12-28 00:07:12 -05:00
const edit = { username : req . session . username , superuser : req . session . superuser , campname : campname , leader : camps [ campname ] . leader , tickets : { } } ;
2024-12-26 00:33:23 -05:00
for ( const t in tickets ) {
const parts = t . split ( "-" ) ;
const cname = parts [ 0 ] ;
const tnum = Number ( parts [ 1 ] ) ;
if ( cname == campname ) {
edit . tickets [ t ] = { } ;
edit . tickets [ t ] . owner = tickets [ t ] . owner ;
edit . tickets [ t ] . offered = tickets [ t ] . offered ;
edit . tickets [ t ] . status = tickets [ t ] . status ;
}
}
return res . render ( "editcamp" , edit ) ;
2024-12-19 15:57:33 -05:00
} )
2024-12-26 00:33:23 -05:00
2024-12-28 00:07:12 -05:00
app . post ( '/moretickets' , requireSuperUser , ( req , res ) => {
const qty = Number ( req . body . qty ) ;
const campname = req . body . campname ;
console . log ( "More tickets! " , campname in camps , qty ) ;
if ( campname in camps ) for ( let i = 0 ; i < qty ; i ++ ) {
camps [ campname ] . lastid ++ ;
tickets [ campname + '-' + camps [ campname ] . lastid ] = { owner : "" , offered : camps [ campname ] . leader , paid : 0 , status : "i" } ;
}
const referer = req . get ( 'Referer' ) ;
if ( referer ) return res . redirect ( referer ) ;
else return res . redirect ( '/' ) ;
} ) ;
2024-12-26 21:46:13 -05:00
app . get ( '/manytickets' , requireLogin , ( req , res ) => {
let username = req . session . username ;
2024-12-28 00:07:12 -05:00
const edit = { username : req . session . username , superuser : req . session . superuser , tickets : { } } ;
2024-12-26 21:46:13 -05:00
for ( const t in tickets ) if ( tickets [ t ] . owner == username && tickets [ t ] . status == "i" ) {
edit . tickets [ t ] = { } ;
edit . tickets [ t ] . offered = tickets [ t ] . offered ;
}
return res . render ( "manytickets" , edit ) ;
} )
2024-12-26 00:33:23 -05:00
2024-12-26 21:46:13 -05:00
app . get ( '/mytickets' , requireLogin , async ( req , res ) => {
2024-12-28 00:07:12 -05:00
console . log ( "In mytickets req.session is " , req . session ) ;
2024-12-26 00:33:23 -05:00
let username = req . session . username ;
let claimed = 0 ;
let owned = 0 ;
let theticket = "" ;
2024-12-28 00:07:12 -05:00
const edit = { username : req . session . username , superuser : req . session . superuser , tickets : { } } ;
2024-12-26 00:33:23 -05:00
for ( const t in tickets ) {
2024-12-28 00:07:12 -05:00
if ( tickets [ t ] . status == "i" && tickets [ t ] . offered == username ) { claimed ++ ; tickets [ t ] . owner = username ; tickets [ t ] . offered = "" ; } // LOG
2024-12-26 00:33:23 -05:00
if ( tickets [ t ] . status == "i" && tickets [ t ] . owner == username ) {
owned ++ ;
if ( owned == 1 ) theticket = t ; else theticket = "" ;
edit . tickets [ t ] = { } ;
edit . tickets [ t ] . owner = tickets [ t ] . owner ;
edit . tickets [ t ] . offered = tickets [ t ] . offered ;
}
}
2024-12-28 00:07:12 -05:00
if ( owned == 0 ) return res . render ( "message" , { username : username , superuser : req . session . superuser , message : "You have no unused tickets" } ) ;
2024-12-26 21:46:13 -05:00
else if ( owned == 1 ) {
const hash0 = crypto . createHash ( 'sha256' ) ;
const hash1 = hash0 . update ( theticket + QRSalt ) ;
const hash = hash1 . digest ( "base64" ) . slice ( 0 , 6 ) ;
const dataURL = await QRCode . toDataURL ( 'localhost:3000/useticket?t=' + theticket + '&h=' + hashQR ( theticket , username ) ) ;
2024-12-28 00:07:12 -05:00
return res . render ( "oneticket" , { username : username , superuser : req . session . superuser , ticket : theticket , offered : tickets [ theticket ] . offered , qrcode : dataURL } ) ;
2024-12-26 21:46:13 -05:00
}
2024-12-26 00:33:23 -05:00
else return res . render ( "manytickets" , edit ) ;
} ) ;
2024-12-19 15:57:33 -05:00
2024-12-26 21:46:13 -05:00
app . post ( '/mytickets' , requireLogin , async ( req , res ) => {
let username = req . session . username ;
let theticket = req . body . ticket ;
let offered = req . body . offered ;
if ( tickets [ theticket ] . owner == username && tickets [ theticket ] . status == "i" ) {
2024-12-28 00:07:12 -05:00
tickets [ theticket ] . offered = offered ; // LOG
2024-12-26 21:46:13 -05:00
}
const hash0 = crypto . createHash ( 'sha256' ) ;
const hash1 = hash0 . update ( theticket + QRSalt ) ;
const hash = hash1 . digest ( "base64" ) . slice ( 0 , 6 ) ;
const dataURL = await QRCode . toDataURL ( 'localhost:3000/useticket?t=' + theticket + '&h=' + hashQR ( theticket , username ) ) ;
2024-12-28 00:07:12 -05:00
return res . render ( "oneticket" , { username : username , superuser : req . session . superuser , ticket : theticket , offered : tickets [ theticket ] . offered , qrcode : dataURL } ) ;
2024-12-26 21:46:13 -05:00
} ) ;
2024-12-05 13:05:35 -05:00
2024-12-26 00:33:23 -05:00
app . post ( "/changestatus" , requireSuperUser , ( req , res ) => {
const ticket = req . body . ticket ;
console . log ( "Changestatus " , ticket ) ;
2024-12-28 00:07:12 -05:00
tickets [ ticket ] . status = req . body . status ; // LOG
2024-12-26 00:33:23 -05:00
res . json ( { message : 'Status received' , status : req . body . status } ) ;
} )
2024-12-09 15:11:22 -05:00
app . post ( "/updateoffered" , requireLogin , ( req , res ) => {
2024-12-26 00:33:23 -05:00
console . log ( "UpdateOffered being rubn" ) ;
2024-12-09 15:11:22 -05:00
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" ) ;
2024-12-26 21:46:13 -05:00
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" ) ;
2024-12-09 15:11:22 -05:00
else {
2024-12-28 00:07:12 -05:00
tickets [ ticket ] . offered = offered ; // LOG
2024-12-09 15:11:22 -05:00
res . json ( { message : 'Updated owner of ' + ticket + ' to ' + offered } ) ;
}
} )
2024-12-05 13:05:35 -05:00
2024-12-19 15:57:33 -05:00
2024-12-26 00:33:23 -05:00
app . post ( "/updateticketsu" , requireSuperUser , ( req , res ) => {
const ticket = req . body . ticket ;
const owner = req . body . owner ;
const offered = req . body . offered ;
2024-12-28 00:07:12 -05:00
tickets [ ticket ] . owner = req . body . owner ; // LOG
tickets [ ticket ] . offered = req . body . offered ; // LOG
2024-12-26 00:33:23 -05:00
res . json ( { message : 'Updated ' + ticket } ) ;
} )
2024-12-05 13:05:35 -05:00
app . get ( "/useticket" , ( req , res ) => {
let ticket = req . t ;
let hash = req . h ;
if ( hashQR ( ticket , req . session . username ) != hash ) res . status ( 500 ) . send ( "Ticket " + ticket + " was transferred to " + tickets [ ticket ] . username ) ;
2024-12-26 21:46:13 -05:00
else if ( tickets [ ticket ] . status != "i" ) res . status ( 500 ) . send ( "Ticket " + ticket + " has already been used." ) ;
2024-12-05 13:05:35 -05:00
else {
2024-12-28 00:07:12 -05:00
tickets [ ticket ] . status = "u" ; // LOG
2024-12-26 21:46:13 -05:00
res . send ( "<h1>Welcome, " + tickets [ ticket ] . owner + " to Falls on Fire! Ticket " + ticket + " has now been used.</h1>" ) ;
2024-12-05 13:05:35 -05:00
}
} )
function knownEmail ( email ) {
if ( users [ email ] ) return true ;
for ( const key in tickets )
if ( tickets [ key ] . owner == email || tickets [ key ] . offered == email ) return true ;
return false ;
}
app . post ( 'emaillink' , ( req , res ) => {
if ( ! knownUser ( req . email ) ) return res . send ( "Unknown User" ) ;
const tok = createtoken ( email ) ;
client . sendEmail ( { From : 'tickets@fallsonfire.net' ,
To : 'teppy@egenesis.com' ,
Subject : 'Falls on Fire Tickets, Login Link' ,
TextBody : 'Your Login Link: http://www.fallonfire.net/longinlink?token=' + tok ,
HtmlBody : '<p>Your Login Link: </p>' ,
} ) . then ( ( ) => {
console . log ( 'Email sent' ) ;
res . send ( "<h1>Email sent</h1>" ) ;
} ) . catch ( ( error ) => {
console . error ( 'Error sending email:' , error ) ;
res . send ( "<h1>Email failed</h1>" ) ;
} ) ;
res . send ( "Email link sent" ) ;
} )
app . get ( '/testemail' ,
( req , res ) => {
client . sendEmail ( { From : 'tickets@fallsonfire.net' ,
To : 'teppy@egenesis.com' ,
Subject : 'Email from Ticketing System' ,
TextBody : 'This is a test email.' ,
HtmlBody : '<p>This is a test email.</p>' ,
} ) . then ( ( ) => {
console . log ( 'Email sent' ) ;
res . send ( "<h1>Email sent</h1>" ) ;
} ) . catch ( ( error ) => {
console . error ( 'Error sending email:' , error ) ;
res . send ( "<h1>Email failed</h1>" ) ;
} ) } ) ;
// Routes
app . get ( '/' , ( req , res ) => {
2024-12-28 00:07:12 -05:00
if ( req . session . username ) return res . redirect ( "/mytickets" ) ;
return res . render ( "login" , { superuser : false } ) ;
} ) ;
app . get ( '/login' , ( req , res ) => {
return res . render ( "login" , { superuser : false } ) ;
2024-12-05 13:05:35 -05:00
} ) ;
app . get ( '/signup' , ( req , res ) => {
res . send ( `
< h1 > Sign Up < / h 1 >
< form method = "POST" action = "/signup" >
< label > Username : < input type = "text" name = "username" required > < / l a b e l > < b r >
< label > Password : < input type = "password" name = "password" required > < / l a b e l > < b r >
< button type = "submit" > Sign Up < / b u t t o n >
< / f o r m >
< a href = "/login" > Log In < / a >
` );
} ) ;
app . post ( '/signup' , ( req , res ) => {
const { username , password } = req . body ;
if ( users [ username ] ) {
return res . send ( 'User already exists. <a href="/signup">Try again</a>' ) ;
}
2024-12-09 15:11:22 -05:00
users [ username ] = { password : hashPW ( password ) } ;
console . log ( "Created new account:" , username ) ;
2024-12-05 13:05:35 -05:00
res . redirect ( '/login' ) ;
} ) ;
app . get ( '/changepassword' , ( req , res ) => {
res . send ( `
< h1 > Change Password < / h 1 >
< form method = "POST" action = "/changepassword" >
< label > Password : < input type = "password" name = "password1" required > < / l a b e l > < b r >
< label > Again : < input type = "password" name = "password2" required > < / l a b e l > < b r >
< button type = "submit" > Sign Up < / b u t t o n >
< / f o r m >
< a href = "/" > Home < / a >
` );
} ) ;
app . post ( '/changepassword' , ( req , res ) => {
const { password1 , password2 } = req . body ;
if ( ! req . session . username ) {
return res . send ( 'You are not logged in<a href="/">Back</a>' ) ;
}
if ( password1 != password2 ) {
return res . send ( 'Passwords do not match<a href="/">Back</a>' ) ;
}
users [ req . session . username ] . password = hashPW ( password1 ) ;
2024-12-28 00:07:12 -05:00
res . redirect ( '/' ) ;
2024-12-05 13:05:35 -05:00
} ) ;
app . post ( '/login' , ( req , res ) => {
2024-12-09 15:11:22 -05:00
const { username , password , superuser } = req . body ;
if ( users [ username ] && users [ username ] . password === hashPW ( password ) ) {
req . session . username = username ;
req . session . superuser = users [ username ] . superuser ;
2024-12-19 15:57:33 -05:00
console . log ( "In post /login" , req . session ) ;
const redir = req . session . returnTo ;
delete req . session . returnTo ;
2024-12-28 00:07:12 -05:00
return res . redirect ( redir || "/mytickets" ) ;
2024-12-05 13:05:35 -05:00
}
res . send ( 'Invalid username or password. <a href="/login">Try again</a>' ) ;
} ) ;
app . get ( '/logout' , ( req , res ) => {
req . session . destroy ( ( ) => {
res . redirect ( '/' ) ;
} ) ;
} ) ;
2024-12-14 23:26:38 -05:00
app . post ( '/qrcode' , requireLogin , async ( req , res ) => {
const username = req . session . username ;
const ticket = req . body . ticket ;
if ( tickets [ ticket ] . owner != username ) return res . status ( 500 ) . send ( "Only a ticket owner can generate a QR code" ) ;
const URL = await QRCode . toDataURL ( 'localhost:3000/useticket?t=' + ticket + '&h=' + hashQR ( ticket , username ) ) ;
2024-12-19 15:57:33 -05:00
return res . send ( { owner : tickets [ ticket ] . owner , qrcode : URL } ) ;
2024-12-14 23:26:38 -05:00
} )
2024-12-26 00:33:23 -05:00
app . post ( '/qrcodesu' , requireSuperUser , async ( req , res ) => {
const username = req . session . username ;
const ticket = req . body . ticket ;
const URL = await QRCode . toDataURL ( 'localhost:3000/useticket?t=' + ticket + '&h=' + hashQR ( ticket , username ) ) ;
return res . send ( { owner : tickets [ ticket ] . owner , qrcode : URL } ) ;
} )
2024-12-28 00:07:12 -05:00
app . get ( '/settings' , requireSuperUser , ( req , res ) => {
res . render ( 'settings' , { username : req . session . username , superuser : req . session . superuser , message : "" } )
} ) ;
2024-12-05 13:05:35 -05:00
2024-12-28 00:07:12 -05:00
app . post ( '/wipedb' , requireSuperUser , ( req , res ) => {
for ( const key in users ) delete users [ key ] ;
for ( const key in tickets ) delete tickets [ key ] ;
for ( const key in camps ) delete camps [ key ] ;
res . render ( 'settings' , { username : req . session . username , superuser : req . session . superuser , message : "Wiped the database, but not the logfile." } )
} ) ;
app . post ( '/purge' , requireSuperUser , ( req , res ) => {
let count = 0 ;
for ( const t in tickets ) if ( tickets [ t ] . status == 'r' ) { count ++ ; delete tickets [ t ] ; }
res . render ( 'message' , { username : req . session . username , superuser : req . session . superuser , message : "Purged " + count + " revoked tickets" } )
} ) ;
2024-12-05 13:05:35 -05:00
// Start the server
app . listen ( PORT , ( ) => {
console . log ( ` Server is running at http://localhost: ${ PORT } ` ) ;
} ) ;