Source

classes/ticket.ts

import { RequestContext } from "./requestContext";

/**
 * Class for handling tickets
 */
export class Ticket {
    /**
     * Verifies and uses a ticket. If the ticket is invalid, an error is thrown.
     * @param {RequestContext} ctx
     * @param {string} ticket
     * @return {Promise<void>}
     */
    public static verifyAndUse(ctx: RequestContext, ticket: string): Promise<void> {
        return new Promise((resolve, reject) => {
            ctx.conn.getConnection((err, conn) => {
                if(err) return reject(err);
                conn.beginTransaction((err) => {
                    if(err) {
                        conn.release();
                        return reject(err);
                    }
                    conn.query("SELECT * FROM tickets WHERE name = ? FOR UPDATE", [ticket],
                        (err, results) => {
                            if(!results || !results.length || err) {
                                return conn.rollback(() => {
                                    reject(err || new Error("Ticket not found"));
                                    conn.release();
                                });
                            }
                            const ticket = results[0];
                            if(ticket.usages + 1 >= ticket.max_usages) {
                                return conn.rollback(() => {
                                    reject(new Error("Ticket has been used too many times"));
                                    conn.release();
                                });
                            }
                            conn.query("UPDATE tickets SET usages = usages + 1 WHERE name = ?",
                                [ticket.name], (err) => {
                                    if(err) {
                                        return conn.rollback(() => {
                                            reject(err);
                                            conn.release();
                                        });
                                    }
                                    conn.commit((err) => {
                                        if(err) {
                                            return conn.rollback(() => {
                                                reject(err);
                                                conn.release();
                                            });
                                        }
                                        conn.release();
                                        resolve();
                                    });
                                });
                        });
                });
            });
        });
    }
}