ticket gen working + various changes

This commit is contained in:
2023-08-07 12:24:52 +02:00
parent 5cbf624284
commit ed38edd880
24 changed files with 211 additions and 98 deletions

9
.gitignore vendored
View File

@@ -16,4 +16,11 @@ node_modules
# ignore dist folder (this repo only contains source code!) # ignore dist folder (this repo only contains source code!)
/dist /dist
*.secret.json *.secret.json
# ignore all latex files except .tex
*.aux
*.fls
*.synctex.gz
*.fdb_latexmk
._wordcount_selection.tex

View 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.

Binary file not shown.

View 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}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
@@ -103,7 +103,11 @@ 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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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