mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 05:14:23 +00:00
ticket gen working + various changes
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -17,3 +17,10 @@ node_modules
|
|||||||
/dist
|
/dist
|
||||||
|
|
||||||
*.secret.json
|
*.secret.json
|
||||||
|
|
||||||
|
# ignore all latex files except .tex
|
||||||
|
*.aux
|
||||||
|
*.fls
|
||||||
|
*.synctex.gz
|
||||||
|
*.fdb_latexmk
|
||||||
|
._wordcount_selection.tex
|
||||||
3
assets/basicTicketTemplate/README.md
Normal file
3
assets/basicTicketTemplate/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Ticket Template
|
||||||
|
|
||||||
|
This template can be used by libreevent if you do not edit the template. It is entirely copyleft and you can change it to your liking. The LaTex document is included with libreevent.
|
||||||
BIN
assets/basicTicketTemplate/basicTicketTemplate.pdf
Normal file
BIN
assets/basicTicketTemplate/basicTicketTemplate.pdf
Normal file
Binary file not shown.
25
assets/basicTicketTemplate/basicTicketTemplate.tex
Normal file
25
assets/basicTicketTemplate/basicTicketTemplate.tex
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
\documentclass[11pt]{article}
|
||||||
|
|
||||||
|
% Imports %
|
||||||
|
\usepackage{amsmath}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{subcaption}
|
||||||
|
\usepackage[export]{adjustbox}
|
||||||
|
\usepackage{tcolorbox}
|
||||||
|
\usepackage{xcolor}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[a4paper]{geometry}
|
||||||
|
|
||||||
|
\addtolength{\oddsidemargin}{-0.5in}
|
||||||
|
\addtolength{\textwidth}{1in}
|
||||||
|
\addtolength{\evensidemargin}{-0.55in}
|
||||||
|
\addtolength{\topmargin}{-0.75in}
|
||||||
|
\addtolength{\textheight}{1.5in}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\begin{tcolorbox}[colback=gray!5!white,colframe=black!75!black,title=Your Ticket - libreevent event management solution]
|
||||||
|
\vspace{6cm}
|
||||||
|
\end{tcolorbox}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
@@ -28,10 +28,9 @@ module.exports = ( app, settings ) => {
|
|||||||
if ( request.body.mail && request.body.password ) {
|
if ( request.body.mail && request.body.password ) {
|
||||||
pwdmanager.checkpassword( request.body.mail, request.body.password ).then( data => {
|
pwdmanager.checkpassword( request.body.mail, request.body.password ).then( data => {
|
||||||
request.session.username = request.body.mail;
|
request.session.username = request.body.mail;
|
||||||
if ( data ) {
|
if ( data.status ) {
|
||||||
request.session.username = request.body.mail;
|
request.session.username = request.body.mail;
|
||||||
// TODO: Check if user has 2fa enabled
|
if ( data.twoFA === 'simple' ) {
|
||||||
if ( settings.twoFA === 'standard' ) {
|
|
||||||
( async () => {
|
( async () => {
|
||||||
let tok = twoFA.registerStandardAuthentication()[ 'token' ];
|
let tok = twoFA.registerStandardAuthentication()[ 'token' ];
|
||||||
let ipRetrieved = request.headers[ 'x-forwarded-for' ];
|
let ipRetrieved = request.headers[ 'x-forwarded-for' ];
|
||||||
@@ -40,7 +39,7 @@ module.exports = ( app, settings ) => {
|
|||||||
request.session.token = tok;
|
request.session.token = tok;
|
||||||
response.send( { 'status': '2fa' } );
|
response.send( { 'status': '2fa' } );
|
||||||
} )();
|
} )();
|
||||||
} else if ( settings.twoFA === 'enhanced' ) {
|
} else if ( data.twoFA === 'enhanced' ) {
|
||||||
( async () => {
|
( async () => {
|
||||||
let res = twoFA.registerEnhancedAuthentication();
|
let res = twoFA.registerEnhancedAuthentication();
|
||||||
let ipRetrieved = request.headers[ 'x-forwarded-for' ];
|
let ipRetrieved = request.headers[ 'x-forwarded-for' ];
|
||||||
@@ -50,7 +49,7 @@ module.exports = ( app, settings ) => {
|
|||||||
response.send( { 'status': '2fa+', 'code': res.code } );
|
response.send( { 'status': '2fa+', 'code': res.code } );
|
||||||
} )();
|
} )();
|
||||||
} else {
|
} else {
|
||||||
request.session.loggedInUser = true;
|
request.session.loggedInAdmin = true;
|
||||||
response.send( { 'status': 'ok' } );
|
response.send( { 'status': 'ok' } );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -63,7 +62,6 @@ module.exports = ( app, settings ) => {
|
|||||||
} );
|
} );
|
||||||
|
|
||||||
app.get( '/admin/2fa', ( request, response ) => {
|
app.get( '/admin/2fa', ( request, response ) => {
|
||||||
// TODO: Add multi language
|
|
||||||
let tokType = twoFA.verifySimple( request.query.token );
|
let tokType = twoFA.verifySimple( request.query.token );
|
||||||
if ( tokType === 'standard' ) {
|
if ( tokType === 'standard' ) {
|
||||||
request.session.loggedInAdmin = true;
|
request.session.loggedInAdmin = true;
|
||||||
|
|||||||
@@ -42,7 +42,13 @@ class GETHandler {
|
|||||||
} );
|
} );
|
||||||
} else if ( call === 'getLocations' ) {
|
} else if ( call === 'getLocations' ) {
|
||||||
db.getJSONData( 'locations' ).then( data => {
|
db.getJSONData( 'locations' ).then( data => {
|
||||||
resolve( data );
|
resolve( data ?? {} );
|
||||||
|
} ).catch( error => {
|
||||||
|
reject( { 'code': 500, 'error': error } );
|
||||||
|
} );
|
||||||
|
} else if ( call === 'getTicketTemplate' ) {
|
||||||
|
db.getJSONDataSimple( 'tickets', query.ticket ).then( data => {
|
||||||
|
resolve( data ?? {} );
|
||||||
} ).catch( error => {
|
} ).catch( error => {
|
||||||
reject( { 'code': 500, 'error': error } );
|
reject( { 'code': 500, 'error': error } );
|
||||||
} );
|
} );
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ module.exports.checkpassword = ( username, password ) => {
|
|||||||
if ( data ) {
|
if ( data ) {
|
||||||
if ( data[ 0 ] ) {
|
if ( data[ 0 ] ) {
|
||||||
bcrypt.compare( password, data[ 0 ].pass ).then( res => {
|
bcrypt.compare( password, data[ 0 ].pass ).then( res => {
|
||||||
resolve( res );
|
resolve( { 'status': res, 'twoFA': data[ 0 ].two_fa } );
|
||||||
} );
|
} );
|
||||||
} else {
|
} else {
|
||||||
resolve( false );
|
resolve( false );
|
||||||
|
|||||||
@@ -101,6 +101,6 @@ app.use( ( request, response ) => {
|
|||||||
|
|
||||||
console.log( '\n\n[ Server ] loading complete!\n\n' );
|
console.log( '\n\n[ Server ] loading complete!\n\n' );
|
||||||
|
|
||||||
const PORT = process.env.PORT || 8081;
|
const PORT = process.env.PORT || 8080;
|
||||||
console.log( '[ Server ] listening on port ' + PORT );
|
console.log( '[ Server ] listening on port ' + PORT );
|
||||||
http.createServer( app ).listen( PORT );
|
http.createServer( app ).listen( PORT );
|
||||||
@@ -30,7 +30,7 @@ class GETHandler {
|
|||||||
if ( query.event ) {
|
if ( query.event ) {
|
||||||
db.getJSONDataSimple( 'booked', query.event ).then( data => {
|
db.getJSONDataSimple( 'booked', query.event ).then( data => {
|
||||||
db.getDataSimple( 'temp', 'user_id', session.id ).then( dat => {
|
db.getDataSimple( 'temp', 'user_id', session.id ).then( dat => {
|
||||||
resolve( { 'booked': data ? data.booked : {}, 'user': dat[ 0 ] ? JSON.parse( dat[ 0 ].data )[ query.event ] ?? {} : {} } );
|
resolve( { 'booked': data ?? {}, 'user': dat[ 0 ] ? JSON.parse( dat[ 0 ].data )[ query.event ] ?? {} : {} } );
|
||||||
} );
|
} );
|
||||||
} ).catch( error => {
|
} ).catch( error => {
|
||||||
reject( { 'code': 500, 'message': error } );
|
reject( { 'code': 500, 'message': error } );
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ class POSTHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
transmit[ data.eventID ][ data.id ] = data;
|
transmit[ data.eventID ][ data.id ] = data;
|
||||||
|
// TODO: Prevent seat selection if already taken (also if in booked!)
|
||||||
// TODO: Respect max ticket count per user
|
// TODO: Respect max ticket count per user
|
||||||
|
// TODO: maybe move to per event setting
|
||||||
let totalUserTickets = 0;
|
let totalUserTickets = 0;
|
||||||
for ( let event in transmit ) {
|
for ( let event in transmit ) {
|
||||||
for ( let ticket in transmit[ event ] ) {
|
for ( let ticket in transmit[ event ] ) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -58,6 +58,16 @@ module.exports.writeDataSimple = ( db, column, searchQuery, data ) => {
|
|||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.deleteDataSimple = ( db, column, searchQuery ) => {
|
||||||
|
return new Promise( ( resolve, reject ) => {
|
||||||
|
dbh.query( { 'command': 'deleteData', 'property': column, 'searchQuery': searchQuery }, dbRef[ db ] ).then( dat => {
|
||||||
|
resolve( dat );
|
||||||
|
} ).catch( error => {
|
||||||
|
reject( error );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.checkDataAvailability = ( db, column, searchQuery ) => {
|
module.exports.checkDataAvailability = ( db, column, searchQuery ) => {
|
||||||
return new Promise( ( resolve, reject ) => {
|
return new Promise( ( resolve, reject ) => {
|
||||||
dbh.query( { 'command': 'checkDataAvailability', 'property': column, 'searchQuery': searchQuery }, dbRef[ db ] ).then( res => {
|
dbh.query( { 'command': 'checkDataAvailability', 'property': column, 'searchQuery': searchQuery }, dbRef[ db ] ).then( res => {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class SQLDB {
|
|||||||
if ( error ) throw error;
|
if ( error ) throw error;
|
||||||
if ( results[ 0 ][ '@@default_storage_engine' ] !== 'InnoDB' ) return 'DB HAS TO USE InnoDB!';
|
if ( results[ 0 ][ '@@default_storage_engine' ] !== 'InnoDB' ) return 'DB HAS TO USE InnoDB!';
|
||||||
} );
|
} );
|
||||||
this.sqlConnection.query( 'CREATE TABLE libreevent_users ( account_id INT ( 10 ) NOT NULL AUTO_INCREMENT, email TINYTEXT NOT NULL, pass TEXT, name TEXT, first_name TEXT, two_fa TINYTEXT, user_data VARCHAR( 60000 ), mail_confirmed TINYTEXT, marketing_ok TINYTEXT, PRIMARY KEY ( account_id ) ) ENGINE=INNODB;', ( error ) => {
|
this.sqlConnection.query( 'CREATE TABLE libreevent_users ( account_id INT ( 10 ) NOT NULL AUTO_INCREMENT, email TINYTEXT NOT NULL, pass TEXT, name TEXT, first_name TEXT, two_fa TINYTEXT, user_data VARCHAR( 60000 ), mail_confirmed TINYTEXT, marketing TINYTEXT, PRIMARY KEY ( account_id ) ) ENGINE=INNODB;', ( error ) => {
|
||||||
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
|
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
|
||||||
this.sqlConnection.query( 'CREATE TABLE libreevent_orders ( order_id INT ( 10 ) NOT NULL AUTO_INCREMENT, order_name TINYTEXT, account_id INT ( 10 ) NOT NULL, tickets VARCHAR( 60000 ), processed TINYTEXT, PRIMARY KEY ( order_id ), FOREIGN KEY ( account_id ) REFERENCES libreevent_users( account_id ) ) ENGINE=INNODB;', ( error ) => {
|
this.sqlConnection.query( 'CREATE TABLE libreevent_orders ( order_id INT ( 10 ) NOT NULL AUTO_INCREMENT, order_name TINYTEXT, account_id INT ( 10 ) NOT NULL, tickets VARCHAR( 60000 ), processed TINYTEXT, PRIMARY KEY ( order_id ), FOREIGN KEY ( account_id ) REFERENCES libreevent_users( account_id ) ) ENGINE=INNODB;', ( error ) => {
|
||||||
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
|
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
|
||||||
@@ -104,6 +104,10 @@ class SQLDB {
|
|||||||
- addData:
|
- addData:
|
||||||
- operation.data (key-value pair with all data as values and column to insert into as key)
|
- operation.data (key-value pair with all data as values and column to insert into as key)
|
||||||
|
|
||||||
|
- deleteData:
|
||||||
|
- operation.property (the column to search for the value)
|
||||||
|
- operation.searchQuery (the value to search for [will be sanitised by method])
|
||||||
|
|
||||||
- updateData:
|
- updateData:
|
||||||
- operation.newValues (a object with keys being the column and value being the value to be inserted into that column, values are being
|
- operation.newValues (a object with keys being the column and value being the value to be inserted into that column, values are being
|
||||||
sanitised by the function)
|
sanitised by the function)
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ module.exports = ( app, settings ) => {
|
|||||||
if ( dat[ 0 ] ) {
|
if ( dat[ 0 ] ) {
|
||||||
db.getJSONData( 'events' ).then( events => {
|
db.getJSONData( 'events' ).then( events => {
|
||||||
let data = JSON.parse( dat[ 0 ].data );
|
let data = JSON.parse( dat[ 0 ].data );
|
||||||
|
console.log( data );
|
||||||
( async () => {
|
( async () => {
|
||||||
for ( let event in data ) {
|
for ( let event in data ) {
|
||||||
for ( let item in data[ event ] ) {
|
for ( let item in data[ event ] ) {
|
||||||
@@ -116,7 +117,7 @@ module.exports = ( app, settings ) => {
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
app.post( '/payments/webhook', bodyParser.raw( { type: 'application/json' } ), ( req, res ) => {
|
app.post( '/payments/webhook', bodyParser.raw( { type: 'application/json' } ), async ( req, res ) => {
|
||||||
const payload = req.body;
|
const payload = req.body;
|
||||||
const sig = req.headers[ 'stripe-signature' ];
|
const sig = req.headers[ 'stripe-signature' ];
|
||||||
|
|
||||||
@@ -139,9 +140,26 @@ module.exports = ( app, settings ) => {
|
|||||||
db.getDataSimple( 'users', 'email', sessionReference[ event.data.object.id ][ 'email' ] ).then( user => {
|
db.getDataSimple( 'users', 'email', sessionReference[ event.data.object.id ][ 'email' ] ).then( user => {
|
||||||
if ( user[ 0 ] ) {
|
if ( user[ 0 ] ) {
|
||||||
console.log( sessionReference[ event.data.object.id ][ 'tok' ] );
|
console.log( sessionReference[ event.data.object.id ][ 'tok' ] );
|
||||||
|
const tickets = JSON.parse( dat[ 0 ].data );
|
||||||
db.writeDataSimple( 'orders', 'account_id', user[ 0 ].account_id, { 'account_id': user[ 0 ].account_id, 'tickets': dat[ 0 ].data, 'order_name': sessionReference[ event.data.object.id ][ 'tok' ] } ).then( () => {
|
db.writeDataSimple( 'orders', 'account_id', user[ 0 ].account_id, { 'account_id': user[ 0 ].account_id, 'tickets': dat[ 0 ].data, 'order_name': sessionReference[ event.data.object.id ][ 'tok' ] } ).then( () => {
|
||||||
TicketGenerator.generateTickets( sessionReference[ event.data.object.id ] );
|
TicketGenerator.generateTickets( sessionReference[ event.data.object.id ] );
|
||||||
} );
|
} );
|
||||||
|
db.getJSONData( 'booked' ).then( ret => {
|
||||||
|
let booked = ret ?? {};
|
||||||
|
for ( let event in tickets ) {
|
||||||
|
if ( !booked[ String( event ) ] ) {
|
||||||
|
booked[ String( event ) ] = {};
|
||||||
|
}
|
||||||
|
for ( let tik in tickets[ event ] ) {
|
||||||
|
booked[ event ][ tik ] = tickets[ event ][ tik ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.writeJSONData( 'booked', booked );
|
||||||
|
} );
|
||||||
|
|
||||||
|
db.deleteDataSimple( 'temp', 'user_id', sessionReference[ event.data.object.id ][ 'tok' ] ).catch( error => {
|
||||||
|
console.error( '[ STRIPE ] ERROR whilst deleting data from DB: ' + error );
|
||||||
|
} );
|
||||||
} else {
|
} else {
|
||||||
console.log( sessionReference[ event.data.object.id ][ 'email' ] );
|
console.log( sessionReference[ event.data.object.id ][ 'email' ] );
|
||||||
console.error( 'user not found' );
|
console.error( 'user not found' );
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class TicketGenerator {
|
|||||||
this.runningTickets = {};
|
this.runningTickets = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Save to disk in case of crash of server / reboot / whatever
|
// TODO: Save to disk / DB in case of crash of server / reboot / whatever
|
||||||
// and continue processing once back online
|
// and continue processing once back online
|
||||||
generateTickets ( order ) {
|
generateTickets ( order ) {
|
||||||
this.ticketQueue[ this.jobId ] = { 'order': order };
|
this.ticketQueue[ this.jobId ] = { 'order': order };
|
||||||
@@ -114,15 +114,18 @@ class TicketGenerator {
|
|||||||
for ( let event in order ) {
|
for ( let event in order ) {
|
||||||
const template = this.tickets[ event ];
|
const template = this.tickets[ event ];
|
||||||
for ( let ticket in order[ event ] ) {
|
for ( let ticket in order[ event ] ) {
|
||||||
const data = [ {
|
for ( let tik = 0; tik < ( order[ event ][ ticket ].count ?? 1 ); tik++ ) {
|
||||||
'locationAndTime': this.events[ event ][ 'date' ],
|
const data = [ {
|
||||||
'ticketName': order[ event ][ ticket ][ 'name' ],
|
'eventName': this.events[ event ][ 'name' ],
|
||||||
'ticketQRCode': ord[ 0 ].order_name + '_' + order[ event ][ ticket ][ 'id' ],
|
'locationAndTime': new Date( this.events[ event ][ 'date' ] ).toLocaleString(),
|
||||||
} ];
|
'ticketName': order[ event ][ ticket ][ 'name' ],
|
||||||
const page = await pdfLib.PDFDocument.load( await pdfme.generate( { 'template': template, 'inputs': data } ) );
|
'ticketQRCode': ord[ 0 ].order_name + '_' + order[ event ][ ticket ][ 'id' ],
|
||||||
const p = await doc.copyPages( page, page.getPageIndices() );
|
} ];
|
||||||
pages.push( p );
|
const page = await pdfLib.PDFDocument.load( await pdfme.generate( { 'template': template, 'inputs': data } ) );
|
||||||
p.forEach( ( page ) => doc.addPage( page ) );
|
const p = await doc.copyPages( page, page.getPageIndices() );
|
||||||
|
pages.push( p );
|
||||||
|
p.forEach( ( page ) => doc.addPage( page ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const f = path.join( __dirname + '/store/' + ord[ 0 ].order_name + '.pdf' );
|
const f = path.join( __dirname + '/store/' + ord[ 0 ].order_name + '.pdf' );
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ module.exports = ( app, settings ) => {
|
|||||||
app.post( '/user/login', bodyParser.json(), ( request, response ) => {
|
app.post( '/user/login', bodyParser.json(), ( request, response ) => {
|
||||||
if ( request.body.mail && request.body.password ) {
|
if ( request.body.mail && request.body.password ) {
|
||||||
pwdmanager.checkpassword( request.body.mail, request.body.password ).then( data => {
|
pwdmanager.checkpassword( request.body.mail, request.body.password ).then( data => {
|
||||||
request.session.username = request.body.mail;
|
|
||||||
if ( data.status ) {
|
if ( data.status ) {
|
||||||
|
request.session.username = request.body.mail;
|
||||||
if ( data.twoFA === 'simple' ) {
|
if ( data.twoFA === 'simple' ) {
|
||||||
( async () => {
|
( async () => {
|
||||||
let tok = twoFA.registerStandardAuthentication()[ 'token' ];
|
let tok = twoFA.registerStandardAuthentication()[ 'token' ];
|
||||||
@@ -83,7 +83,6 @@ module.exports = ( app, settings ) => {
|
|||||||
} );
|
} );
|
||||||
|
|
||||||
app.get( '/user/2fa', ( request, response ) => {
|
app.get( '/user/2fa', ( request, response ) => {
|
||||||
// TODO: Add multi language
|
|
||||||
let tokType = twoFA.verifySimple( request.query.token );
|
let tokType = twoFA.verifySimple( request.query.token );
|
||||||
if ( tokType === 'standard' ) {
|
if ( tokType === 'standard' ) {
|
||||||
request.session.loggedInUser = true;
|
request.session.loggedInUser = true;
|
||||||
@@ -154,7 +153,7 @@ module.exports = ( app, settings ) => {
|
|||||||
mailManager.sendMail( request.body.mail, await twoFA.generateSignupEmail( tok, settings.yourDomain, settings.name ), 'Confirm your email', settings.mailSender );
|
mailManager.sendMail( request.body.mail, await twoFA.generateSignupEmail( tok, settings.yourDomain, settings.name ), 'Confirm your email', settings.mailSender );
|
||||||
} )();
|
} )();
|
||||||
pwdmanager.hashPassword( request.body.password ).then( hash => {
|
pwdmanager.hashPassword( request.body.password ).then( hash => {
|
||||||
db.writeDataSimple( 'users', 'email', request.body.mail, { 'email': request.body.mail, 'pass': hash, 'first_name': request.body.firstName, 'name': request.body.name, 'two_fa': 'disabled', 'user_data': JSON.stringify( { 'country': request.body.country } ) } ).then( () => {
|
db.writeDataSimple( 'users', 'email', request.body.mail, { 'email': request.body.mail, 'pass': hash, 'first_name': request.body.firstName, 'name': request.body.name, 'two_fa': 'disabled', 'user_data': JSON.stringify( { 'country': request.body.country } ), 'marketing': request.body.newsletter ? generator.generateToken( 60 ) : null } ).then( () => {
|
||||||
request.session.loggedInUser = true;
|
request.session.loggedInUser = true;
|
||||||
request.session.username = request.body.mail;
|
request.session.username = request.body.mail;
|
||||||
response.send( 'ok' );
|
response.send( 'ok' );
|
||||||
|
|||||||
@@ -5,6 +5,6 @@
|
|||||||
"db": "mysql",
|
"db": "mysql",
|
||||||
"payments": "stripe",
|
"payments": "stripe",
|
||||||
"name": "libreevent",
|
"name": "libreevent",
|
||||||
"yourDomain": "http://localhost:8081",
|
"yourDomain": "http://localhost:8080",
|
||||||
"mailSender": "libreevent <info@libreevent.janishutz.com>"
|
"mailSender": "libreevent <info@libreevent.janishutz.com>"
|
||||||
}
|
}
|
||||||
@@ -3,11 +3,13 @@
|
|||||||
|
|
||||||
- make pricing groups changeable in UI (event categories)
|
- make pricing groups changeable in UI (event categories)
|
||||||
|
|
||||||
- create function that parses DB every 15 minutes and clears out junk
|
- create function that parses DB every 15 minutes and clears out junk --> Also update data in db when user goes to purchase to prevent clearing during purchase
|
||||||
|
|
||||||
- Require user to confirm email before purchasing
|
- Require user to confirm email before purchasing
|
||||||
|
|
||||||
- Guest purchase in the future (remove from matura shit)
|
|
||||||
|
|
||||||
|
- Guest purchase in the future (maybe remove from matura)
|
||||||
|
|
||||||
- Create password changing endpoint (to reset forgotten pwd)
|
- Create password changing endpoint (to reset forgotten pwd)
|
||||||
- Add Admin profile (page to change account settings per person like changing pwd)
|
- Add Admin profile (page to change account settings per person like changing pwd)
|
||||||
@@ -19,7 +21,9 @@
|
|||||||
|
|
||||||
- Implement Permission system
|
- Implement Permission system
|
||||||
|
|
||||||
- Seat numbering
|
- Seat numbering!!
|
||||||
|
|
||||||
|
- Add localization for date
|
||||||
|
|
||||||
|
|
||||||
- add webpack (or any other minifying tool) to project website to decrease file size (OPTIONAL)
|
- add webpack (or any other minifying tool) to project website to decrease file size (OPTIONAL)
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
} );
|
} );
|
||||||
|
|
||||||
if ( !sessionStorage.getItem( 'seatplan-history' ) ) {
|
if ( !sessionStorage.getItem( 'seatplan-history' ) ) {
|
||||||
sessionStorage.setItem( 'seatplaTODO:n-history', JSON.stringify( { '1': this.scaleDown( this.draggables ) } ) );
|
sessionStorage.setItem( 'seatplan-history', JSON.stringify( { '1': this.scaleDown( this.draggables ) } ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
let history = sessionStorage.getItem( 'seatplan-history' ) ? JSON.parse( sessionStorage.getItem( 'seatplan-history' ) ) : {};
|
let history = sessionStorage.getItem( 'seatplan-history' ) ? JSON.parse( sessionStorage.getItem( 'seatplan-history' ) ) : {};
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="window">
|
<div id="window">
|
||||||
<h2>Seat plan: {{ event.name }}</h2>
|
|
||||||
<div class="parent" id="parent" @wheel="( e ) => { handleScroll( e ); }" @mousemove="( e ) => { handleDrag( e ); }" @mousedown="( e ) => { setOffset( e ); }">
|
<div class="parent" id="parent" @wheel="( e ) => { handleScroll( e ); }" @mousemove="( e ) => { handleDrag( e ); }" @mousedown="( e ) => { setOffset( e ); }">
|
||||||
<div class="content-parent">
|
<div class="content-parent">
|
||||||
<Vue3DraggableResizable v-for="draggable in draggables" :initW="draggable.w" :initH="draggable.h" :x="draggable.x" :y="draggable.y" :w="draggable.w" :h="draggable.h"
|
<Vue3DraggableResizable v-for="draggable in draggables" :initW="draggable.w" :initH="draggable.h" :x="draggable.x" :y="draggable.y" :w="draggable.w" :h="draggable.h"
|
||||||
@@ -42,7 +41,7 @@
|
|||||||
<button title="Reset zoom [=]" @click="zoom( 1 );"><span class="material-symbols-outlined">center_focus_strong</span></button>
|
<button title="Reset zoom [=]" @click="zoom( 1 );"><span class="material-symbols-outlined">center_focus_strong</span></button>
|
||||||
<button title="Zoom out [-]" @click="zoom( -0.2 )"><span class="material-symbols-outlined">zoom_out</span></button>
|
<button title="Zoom out [-]" @click="zoom( -0.2 )"><span class="material-symbols-outlined">zoom_out</span></button>
|
||||||
</div>
|
</div>
|
||||||
<sideCartView :cart="cart" ref="cart"></sideCartView>
|
<sideCartView :cart="cart" :name="event.name" ref="cart"></sideCartView>
|
||||||
<notifications ref="notification" location="topright"></notifications>
|
<notifications ref="notification" location="topright"></notifications>
|
||||||
<popups ref="popups" size="normal" @data="data => { reserveTicket( data ) }"
|
<popups ref="popups" size="normal" @data="data => { reserveTicket( data ) }"
|
||||||
@ticket="data => { standingTicketHandling( data ) }"></popups>
|
@ticket="data => { standingTicketHandling( data ) }"></popups>
|
||||||
@@ -156,7 +155,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.seatChecks();
|
this.seatChecks();
|
||||||
// TODO: Optimise for odd screen sizes and aspect ratios and fucking webkit
|
|
||||||
// TODO: Trim scroll box to about 200px more than seatplan size
|
// TODO: Trim scroll box to about 200px more than seatplan size
|
||||||
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
|
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
|
||||||
window.addEventListener( 'visibilitychange', ( e ) => {
|
window.addEventListener( 'visibilitychange', ( e ) => {
|
||||||
@@ -171,15 +169,6 @@
|
|||||||
if ( res.status === 200 ) {
|
if ( res.status === 200 ) {
|
||||||
let unavailableSeats = {};
|
let unavailableSeats = {};
|
||||||
res.json().then( data => {
|
res.json().then( data => {
|
||||||
for ( let seat in data.booked ) {
|
|
||||||
if ( data.booked[ seat ] ) {
|
|
||||||
if ( !unavailableSeats[ data.booked[ seat ].component ] ) {
|
|
||||||
unavailableSeats[ data.booked[ seat ].component ];
|
|
||||||
}
|
|
||||||
unavailableSeats[ data.booked[ seat ].component ][ data.booked[ seat ].id ] = 'nav';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( let seat in data.reserved ) {
|
for ( let seat in data.reserved ) {
|
||||||
if ( data.reserved[ seat ] ) {
|
if ( data.reserved[ seat ] ) {
|
||||||
if ( !unavailableSeats[ data.reserved[ seat ].component ] ) {
|
if ( !unavailableSeats[ data.reserved[ seat ].component ] ) {
|
||||||
@@ -198,6 +187,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ( let seat in data.booked ) {
|
||||||
|
if ( data.booked[ seat ] ) {
|
||||||
|
if ( !unavailableSeats[ data.booked[ seat ].component ] ) {
|
||||||
|
unavailableSeats[ data.booked[ seat ].component ];
|
||||||
|
}
|
||||||
|
unavailableSeats[ data.booked[ seat ].component ][ data.booked[ seat ].id ] = 'nav';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let tickets = {};
|
let tickets = {};
|
||||||
if ( this.cart[ this.event.eventID ] ) {
|
if ( this.cart[ this.event.eventID ] ) {
|
||||||
tickets = this.cart[ this.event.eventID ][ 'tickets' ];
|
tickets = this.cart[ this.event.eventID ][ 'tickets' ];
|
||||||
@@ -449,8 +447,7 @@
|
|||||||
if ( data.data[ group ] > 0 ) {
|
if ( data.data[ group ] > 0 ) {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
// TODO: Add correct name here as well once it is working at all
|
body: JSON.stringify( { 'id': 'ticket' + data.component + '_' + group, 'component': data.component, 'ticketOption': group, 'eventID': this.event.eventID, 'count': data.data[ group ], 'category': this.draggables[ data.component ].category, 'name': 'Ticket ' + data.component + ' (' + this.event.ageGroups[ group ].name + ')' } ),
|
||||||
body: JSON.stringify( { 'id': 'ticket' + data.component + '_' + group, 'component': data.component, 'ticketOption': '', 'eventID': this.event.eventID, 'count': data.data[ group ], 'category': this.draggables[ data.component ].category, 'name': 'Ticket ' } ),
|
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'charset': 'utf-8'
|
'charset': 'utf-8'
|
||||||
@@ -510,7 +507,7 @@
|
|||||||
.parent {
|
.parent {
|
||||||
height: 80vh;
|
height: 80vh;
|
||||||
width: 70vw;
|
width: 70vw;
|
||||||
top: 17vh;
|
top: 90px;
|
||||||
left: 5vw;
|
left: 5vw;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: black 1px solid;
|
border: black 1px solid;
|
||||||
@@ -548,7 +545,7 @@
|
|||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 17vh;
|
top: 90px;
|
||||||
left: 5.5vw;
|
left: 5.5vw;
|
||||||
}
|
}
|
||||||
.toolbar button {
|
.toolbar button {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="sideCartView">
|
<div id="sideCartView">
|
||||||
|
<h1>Seat plan: {{ name }}</h1>
|
||||||
<h2>Cart</h2>
|
<h2>Cart</h2>
|
||||||
<div v-if="Object.keys( cart ).length > 0" style="height: 100%; width: 100%;">
|
<div v-if="Object.keys( cart ).length > 0" style="height: 100%; width: 100%;">
|
||||||
<div class="scroll-wrapper">
|
<div class="scroll-wrapper">
|
||||||
@@ -64,6 +65,10 @@ export default {
|
|||||||
'height': {
|
'height': {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 17
|
default: 17
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -92,7 +97,7 @@ export default {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
top: 17vh;
|
top: 90px;
|
||||||
width: 25vw;
|
width: 25vw;
|
||||||
background-color: var( --accent-background );
|
background-color: var( --accent-background );
|
||||||
color: var( --secondary-color );
|
color: var( --secondary-color );
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p>Detailed explanation of payment gateways can be found <a href="https://libreevent.janishutz.com/docs/payments" target="_blank">here</a>. You may install more payment gateway integrations in the plugins section.</p>
|
<p>Detailed explanation of payment gateways can be found <a href="https://libreevent.janishutz.com/docs/payments" target="_blank">here</a>. You may install more payment gateway integrations in the plugins section. Only one may be used at any given time.</p>
|
||||||
|
|
||||||
<div class="admin-settings">
|
<div class="admin-settings">
|
||||||
<h2>Admin Accounts</h2>
|
<h2>Admin Accounts</h2>
|
||||||
@@ -103,8 +103,8 @@
|
|||||||
'value': 'stripe'
|
'value': 'stripe'
|
||||||
},
|
},
|
||||||
'adyen': {
|
'adyen': {
|
||||||
'displayName':'Adyen',
|
'displayName':'Payrexx',
|
||||||
'value': 'adyen'
|
'value': 'payrexx'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -43,6 +43,12 @@
|
|||||||
<input type="password" v-model="formData[ 'password2' ]" name="password2" id="password2" required><br><br>
|
<input type="password" v-model="formData[ 'password2' ]" name="password2" id="password2" required><br><br>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="news">Do you want to potentially get newsletter?</label><br>
|
||||||
|
<input type="checkbox" v-model="formData[ 'newsletter' ]" name="news" id="news"><br><br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<!-- TODO: Ask for permission to send emails (Make question sound really optional) -->
|
<!-- TODO: Ask for permission to send emails (Make question sound really optional) -->
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Reference in New Issue
Block a user