From 0325534d530d1c8fafbbf41ae12616d5347524b5 Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Sun, 26 Jun 2022 14:48:00 +0200 Subject: [PATCH] Better connection handling --- src/models/betterzon/Betterzon.db.ts | 20 +- .../categories/categories.interface.ts | 2 +- .../categories/categories.service.ts | 103 ++-- .../categories/category.interface.ts | 4 +- .../contact_person.interface.ts | 14 +- .../contact_persons.interface.ts | 2 +- .../contact_persons.service.ts | 149 +++--- .../crawling_status.interface.ts | 10 +- .../crawling_status.service.ts | 73 +-- .../crawling_statuses.interface.ts | 2 +- .../favorite_shops/favoriteshop.interface.ts | 6 +- .../favorite_shops/favoriteshops.interface.ts | 2 +- .../favorite_shops/favoriteshops.service.ts | 63 ++- .../manufacturers/manufacturer.interface.ts | 4 +- .../manufacturers/manufacturers.interface.ts | 2 +- .../manufacturers/manufacturers.service.ts | 103 ++-- .../pricealarms/pricealarm.interface.ts | 8 +- .../pricealarms/pricealarms.interface.ts | 2 +- .../pricealarms/pricealarms.service.ts | 80 +-- .../betterzon/prices/price.interface.ts | 42 +- .../betterzon/prices/prices.interface.ts | 2 +- src/models/betterzon/prices/prices.service.ts | 504 +++++++++--------- .../betterzon/products/product.interface.ts | 24 +- .../betterzon/products/products.interface.ts | 2 +- .../betterzon/products/products.service.ts | 261 ++++----- .../betterzon/users/session.interface.ts | 16 +- src/models/betterzon/users/user.interface.ts | 14 +- src/models/betterzon/users/users.interface.ts | 2 +- src/models/betterzon/users/users.service.ts | 20 +- .../betterzon/vendors/vendor.interface.ts | 16 +- .../betterzon/vendors/vendors.interface.ts | 2 +- .../betterzon/vendors/vendors.service.ts | 30 +- .../ClimbingRouteRating.db.ts | 20 +- .../climbing_gyms/ClimbingGym.interface.ts | 8 +- .../climbing_gyms/climbingGyms.service.ts | 32 +- .../ClimbingRoute.interface.ts | 10 +- .../climbing_routes/climbingRoutes.service.ts | 65 ++- .../common/VerifyCaptcha.ts | 12 +- .../route_comments/RouteComment.interface.ts | 8 +- .../route_comments/routeComments.service.ts | 32 +- .../route_ratings/RouteRating.interface.ts | 8 +- .../route_ratings/routeRatings.service.ts | 48 +- .../dhbw-rapla-changes/DHBWRaPlaChanges.db.ts | 20 +- .../changes/Change.interface.ts | 28 +- .../changes/Event.interface.ts | 10 +- .../changes/changes.service.ts | 202 +++---- src/models/partyplaner/PartyPlaner.db.ts | 40 +- .../partyplaner/event/Event.interface.ts | 16 +- .../partyplaner/event/Invite.interface.ts | 10 +- .../event/Registration.interface.ts | 10 +- src/models/partyplaner/event/event.service.ts | 105 ++-- .../friendship/Friendship.interface.ts | 10 +- .../friendship/friendship.service.ts | 37 +- .../invite/ReceivedInvite.interface.ts | 24 +- .../partyplaner/invite/invite.service.ts | 51 +- .../session/SessionData.interface.ts | 8 +- .../partyplaner/session/session.service.ts | 35 +- .../partyplaner/user/Session.interface.ts | 6 +- .../partyplaner/user/Status.interface.ts | 6 +- .../partyplaner/user/UserData.interface.ts | 14 +- src/models/partyplaner/user/user.service.ts | 374 ++++++------- .../icalgenerator/icalgenerator.service.ts | 318 +++++------ .../HighlightMarker.db.ts | 20 +- .../addHighlight/addHighlights.service.ts | 31 +- 64 files changed, 1697 insertions(+), 1505 deletions(-) diff --git a/src/models/betterzon/Betterzon.db.ts b/src/models/betterzon/Betterzon.db.ts index 90f5946..70f8e3e 100644 --- a/src/models/betterzon/Betterzon.db.ts +++ b/src/models/betterzon/Betterzon.db.ts @@ -5,15 +5,15 @@ const mariadb = require('mariadb'); dotenv.config(); export namespace BetterzonDB { - const pool = mariadb.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.BETTERZON_DATABASE, - connectionLimit: 5 - }); + const pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.BETTERZON_DATABASE, + connectionLimit: 5 + }); - export function getConnection() { - return pool; - } + export const getConnection = async () => { + return pool.getConnection(); + }; } diff --git a/src/models/betterzon/categories/categories.interface.ts b/src/models/betterzon/categories/categories.interface.ts index 136ee49..863e9fd 100644 --- a/src/models/betterzon/categories/categories.interface.ts +++ b/src/models/betterzon/categories/categories.interface.ts @@ -1,5 +1,5 @@ import {Category} from './category.interface'; export interface Categories { - [key: number]: Category; + [key: number]: Category; } diff --git a/src/models/betterzon/categories/categories.service.ts b/src/models/betterzon/categories/categories.service.ts index f35a6ed..47f4fbe 100644 --- a/src/models/betterzon/categories/categories.service.ts +++ b/src/models/betterzon/categories/categories.service.ts @@ -18,29 +18,32 @@ dotenv.config(); * Fetches and returns all known categories */ export const findAll = async (): Promise => { - let conn = BetterzonDB.getConnection(); - let categRows = []; - try { - const rows = await conn.query('SELECT category_id, name FROM categories'); - for (let row in rows) { - if (row !== 'meta') { - let categ: Category = { - category_id: 0, - name: '' - }; - const sqlCateg = rows[row]; + let conn = await BetterzonDB.getConnection(); + let categRows = []; + try { + const rows = await conn.query('SELECT category_id, name FROM categories'); + for (let row in rows) { + if (row !== 'meta') { + let categ: Category = { + category_id: 0, + name: '' + }; + const sqlCateg = rows[row]; - categ.category_id = sqlCateg.category_id; - categ.name = sqlCateg.name; - categRows.push(categ); - } - } + categ.category_id = sqlCateg.category_id; + categ.name = sqlCateg.name; + categRows.push(categ); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return categRows; + return categRows; }; /** @@ -48,21 +51,24 @@ export const findAll = async (): Promise => { * @param id The id of the category to fetch */ export const find = async (id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let categ: any; - try { - const rows = await conn.query('SELECT category_id, name FROM categories WHERE category_id = ?', id); - for (let row in rows) { - if (row !== 'meta') { - categ = rows[row]; - } - } + let conn = await BetterzonDB.getConnection(); + let categ: any; + try { + const rows = await conn.query('SELECT category_id, name FROM categories WHERE category_id = ?', id); + for (let row in rows) { + if (row !== 'meta') { + categ = rows[row]; + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return categ; + return categ; }; /** @@ -70,20 +76,23 @@ export const find = async (id: number): Promise => { * @param term the term to match */ export const findBySearchTerm = async (term: string): Promise => { - let conn = BetterzonDB.getConnection(); - let categRows = []; - try { - term = '%' + term + '%'; - const rows = await conn.query('SELECT category_id, name FROM categories WHERE name LIKE ?', term); - for (let row in rows) { - if (row !== 'meta') { - categRows.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let categRows = []; + try { + term = '%' + term + '%'; + const rows = await conn.query('SELECT category_id, name FROM categories WHERE name LIKE ?', term); + for (let row in rows) { + if (row !== 'meta') { + categRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return categRows; + return categRows; }; diff --git a/src/models/betterzon/categories/category.interface.ts b/src/models/betterzon/categories/category.interface.ts index a909167..942d922 100644 --- a/src/models/betterzon/categories/category.interface.ts +++ b/src/models/betterzon/categories/category.interface.ts @@ -1,4 +1,4 @@ export interface Category { - category_id: number; - name: string; + category_id: number; + name: string; } diff --git a/src/models/betterzon/contact_persons/contact_person.interface.ts b/src/models/betterzon/contact_persons/contact_person.interface.ts index e777a40..0b32633 100644 --- a/src/models/betterzon/contact_persons/contact_person.interface.ts +++ b/src/models/betterzon/contact_persons/contact_person.interface.ts @@ -1,9 +1,9 @@ export interface Contact_Person { - contact_person_id: number; - first_name: string; - last_name: string; - gender: string; - email: string; - phone: string; - vendor_id: number; + contact_person_id: number; + first_name: string; + last_name: string; + gender: string; + email: string; + phone: string; + vendor_id: number; } diff --git a/src/models/betterzon/contact_persons/contact_persons.interface.ts b/src/models/betterzon/contact_persons/contact_persons.interface.ts index 97f8393..e9e4c41 100644 --- a/src/models/betterzon/contact_persons/contact_persons.interface.ts +++ b/src/models/betterzon/contact_persons/contact_persons.interface.ts @@ -1,5 +1,5 @@ import {Contact_Person} from './contact_person.interface'; export interface Contact_Persons { - [key: number]: Contact_Person; + [key: number]: Contact_Person; } diff --git a/src/models/betterzon/contact_persons/contact_persons.service.ts b/src/models/betterzon/contact_persons/contact_persons.service.ts index e95ad7e..b6a2533 100644 --- a/src/models/betterzon/contact_persons/contact_persons.service.ts +++ b/src/models/betterzon/contact_persons/contact_persons.service.ts @@ -18,21 +18,24 @@ dotenv.config(); * Fetches and returns all known contact persons */ export const findAll = async (): Promise => { - let conn = BetterzonDB.getConnection(); - let contRows = []; - try { - const rows = await conn.query('SELECT contact_person_id, first_name, last_name, gender, email, phone, vendor_id FROM contact_persons'); - for (let row in rows) { - if (row !== 'meta') { - contRows.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let contRows = []; + try { + const rows = await conn.query('SELECT contact_person_id, first_name, last_name, gender, email, phone, vendor_id FROM contact_persons'); + for (let row in rows) { + if (row !== 'meta') { + contRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return contRows; + return contRows; }; /** @@ -40,21 +43,24 @@ export const findAll = async (): Promise => { * @param id The id of the contact person to fetch */ export const find = async (id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let cont: any; - try { - const rows = await conn.query('SELECT contact_person_id, first_name, last_name, gender, email, phone, vendor_id FROM contact_persons WHERE contact_person_id = ?', id); - for (let row in rows) { - if (row !== 'meta') { - cont = rows[row]; - } - } + let conn = await BetterzonDB.getConnection(); + let cont: any; + try { + const rows = await conn.query('SELECT contact_person_id, first_name, last_name, gender, email, phone, vendor_id FROM contact_persons WHERE contact_person_id = ?', id); + for (let row in rows) { + if (row !== 'meta') { + cont = rows[row]; + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return cont; + return cont; }; /** @@ -62,21 +68,24 @@ export const find = async (id: number): Promise => { * @param id The id of the vendor to fetch contact persons for */ export const findByVendor = async (id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let contRows = []; - try { - const rows = await conn.query('SELECT contact_person_id, first_name, last_name, gender, email, phone, vendor_id FROM contact_persons WHERE vendor_id = ?', id); - for (let row in rows) { - if (row !== 'meta') { - contRows.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let contRows = []; + try { + const rows = await conn.query('SELECT contact_person_id, first_name, last_name, gender, email, phone, vendor_id FROM contact_persons WHERE vendor_id = ?', id); + for (let row in rows) { + if (row !== 'meta') { + contRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return contRows; + return contRows; }; /** @@ -90,22 +99,25 @@ export const findByVendor = async (id: number): Promise => { * @param phone The phone number of the contact person */ export const createContactEntry = async (user_id: number, vendor_id: number, first_name: string, last_name: string, gender: string, email: string, phone: string): Promise => { - let conn = BetterzonDB.getConnection(); - try { - // Check if the user is authorized to manage the requested vendor - const user_vendor_rows = await conn.query('SELECT vendor_id FROM vendors WHERE vendor_id = ? AND admin_id = ?', [vendor_id, user_id]); - if (user_vendor_rows.length !== 1) { - return false; - } + let conn = await BetterzonDB.getConnection(); + try { + // Check if the user is authorized to manage the requested vendor + const user_vendor_rows = await conn.query('SELECT vendor_id FROM vendors WHERE vendor_id = ? AND admin_id = ?', [vendor_id, user_id]); + if (user_vendor_rows.length !== 1) { + return false; + } - // Create contact person entry - const res = await conn.query('INSERT INTO contact_persons (first_name, last_name, gender, email, phone, vendor_id) VALUES (?, ?, ?, ?, ?, ?)', [first_name, last_name, gender, email, phone, vendor_id]); + // Create contact person entry + const res = await conn.query('INSERT INTO contact_persons (first_name, last_name, gender, email, phone, vendor_id) VALUES (?, ?, ?, ?, ?, ?)', [first_name, last_name, gender, email, phone, vendor_id]); - // If there are more / less than 1 affected rows, return false - return res.affectedRows === 1; - } catch (err) { - throw err; - } + // If there are more / less than 1 affected rows, return false + return res.affectedRows === 1; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -120,20 +132,23 @@ export const createContactEntry = async (user_id: number, vendor_id: number, fir * @param phone The phone number of the contact person */ export const updateContactEntry = async (user_id: number, contact_person_id: number, vendor_id: number, first_name: string, last_name: string, gender: string, email: string, phone: string): Promise => { - let conn = BetterzonDB.getConnection(); - try { - // Check if the user is authorized to manage the requested vendor - const user_vendor_rows = await conn.query('SELECT vendor_id FROM vendors WHERE vendor_id = ? AND admin_id = ?', [vendor_id, user_id]); - if (user_vendor_rows.length !== 1) { - return false; - } + let conn = await BetterzonDB.getConnection(); + try { + // Check if the user is authorized to manage the requested vendor + const user_vendor_rows = await conn.query('SELECT vendor_id FROM vendors WHERE vendor_id = ? AND admin_id = ?', [vendor_id, user_id]); + if (user_vendor_rows.length !== 1) { + return false; + } - // Create contact person entry - const res = await conn.query('UPDATE contact_persons SET first_name = ?, last_name = ?, gender = ?, email = ?, phone = ? WHERE contact_person_id = ? AND vendor_id = ?', [first_name, last_name, gender, email, phone, contact_person_id, vendor_id]); + // Create contact person entry + const res = await conn.query('UPDATE contact_persons SET first_name = ?, last_name = ?, gender = ?, email = ?, phone = ? WHERE contact_person_id = ? AND vendor_id = ?', [first_name, last_name, gender, email, phone, contact_person_id, vendor_id]); - // If there are more / less than 1 affected rows, return false - return res.affectedRows === 1; - } catch (err) { - throw err; - } + // If there are more / less than 1 affected rows, return false + return res.affectedRows === 1; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/betterzon/crawling_status/crawling_status.interface.ts b/src/models/betterzon/crawling_status/crawling_status.interface.ts index 14def6a..c83267f 100644 --- a/src/models/betterzon/crawling_status/crawling_status.interface.ts +++ b/src/models/betterzon/crawling_status/crawling_status.interface.ts @@ -1,7 +1,7 @@ export interface Crawling_Status { - process_id: number; - started_timestamp: Date; - combinations_to_crawl: number; - successful_crawls: number; - failed_crawls: number; + process_id: number; + started_timestamp: Date; + combinations_to_crawl: number; + successful_crawls: number; + failed_crawls: number; } diff --git a/src/models/betterzon/crawling_status/crawling_status.service.ts b/src/models/betterzon/crawling_status/crawling_status.service.ts index e8976ca..f4bde02 100644 --- a/src/models/betterzon/crawling_status/crawling_status.service.ts +++ b/src/models/betterzon/crawling_status/crawling_status.service.ts @@ -17,43 +17,46 @@ dotenv.config(); * Fetches and returns the current crawling status if the issuing user is an admin */ export const getCurrent = async (): Promise => { - let conn = BetterzonDB.getConnection(); - try { - // Get the current crawling process - let process_info = { - process_id: -1, - started_timestamp: new Date(), - combinations_to_crawl: -1 - }; - const process = await conn.query('SELECT process_id, started_timestamp, combinations_to_crawl FROM crawling_processes ORDER BY started_timestamp DESC LIMIT 1'); - for (let row in process) { - if (row !== 'meta') { - process_info = process[row]; - } - } + let conn = await BetterzonDB.getConnection(); + try { + // Get the current crawling process + let process_info = { + process_id: -1, + started_timestamp: new Date(), + combinations_to_crawl: -1 + }; + const process = await conn.query('SELECT process_id, started_timestamp, combinations_to_crawl FROM crawling_processes ORDER BY started_timestamp DESC LIMIT 1'); + for (let row in process) { + if (row !== 'meta') { + process_info = process[row]; + } + } - // Get the current status - let total_crawls = 0; - let successful_crawls = 0; - const rows = await conn.query('SELECT COUNT(status_id) as total, SUM(success) as successful FROM crawling_status WHERE process_id = ?', process_info.process_id); - for (let row in rows) { - if (row !== 'meta') { - total_crawls = rows[row].total; - successful_crawls = rows[row].successful; - } - } + // Get the current status + let total_crawls = 0; + let successful_crawls = 0; + const rows = await conn.query('SELECT COUNT(status_id) as total, SUM(success) as successful FROM crawling_status WHERE process_id = ?', process_info.process_id); + for (let row in rows) { + if (row !== 'meta') { + total_crawls = rows[row].total; + successful_crawls = rows[row].successful; + } + } - const failed_crawls = total_crawls - successful_crawls; + const failed_crawls = total_crawls - successful_crawls; - return { - process_id: process_info.process_id, - started_timestamp: process_info.started_timestamp, - combinations_to_crawl: process_info.combinations_to_crawl, - successful_crawls: successful_crawls, - failed_crawls: failed_crawls - }; + return { + process_id: process_info.process_id, + started_timestamp: process_info.started_timestamp, + combinations_to_crawl: process_info.combinations_to_crawl, + successful_crawls: successful_crawls, + failed_crawls: failed_crawls + }; - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/betterzon/crawling_status/crawling_statuses.interface.ts b/src/models/betterzon/crawling_status/crawling_statuses.interface.ts index 10815d1..d2402ff 100644 --- a/src/models/betterzon/crawling_status/crawling_statuses.interface.ts +++ b/src/models/betterzon/crawling_status/crawling_statuses.interface.ts @@ -1,5 +1,5 @@ import {Crawling_Status} from './crawling_status.interface'; export interface Crawling_Statuses { - [key: number]: Crawling_Status; + [key: number]: Crawling_Status; } diff --git a/src/models/betterzon/favorite_shops/favoriteshop.interface.ts b/src/models/betterzon/favorite_shops/favoriteshop.interface.ts index 71652b1..65eab0a 100644 --- a/src/models/betterzon/favorite_shops/favoriteshop.interface.ts +++ b/src/models/betterzon/favorite_shops/favoriteshop.interface.ts @@ -1,5 +1,5 @@ export interface FavoriteShop { - favorite_id: number; - vendor_id: number; - user_id: number; + favorite_id: number; + vendor_id: number; + user_id: number; } diff --git a/src/models/betterzon/favorite_shops/favoriteshops.interface.ts b/src/models/betterzon/favorite_shops/favoriteshops.interface.ts index b921b0d..b024af1 100644 --- a/src/models/betterzon/favorite_shops/favoriteshops.interface.ts +++ b/src/models/betterzon/favorite_shops/favoriteshops.interface.ts @@ -1,5 +1,5 @@ import {FavoriteShop} from './favoriteshop.interface'; export interface FavoriteShops { - [key: number]: FavoriteShop; + [key: number]: FavoriteShop; } diff --git a/src/models/betterzon/favorite_shops/favoriteshops.service.ts b/src/models/betterzon/favorite_shops/favoriteshops.service.ts index 7483a01..d3c451a 100644 --- a/src/models/betterzon/favorite_shops/favoriteshops.service.ts +++ b/src/models/betterzon/favorite_shops/favoriteshops.service.ts @@ -19,14 +19,17 @@ dotenv.config(); * @param vendor_id The id of the vendor to set as favorite */ export const createFavoriteShop = async (user_id: number, vendor_id: number): Promise => { - let conn = BetterzonDB.getConnection(); - try { - const res = await conn.query('INSERT INTO favorite_shops (vendor_id, user_id) VALUES (?, ?)', [vendor_id, user_id]); + let conn = await BetterzonDB.getConnection(); + try { + const res = await conn.query('INSERT INTO favorite_shops (vendor_id, user_id) VALUES (?, ?)', [vendor_id, user_id]); - return res.affectedRows === 1; - } catch (err) { - throw err; - } + return res.affectedRows === 1; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -34,20 +37,23 @@ export const createFavoriteShop = async (user_id: number, vendor_id: number): Pr * @param user_id */ export const getFavoriteShops = async (user_id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let shops = []; - try { - const rows = await conn.query('SELECT favorite_id, vendor_id, user_id FROM favorite_shops WHERE user_id = ?', user_id); - for (let row in rows) { - if (row !== 'meta') { - shops.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let shops = []; + try { + const rows = await conn.query('SELECT favorite_id, vendor_id, user_id FROM favorite_shops WHERE user_id = ?', user_id); + for (let row in rows) { + if (row !== 'meta') { + shops.push(rows[row]); + } + } - return shops; - } catch (err) { - throw err; - } + return shops; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -56,12 +62,15 @@ export const getFavoriteShops = async (user_id: number): Promise * @param favorite_id The favorite shop to delete */ export const deleteFavoriteShop = async (user_id: number, favorite_id: number): Promise => { - let conn = BetterzonDB.getConnection(); - try { - const res = await conn.query('DELETE FROM favorite_shops WHERE favorite_id = ? AND user_id = ?', [favorite_id, user_id]); + let conn = await BetterzonDB.getConnection(); + try { + const res = await conn.query('DELETE FROM favorite_shops WHERE favorite_id = ? AND user_id = ?', [favorite_id, user_id]); - return res.affectedRows === 1; - } catch (err) { - throw err; - } + return res.affectedRows === 1; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/betterzon/manufacturers/manufacturer.interface.ts b/src/models/betterzon/manufacturers/manufacturer.interface.ts index 08e8ea8..223573d 100644 --- a/src/models/betterzon/manufacturers/manufacturer.interface.ts +++ b/src/models/betterzon/manufacturers/manufacturer.interface.ts @@ -1,4 +1,4 @@ export interface Manufacturer { - manufacturer_id: number; - name: string; + manufacturer_id: number; + name: string; } diff --git a/src/models/betterzon/manufacturers/manufacturers.interface.ts b/src/models/betterzon/manufacturers/manufacturers.interface.ts index 94836e2..01f4268 100644 --- a/src/models/betterzon/manufacturers/manufacturers.interface.ts +++ b/src/models/betterzon/manufacturers/manufacturers.interface.ts @@ -1,5 +1,5 @@ import {Manufacturer} from './manufacturer.interface'; export interface Manufacturers { - [key: number]: Manufacturer; + [key: number]: Manufacturer; } diff --git a/src/models/betterzon/manufacturers/manufacturers.service.ts b/src/models/betterzon/manufacturers/manufacturers.service.ts index 6a20af5..728df5e 100644 --- a/src/models/betterzon/manufacturers/manufacturers.service.ts +++ b/src/models/betterzon/manufacturers/manufacturers.service.ts @@ -18,29 +18,32 @@ dotenv.config(); * Fetches and returns all known manufacturers */ export const findAll = async (): Promise => { - let conn = BetterzonDB.getConnection(); - let manRows = []; - try { - const rows = await conn.query('SELECT manufacturer_id, name FROM manufacturers'); - for (let row in rows) { - if (row !== 'meta') { - let man: Manufacturer = { - manufacturer_id: 0, - name: '' - }; - const sqlMan = rows[row]; + let conn = await BetterzonDB.getConnection(); + let manRows = []; + try { + const rows = await conn.query('SELECT manufacturer_id, name FROM manufacturers'); + for (let row in rows) { + if (row !== 'meta') { + let man: Manufacturer = { + manufacturer_id: 0, + name: '' + }; + const sqlMan = rows[row]; - man.manufacturer_id = sqlMan.manufacturer_id; - man.name = sqlMan.name; - manRows.push(man); - } - } + man.manufacturer_id = sqlMan.manufacturer_id; + man.name = sqlMan.name; + manRows.push(man); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return manRows; + return manRows; }; /** @@ -48,21 +51,24 @@ export const findAll = async (): Promise => { * @param id The id of the manufacturer to fetch */ export const find = async (id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let man: any; - try { - const rows = await conn.query('SELECT manufacturer_id, name FROM manufacturers WHERE manufacturer_id = ?', id); - for (let row in rows) { - if (row !== 'meta') { - man = rows[row]; - } - } + let conn = await BetterzonDB.getConnection(); + let man: any; + try { + const rows = await conn.query('SELECT manufacturer_id, name FROM manufacturers WHERE manufacturer_id = ?', id); + for (let row in rows) { + if (row !== 'meta') { + man = rows[row]; + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return man; + return man; }; /** @@ -70,20 +76,23 @@ export const find = async (id: number): Promise => { * @param term the term to match */ export const findBySearchTerm = async (term: string): Promise => { - let conn = BetterzonDB.getConnection(); - let manRows = []; - try { - term = '%' + term + '%'; - const rows = await conn.query('SELECT manufacturer_id, name FROM manufacturers WHERE name LIKE ?', term); - for (let row in rows) { - if (row !== 'meta') { - manRows.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let manRows = []; + try { + term = '%' + term + '%'; + const rows = await conn.query('SELECT manufacturer_id, name FROM manufacturers WHERE name LIKE ?', term); + for (let row in rows) { + if (row !== 'meta') { + manRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return manRows; + return manRows; }; diff --git a/src/models/betterzon/pricealarms/pricealarm.interface.ts b/src/models/betterzon/pricealarms/pricealarm.interface.ts index c8a1717..fd8acd7 100644 --- a/src/models/betterzon/pricealarms/pricealarm.interface.ts +++ b/src/models/betterzon/pricealarms/pricealarm.interface.ts @@ -1,6 +1,6 @@ export interface PriceAlarm { - alarm_id: number; - user_id: number; - product_id: number; - defined_price: number; + alarm_id: number; + user_id: number; + product_id: number; + defined_price: number; } diff --git a/src/models/betterzon/pricealarms/pricealarms.interface.ts b/src/models/betterzon/pricealarms/pricealarms.interface.ts index c1dcbbd..937710c 100644 --- a/src/models/betterzon/pricealarms/pricealarms.interface.ts +++ b/src/models/betterzon/pricealarms/pricealarms.interface.ts @@ -1,5 +1,5 @@ import {PriceAlarm} from './pricealarm.interface'; export interface PriceAlarms { - [key: number]: PriceAlarm; + [key: number]: PriceAlarm; } diff --git a/src/models/betterzon/pricealarms/pricealarms.service.ts b/src/models/betterzon/pricealarms/pricealarms.service.ts index 0ef1fe9..c4e2d4d 100644 --- a/src/models/betterzon/pricealarms/pricealarms.service.ts +++ b/src/models/betterzon/pricealarms/pricealarms.service.ts @@ -20,14 +20,17 @@ dotenv.config(); * @param defined_price The defined price for the price alarm */ export const createPriceAlarm = async (user_id: number, product_id: number, defined_price: number): Promise => { - let conn = BetterzonDB.getConnection(); - try { - const res = await conn.query('INSERT INTO price_alarms (user_id, product_id, defined_price) VALUES (?, ?, ?)', [user_id, product_id, defined_price]); + let conn = await BetterzonDB.getConnection(); + try { + const res = await conn.query('INSERT INTO price_alarms (user_id, product_id, defined_price) VALUES (?, ?, ?)', [user_id, product_id, defined_price]); - return res.affectedRows === 1; - } catch (err) { - throw err; - } + return res.affectedRows === 1; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -35,20 +38,23 @@ export const createPriceAlarm = async (user_id: number, product_id: number, defi * @param user_id */ export const getPriceAlarms = async (user_id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let priceAlarms = []; - try { - const rows = await conn.query('SELECT alarm_id, user_id, product_id, defined_price FROM price_alarms WHERE user_id = ?', user_id); - for (let row in rows) { - if (row !== 'meta') { - priceAlarms.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let priceAlarms = []; + try { + const rows = await conn.query('SELECT alarm_id, user_id, product_id, defined_price FROM price_alarms WHERE user_id = ?', user_id); + for (let row in rows) { + if (row !== 'meta') { + priceAlarms.push(rows[row]); + } + } - return priceAlarms; - } catch (err) { - throw err; - } + return priceAlarms; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -58,14 +64,17 @@ export const getPriceAlarms = async (user_id: number): Promise => { * @param defined_price The defined price for the price alarm */ export const updatePriceAlarm = async (alarm_id: number, user_id: number, defined_price: number): Promise => { - let conn = BetterzonDB.getConnection(); - try { - const res = await conn.query('UPDATE price_alarms SET defined_price = ? WHERE alarm_id = ? AND user_id = ?', [defined_price, alarm_id, user_id]); + let conn = await BetterzonDB.getConnection(); + try { + const res = await conn.query('UPDATE price_alarms SET defined_price = ? WHERE alarm_id = ? AND user_id = ?', [defined_price, alarm_id, user_id]); - return res.affectedRows === 1; - } catch (err) { - throw err; - } + return res.affectedRows === 1; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -74,12 +83,15 @@ export const updatePriceAlarm = async (alarm_id: number, user_id: number, define * @param user_id The id of the user that wants to update the price alarm */ export const deletePriceAlarm = async (alarm_id: number, user_id: number): Promise => { - let conn = BetterzonDB.getConnection(); - try { - const res = await conn.query('DELETE FROM price_alarms WHERE alarm_id = ? AND user_id = ?', [alarm_id, user_id]); + let conn = await BetterzonDB.getConnection(); + try { + const res = await conn.query('DELETE FROM price_alarms WHERE alarm_id = ? AND user_id = ?', [alarm_id, user_id]); - return res.affectedRows === 1; - } catch (err) { - throw err; - } + return res.affectedRows === 1; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/betterzon/prices/price.interface.ts b/src/models/betterzon/prices/price.interface.ts index 702015a..5ca096b 100644 --- a/src/models/betterzon/prices/price.interface.ts +++ b/src/models/betterzon/prices/price.interface.ts @@ -1,27 +1,27 @@ export interface Price { - price_id: number; - product_id: number; - vendor_id: number; - price_in_cents: number; - timestamp: Date; + price_id: number; + product_id: number; + vendor_id: number; + price_in_cents: number; + timestamp: Date; } export class Deal implements Price { - price_id: number; - product_id: number; - vendor_id: number; - price_in_cents: number; - timestamp: Date; - amazonDifference: number; - amazonDifferencePercent: number; + price_id: number; + product_id: number; + vendor_id: number; + price_in_cents: number; + timestamp: Date; + amazonDifference: number; + amazonDifferencePercent: number; - constructor(price_id: number, product_id: number, vendor_id: number, price_in_cents: number, timestamp: Date, amazonDifference: number, amazonDifferencePercent: number) { - this.price_id = price_id; - this.product_id = product_id; - this.vendor_id = vendor_id; - this.price_in_cents = price_in_cents; - this.timestamp = timestamp; - this.amazonDifference = amazonDifference; - this.amazonDifferencePercent = amazonDifferencePercent; - } + constructor(price_id: number, product_id: number, vendor_id: number, price_in_cents: number, timestamp: Date, amazonDifference: number, amazonDifferencePercent: number) { + this.price_id = price_id; + this.product_id = product_id; + this.vendor_id = vendor_id; + this.price_in_cents = price_in_cents; + this.timestamp = timestamp; + this.amazonDifference = amazonDifference; + this.amazonDifferencePercent = amazonDifferencePercent; + } } diff --git a/src/models/betterzon/prices/prices.interface.ts b/src/models/betterzon/prices/prices.interface.ts index 9469832..84467e0 100644 --- a/src/models/betterzon/prices/prices.interface.ts +++ b/src/models/betterzon/prices/prices.interface.ts @@ -1,5 +1,5 @@ import {Price} from './price.interface'; export interface Prices { - [key: number]: Price; + [key: number]: Price; } diff --git a/src/models/betterzon/prices/prices.service.ts b/src/models/betterzon/prices/prices.service.ts index ea72863..331fdb7 100644 --- a/src/models/betterzon/prices/prices.service.ts +++ b/src/models/betterzon/prices/prices.service.ts @@ -18,35 +18,38 @@ dotenv.config(); * Fetches and returns all known prices */ export const findAll = async (): Promise => { - let conn = BetterzonDB.getConnection(); - let priceRows = []; - try { - const rows = await conn.query('SELECT price_id, product_id, v.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE active_listing = true AND v.isActive = true'); - for (let row in rows) { - if (row !== 'meta') { - let price: Price = { - price_id: 0, - price_in_cents: 0, - product_id: 0, - timestamp: new Date(), - vendor_id: 0 - }; - const sqlPrice = rows[row]; + let conn = await BetterzonDB.getConnection(); + let priceRows = []; + try { + const rows = await conn.query('SELECT price_id, product_id, v.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE active_listing = true AND v.isActive = true'); + for (let row in rows) { + if (row !== 'meta') { + let price: Price = { + price_id: 0, + price_in_cents: 0, + product_id: 0, + timestamp: new Date(), + vendor_id: 0 + }; + const sqlPrice = rows[row]; - price.price_id = sqlPrice.price_id; - price.product_id = sqlPrice.product_id; - price.vendor_id = sqlPrice.vendor_id; - price.price_in_cents = sqlPrice.price_in_cents; - price.timestamp = sqlPrice.timestamp; - priceRows.push(price); - } - } + price.price_id = sqlPrice.price_id; + price.product_id = sqlPrice.product_id; + price.vendor_id = sqlPrice.vendor_id; + price.price_in_cents = sqlPrice.price_in_cents; + price.timestamp = sqlPrice.timestamp; + priceRows.push(price); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return priceRows; + return priceRows; }; /** @@ -54,21 +57,24 @@ export const findAll = async (): Promise => { * @param id The id of the price to fetch */ export const find = async (id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let price: any; - try { - const rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE price_id = ? AND active_listing = true AND v.isActive = true', id); - for (let row in rows) { - if (row !== 'meta') { - price = rows[row]; - } - } + let conn = await BetterzonDB.getConnection(); + let price: any; + try { + const rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE price_id = ? AND active_listing = true AND v.isActive = true', id); + for (let row in rows) { + if (row !== 'meta') { + price = rows[row]; + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return price; + return price; }; /** @@ -76,21 +82,24 @@ export const find = async (id: number): Promise => { * @param product the product to fetch the prices for */ export const findByProduct = async (product: number): Promise => { - let conn = BetterzonDB.getConnection(); - let priceRows = []; - try { - const rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND active_listing = true AND v.isActive = true', product); - for (let row in rows) { - if (row !== 'meta') { - priceRows.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let priceRows = []; + try { + const rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND active_listing = true AND v.isActive = true', product); + for (let row in rows) { + if (row !== 'meta') { + priceRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return priceRows; + return priceRows; }; /** @@ -102,45 +111,48 @@ export const findByProduct = async (product: number): Promise => { * @param type The type of prices, e.g. newest / lowest */ export const findByType = async (product: string, type: string): Promise => { - let conn = BetterzonDB.getConnection(); - let priceRows = []; - try { - let rows = []; - if (type === 'newest') { - // Used to get the newest price for this product per vendor - rows = await conn.query(('WITH summary AS ( ' + - 'SELECT p.product_id, ' + - 'p.vendor_id, ' + - 'p.price_in_cents, ' + - 'p.timestamp, ' + - 'ROW_NUMBER() OVER( ' + - 'PARTITION BY p.vendor_id ' + - 'ORDER BY p.timestamp DESC) AS rk ' + - 'FROM prices p ' + - 'LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id ' + - 'WHERE product_id = ? AND p.vendor_id != 1 AND active_listing = true AND v.isActive = true) ' + - 'SELECT s.* ' + - 'FROM summary s ' + - 'WHERE s.rk = 1 '), product); - } else if (type === 'lowest') { - // Used to get the lowest prices for this product over a period of time - rows = await conn.query('SELECT price_id, product_id, p.vendor_id, MIN(price_in_cents) as price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND v.vendor_id != 1 AND active_listing = true AND v.isActive = true GROUP BY DAY(timestamp) ORDER BY timestamp', product); - } else { - // If no type is given, return all prices for this product - rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND p.vendor_id != 1 AND active_listing = true AND v.isActive = true', product); - } + let conn = await BetterzonDB.getConnection(); + let priceRows = []; + try { + let rows = []; + if (type === 'newest') { + // Used to get the newest price for this product per vendor + rows = await conn.query(('WITH summary AS ( ' + + 'SELECT p.product_id, ' + + 'p.vendor_id, ' + + 'p.price_in_cents, ' + + 'p.timestamp, ' + + 'ROW_NUMBER() OVER( ' + + 'PARTITION BY p.vendor_id ' + + 'ORDER BY p.timestamp DESC) AS rk ' + + 'FROM prices p ' + + 'LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id ' + + 'WHERE product_id = ? AND p.vendor_id != 1 AND active_listing = true AND v.isActive = true) ' + + 'SELECT s.* ' + + 'FROM summary s ' + + 'WHERE s.rk = 1 '), product); + } else if (type === 'lowest') { + // Used to get the lowest prices for this product over a period of time + rows = await conn.query('SELECT price_id, product_id, p.vendor_id, MIN(price_in_cents) as price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND v.vendor_id != 1 AND active_listing = true AND v.isActive = true GROUP BY DAY(timestamp) ORDER BY timestamp', product); + } else { + // If no type is given, return all prices for this product + rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND p.vendor_id != 1 AND active_listing = true AND v.isActive = true', product); + } - for (let row in rows) { - if (row !== 'meta') { - priceRows.push(rows[row]); - } - } + for (let row in rows) { + if (row !== 'meta') { + priceRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return priceRows; + return priceRows; }; /** @@ -153,32 +165,35 @@ export const findByType = async (product: string, type: string): Promise * @param type The type of prices, e.g. newest / lowest */ export const findByVendor = async (product: string, vendor: string, type: string): Promise => { - let conn = BetterzonDB.getConnection(); - let priceRows = []; - try { - let rows = []; - if (type === 'newest') { - // Used to get the newest price for this product and vendor - rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND p.vendor_id = ? AND active_listing = true AND v.isActive = true ORDER BY timestamp DESC LIMIT 1', [product, vendor]); - } else if (type === 'lowest') { - // Used to get the lowest prices for this product and vendor in all time - rows = await conn.query('SELECT price_id, product_id, p.vendor_id, MIN(price_in_cents) as price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND p.vendor_id = ? AND active_listing = true AND v.isActive = true LIMIT 1', [product, vendor]); - } else { - // If no type is given, return all prices for this product and vendor - rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND p.vendor_id = ? AND active_listing = true AND v.isActive = true', [product, vendor]); - } + let conn = await BetterzonDB.getConnection(); + let priceRows = []; + try { + let rows = []; + if (type === 'newest') { + // Used to get the newest price for this product and vendor + rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND p.vendor_id = ? AND active_listing = true AND v.isActive = true ORDER BY timestamp DESC LIMIT 1', [product, vendor]); + } else if (type === 'lowest') { + // Used to get the lowest prices for this product and vendor in all time + rows = await conn.query('SELECT price_id, product_id, p.vendor_id, MIN(price_in_cents) as price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND p.vendor_id = ? AND active_listing = true AND v.isActive = true LIMIT 1', [product, vendor]); + } else { + // If no type is given, return all prices for this product and vendor + rows = await conn.query('SELECT price_id, product_id, p.vendor_id, price_in_cents, timestamp FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE product_id = ? AND p.vendor_id = ? AND active_listing = true AND v.isActive = true', [product, vendor]); + } - for (let row in rows) { - if (row !== 'meta') { - priceRows.push(rows[row]); - } - } + for (let row in rows) { + if (row !== 'meta') { + priceRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return priceRows; + return priceRows; }; /** @@ -187,90 +202,93 @@ export const findByVendor = async (product: string, vendor: string, type: string * @param amount The amount of deals to return */ export const getBestDeals = async (amount: number): Promise => { - let conn = BetterzonDB.getConnection(); - let priceRows = []; - try { - let allPrices: Record = {}; + let conn = await BetterzonDB.getConnection(); + let priceRows = []; + try { + let allPrices: Record = {}; - // Get newest prices for every product at every vendor - const rows = await conn.query( - 'WITH summary AS (\n' + - ' SELECT p.product_id,\n' + - ' p.vendor_id,\n' + - ' p.price_in_cents,\n' + - ' p.timestamp,\n' + - ' ROW_NUMBER() OVER(\n' + - ' PARTITION BY p.product_id, p.vendor_id\n' + - ' ORDER BY p.timestamp DESC) AS rk\n' + - ' FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE active_listing = true AND v.isActive = true)\n' + - 'SELECT s.*\n' + - 'FROM summary s\n' + - 'WHERE s.rk = 1'); + // Get newest prices for every product at every vendor + const rows = await conn.query( + 'WITH summary AS (\n' + + ' SELECT p.product_id,\n' + + ' p.vendor_id,\n' + + ' p.price_in_cents,\n' + + ' p.timestamp,\n' + + ' ROW_NUMBER() OVER(\n' + + ' PARTITION BY p.product_id, p.vendor_id\n' + + ' ORDER BY p.timestamp DESC) AS rk\n' + + ' FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id WHERE active_listing = true AND v.isActive = true)\n' + + 'SELECT s.*\n' + + 'FROM summary s\n' + + 'WHERE s.rk = 1'); - // Write returned values to allPrices map with product id as key and a list of prices as value - for (let row in rows) { - if (row !== 'meta') { - if (!allPrices[parseInt(rows[row].product_id)]) { - allPrices[parseInt(rows[row].product_id)] = []; - } + // Write returned values to allPrices map with product id as key and a list of prices as value + for (let row in rows) { + if (row !== 'meta') { + if (!allPrices[parseInt(rows[row].product_id)]) { + allPrices[parseInt(rows[row].product_id)] = []; + } - allPrices[parseInt(rows[row].product_id)].push(rows[row]); - } - } + allPrices[parseInt(rows[row].product_id)].push(rows[row]); + } + } - // Iterate over all prices to find the products with the biggest difference between amazon and other vendor - let deals: Deal[] = []; + // Iterate over all prices to find the products with the biggest difference between amazon and other vendor + let deals: Deal[] = []; - Object.keys(allPrices).forEach(productId => { - if (allPrices[parseInt(productId)]) { - let pricesForProd = allPrices[parseInt(productId)]; + Object.keys(allPrices).forEach(productId => { + if (allPrices[parseInt(productId)]) { + let pricesForProd = allPrices[parseInt(productId)]; - // Get amazon price and lowest price from other vendor - let amazonPrice = {} as Price; - let lowestPrice = {} as Price; - pricesForProd.forEach(function (price, priceIndex) { - if (price.vendor_id === 1) { - amazonPrice = price; - } else { - // If there is no lowest price yet or the price of the current iteration is lower, set / replace it - if (!lowestPrice.price_in_cents || lowestPrice.price_in_cents > price.price_in_cents) { - lowestPrice = price; - } - } - }); + // Get amazon price and lowest price from other vendor + let amazonPrice = {} as Price; + let lowestPrice = {} as Price; + pricesForProd.forEach(function (price, priceIndex) { + if (price.vendor_id === 1) { + amazonPrice = price; + } else { + // If there is no lowest price yet or the price of the current iteration is lower, set / replace it + if (!lowestPrice.price_in_cents || lowestPrice.price_in_cents > price.price_in_cents) { + lowestPrice = price; + } + } + }); - // Create deal object and add it to list - let deal = { - 'product_id': lowestPrice.product_id, - 'vendor_id': lowestPrice.vendor_id, - 'price_in_cents': lowestPrice.price_in_cents, - 'timestamp': lowestPrice.timestamp, - 'amazonDifference': (amazonPrice.price_in_cents - lowestPrice.price_in_cents), - 'amazonDifferencePercent': ((amazonPrice.price_in_cents / lowestPrice.price_in_cents) * 100) - }; + // Create deal object and add it to list + let deal = { + 'product_id': lowestPrice.product_id, + 'vendor_id': lowestPrice.vendor_id, + 'price_in_cents': lowestPrice.price_in_cents, + 'timestamp': lowestPrice.timestamp, + 'amazonDifference': (amazonPrice.price_in_cents - lowestPrice.price_in_cents), + 'amazonDifferencePercent': ((amazonPrice.price_in_cents / lowestPrice.price_in_cents) * 100) + }; - // Push only deals were the amazon price is actually higher - if (deal.amazonDifferencePercent > 0 && deal.amazonDifference > 0) { - deals.push(deal as Deal); - } - } - }); + // Push only deals were the amazon price is actually higher + if (deal.amazonDifferencePercent > 0 && deal.amazonDifference > 0) { + deals.push(deal as Deal); + } + } + }); - // Sort to have the best deals on the top - deals.sort((a, b) => a.amazonDifferencePercent! < b.amazonDifferencePercent! ? 1 : -1); + // Sort to have the best deals on the top + deals.sort((a, b) => a.amazonDifferencePercent! < b.amazonDifferencePercent! ? 1 : -1); - // Return only as many records as requested or the maximum amount of found deals, whatever is less - let maxAmt = Math.min(amount, deals.length); + // Return only as many records as requested or the maximum amount of found deals, whatever is less + let maxAmt = Math.min(amount, deals.length); - for (let dealIndex = 0; dealIndex < maxAmt; dealIndex++) { - priceRows.push(deals[dealIndex] as Price); - } - } catch (err) { - console.log(err); - throw err; - } + for (let dealIndex = 0; dealIndex < maxAmt; dealIndex++) { + priceRows.push(deals[dealIndex] as Price); + } + } catch (err) { + console.log(err); + throw err; + } finally { + // Return connection + await conn.end(); + } - return priceRows; + return priceRows; }; /** @@ -278,73 +296,79 @@ export const getBestDeals = async (amount: number): Promise => { * @param productIds the ids of the products */ export const findListByProducts = async (productIds: [number]): Promise => { - let conn = BetterzonDB.getConnection(); - let priceRows: Price[] = []; - try { - let allPrices: Record = {}; + let conn = await BetterzonDB.getConnection(); + let priceRows: Price[] = []; + try { + let allPrices: Record = {}; - // Get newest prices for every given product at every vendor - const rows = await conn.query( - 'WITH summary AS (\n' + - ' SELECT p.product_id,\n' + - ' p.vendor_id,\n' + - ' p.price_in_cents,\n' + - ' p.timestamp,\n' + - ' ROW_NUMBER() OVER(\n' + - ' PARTITION BY p.product_id, p.vendor_id\n' + - ' ORDER BY p.timestamp DESC) AS rk\n' + - ' FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id ' + - ' WHERE p.product_id IN (?) AND v.isActive = true' + - ' AND p.vendor_id != 1 AND active_listing = true)\n' + - 'SELECT s.*\n' + - 'FROM summary s\n' + - 'WHERE s.rk = 1', [productIds]); + // Get newest prices for every given product at every vendor + const rows = await conn.query( + 'WITH summary AS (\n' + + ' SELECT p.product_id,\n' + + ' p.vendor_id,\n' + + ' p.price_in_cents,\n' + + ' p.timestamp,\n' + + ' ROW_NUMBER() OVER(\n' + + ' PARTITION BY p.product_id, p.vendor_id\n' + + ' ORDER BY p.timestamp DESC) AS rk\n' + + ' FROM prices p LEFT OUTER JOIN vendors v ON v.vendor_id = p.vendor_id ' + + ' WHERE p.product_id IN (?) AND v.isActive = true' + + ' AND p.vendor_id != 1 AND active_listing = true)\n' + + 'SELECT s.*\n' + + 'FROM summary s\n' + + 'WHERE s.rk = 1', [productIds]); - // Write returned values to allPrices map with product id as key and a list of prices as value - for (let row in rows) { - if (row !== 'meta') { - if (!allPrices[parseInt(rows[row].product_id)]) { - allPrices[parseInt(rows[row].product_id)] = []; - } + // Write returned values to allPrices map with product id as key and a list of prices as value + for (let row in rows) { + if (row !== 'meta') { + if (!allPrices[parseInt(rows[row].product_id)]) { + allPrices[parseInt(rows[row].product_id)] = []; + } - allPrices[parseInt(rows[row].product_id)].push(rows[row]); - } - } + allPrices[parseInt(rows[row].product_id)].push(rows[row]); + } + } - // Iterate over all products to find lowest price - Object.keys(allPrices).forEach(productId => { - if (allPrices[parseInt(productId)]) { - let pricesForProd = allPrices[parseInt(productId)]; + // Iterate over all products to find lowest price + Object.keys(allPrices).forEach(productId => { + if (allPrices[parseInt(productId)]) { + let pricesForProd = allPrices[parseInt(productId)]; - // Sort ascending by price so index 0 has the lowest price - pricesForProd.sort((a, b) => a.price_in_cents > b.price_in_cents ? 1 : -1); + // Sort ascending by price so index 0 has the lowest price + pricesForProd.sort((a, b) => a.price_in_cents > b.price_in_cents ? 1 : -1); - // Push the lowest price to the return list - priceRows.push(pricesForProd[0]); - } - }); - } catch (err) { - throw err; - } + // Push the lowest price to the return list + priceRows.push(pricesForProd[0]); + } + }); + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return priceRows; + return priceRows; }; export const createPriceEntry = async (user_id: number, vendor_id: number, product_id: number, price_in_cents: number): Promise => { - let conn = BetterzonDB.getConnection(); - try { - // Check if the user is authorized to manage the requested vendor - const user_vendor_rows = await conn.query('SELECT vendor_id FROM vendors WHERE vendor_id = ? AND admin_id = ?', [vendor_id, user_id]); - if (user_vendor_rows.length !== 1) { - return false; - } + let conn = await BetterzonDB.getConnection(); + try { + // Check if the user is authorized to manage the requested vendor + const user_vendor_rows = await conn.query('SELECT vendor_id FROM vendors WHERE vendor_id = ? AND admin_id = ?', [vendor_id, user_id]); + if (user_vendor_rows.length !== 1) { + return false; + } - // Create price entry - const res = await conn.query('INSERT INTO prices (product_id, vendor_id, price_in_cents) VALUES (?,?,?)', [product_id, vendor_id, price_in_cents]); + // Create price entry + const res = await conn.query('INSERT INTO prices (product_id, vendor_id, price_in_cents) VALUES (?,?,?)', [product_id, vendor_id, price_in_cents]); - // If there are more / less than 1 affected rows, return false - return res.affectedRows === 1; - } catch (err) { - throw err; - } + // If there are more / less than 1 affected rows, return false + return res.affectedRows === 1; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/betterzon/products/product.interface.ts b/src/models/betterzon/products/product.interface.ts index 8c51860..bb1ce80 100644 --- a/src/models/betterzon/products/product.interface.ts +++ b/src/models/betterzon/products/product.interface.ts @@ -1,14 +1,14 @@ export interface Product { - product_id: number; - asin: string; - is_active: boolean; - name: string; - short_description: string; - long_description: string; - image_guid: string; - date_added: Date; - last_modified: Date; - manufacturer_id: number; - selling_rank: string; - category_id: number; + product_id: number; + asin: string; + is_active: boolean; + name: string; + short_description: string; + long_description: string; + image_guid: string; + date_added: Date; + last_modified: Date; + manufacturer_id: number; + selling_rank: string; + category_id: number; } diff --git a/src/models/betterzon/products/products.interface.ts b/src/models/betterzon/products/products.interface.ts index 00b5e36..176abc2 100644 --- a/src/models/betterzon/products/products.interface.ts +++ b/src/models/betterzon/products/products.interface.ts @@ -1,5 +1,5 @@ import {Product} from './product.interface'; export interface Products { - [key: number]: Product; + [key: number]: Product; } diff --git a/src/models/betterzon/products/products.service.ts b/src/models/betterzon/products/products.service.ts index 2956c0e..22741ca 100644 --- a/src/models/betterzon/products/products.service.ts +++ b/src/models/betterzon/products/products.service.ts @@ -19,49 +19,52 @@ dotenv.config(); * Fetches and returns all known products */ export const findAll = async (): Promise => { - let conn = BetterzonDB.getConnection(); - let prodRows = []; - try { - const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products'); - for (let row in rows) { - if (row !== 'meta') { - let prod: Product = { - asin: '', - category_id: 0, - date_added: new Date(), - image_guid: '', - is_active: false, - last_modified: new Date(), - long_description: '', - manufacturer_id: 0, - name: '', - product_id: 0, - selling_rank: '', - short_description: '' - }; - const sqlProd = rows[row]; + let conn = await BetterzonDB.getConnection(); + let prodRows = []; + try { + const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products'); + for (let row in rows) { + if (row !== 'meta') { + let prod: Product = { + asin: '', + category_id: 0, + date_added: new Date(), + image_guid: '', + is_active: false, + last_modified: new Date(), + long_description: '', + manufacturer_id: 0, + name: '', + product_id: 0, + selling_rank: '', + short_description: '' + }; + const sqlProd = rows[row]; - prod.product_id = sqlProd.product_id; - prod.name = sqlProd.name; - prod.asin = sqlProd.asin; - prod.is_active = sqlProd.is_active; - prod.short_description = sqlProd.short_description; - prod.long_description = sqlProd.long_description; - prod.image_guid = sqlProd.image_guid; - prod.date_added = sqlProd.date_added; - prod.last_modified = sqlProd.last_modified; - prod.manufacturer_id = sqlProd.manufacturer_id; - prod.selling_rank = sqlProd.selling_rank; - prod.category_id = sqlProd.category_id; - prodRows.push(prod); - } - } + prod.product_id = sqlProd.product_id; + prod.name = sqlProd.name; + prod.asin = sqlProd.asin; + prod.is_active = sqlProd.is_active; + prod.short_description = sqlProd.short_description; + prod.long_description = sqlProd.long_description; + prod.image_guid = sqlProd.image_guid; + prod.date_added = sqlProd.date_added; + prod.last_modified = sqlProd.last_modified; + prod.manufacturer_id = sqlProd.manufacturer_id; + prod.selling_rank = sqlProd.selling_rank; + prod.category_id = sqlProd.category_id; + prodRows.push(prod); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return prodRows; + return prodRows; }; /** @@ -69,21 +72,24 @@ export const findAll = async (): Promise => { * @param id The id of the product to fetch */ export const find = async (id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let prod: any; - try { - const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products WHERE product_id = ?', id); - for (let row in rows) { - if (row !== 'meta') { - prod = rows[row]; - } - } + let conn = await BetterzonDB.getConnection(); + let prod: any; + try { + const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products WHERE product_id = ?', id); + for (let row in rows) { + if (row !== 'meta') { + prod = rows[row]; + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return prod; + return prod; }; /** @@ -91,23 +97,26 @@ export const find = async (id: number): Promise => { * @param term the term to match */ export const findBySearchTerm = async (term: string): Promise => { - let conn = BetterzonDB.getConnection(); - let prodRows = []; - try { - term = '%' + term + '%'; - const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products WHERE name LIKE ?', term); - for (let row in rows) { - if (row !== 'meta') { - prodRows.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let prodRows = []; + try { + term = '%' + term + '%'; + const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products WHERE name LIKE ?', term); + for (let row in rows) { + if (row !== 'meta') { + prodRows.push(rows[row]); + } + } - } catch (err) { - console.log(err); - throw err; - } + } catch (err) { + console.log(err); + throw err; + } finally { + // Return connection + await conn.end(); + } - return prodRows; + return prodRows; }; /** @@ -115,21 +124,24 @@ export const findBySearchTerm = async (term: string): Promise => { * @param ids The list of product ids to fetch the details for */ export const findList = async (ids: [number]): Promise => { - let conn = BetterzonDB.getConnection(); - let prodRows = []; - try { - const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products WHERE product_id IN (?)', [ids]); - for (let row in rows) { - if (row !== 'meta') { - prodRows.push(rows[row]); - } - } + let conn = await BetterzonDB.getConnection(); + let prodRows = []; + try { + const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products WHERE product_id IN (?)', [ids]); + for (let row in rows) { + if (row !== 'meta') { + prodRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return prodRows; + return prodRows; }; /** @@ -137,31 +149,34 @@ export const findList = async (ids: [number]): Promise => { * @param id The id of the vendor to fetch the products for */ export const findByVendor = async (id: number): Promise => { - let conn = BetterzonDB.getConnection(); - let prodRows = []; - try { - // Get the relevant product ids - let relevant_prod_ids = []; - const relevantProds = await conn.query('SELECT product_id FROM prices WHERE vendor_id = ? GROUP BY product_id', id); - for (let row in relevantProds) { - if (row !== 'meta') { - relevant_prod_ids.push(relevantProds[row].product_id); - } - } + let conn = await BetterzonDB.getConnection(); + let prodRows = []; + try { + // Get the relevant product ids + let relevant_prod_ids = []; + const relevantProds = await conn.query('SELECT product_id FROM prices WHERE vendor_id = ? GROUP BY product_id', id); + for (let row in relevantProds) { + if (row !== 'meta') { + relevant_prod_ids.push(relevantProds[row].product_id); + } + } - // Fetch products - const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products WHERE product_id IN (?)', [relevant_prod_ids]); - for (let row in rows) { - if (row !== 'meta') { - prodRows.push(rows[row]); - } - } + // Fetch products + const rows = await conn.query('SELECT product_id, name, asin, is_active, short_description, long_description, image_guid, date_added, last_modified, manufacturer_id, selling_rank, category_id FROM products WHERE product_id IN (?)', [relevant_prod_ids]); + for (let row in rows) { + if (row !== 'meta') { + prodRows.push(rows[row]); + } + } - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } - return prodRows; + return prodRows; }; /** @@ -169,26 +184,26 @@ export const findByVendor = async (id: number): Promise => { * @param asin The amazon asin of the product to look for */ export const addNewProduct = async (asin: string): Promise => { - try { - let options = { - host: 'crawl.p4ddy.com', - path: '/searchNew', - port: '443', - method: 'POST' - }; + try { + let options = { + host: 'crawl.p4ddy.com', + path: '/searchNew', + port: '443', + method: 'POST' + }; - let req = http.request(options, res => { - return res.statusCode === 202; - }); - req.write(JSON.stringify({ - asin: asin, - key: process.env.CRAWLER_ACCESS_KEY - })); - req.end(); - } catch (err) { - console.log(err); - throw(err); - } + let req = http.request(options, res => { + return res.statusCode === 202; + }); + req.write(JSON.stringify({ + asin: asin, + key: process.env.CRAWLER_ACCESS_KEY + })); + req.end(); + } catch (err) { + console.log(err); + throw(err); + } - return false; + return false; }; diff --git a/src/models/betterzon/users/session.interface.ts b/src/models/betterzon/users/session.interface.ts index 4b68e9e..a34f59e 100644 --- a/src/models/betterzon/users/session.interface.ts +++ b/src/models/betterzon/users/session.interface.ts @@ -1,10 +1,10 @@ export interface Session { - session_id: number; - session_key: string; - session_key_hash: string; - createdDate?: Date; - lastLogin?: Date; - validUntil?: Date; - validDays?: number; - last_IP: string; + session_id: number; + session_key: string; + session_key_hash: string; + createdDate?: Date; + lastLogin?: Date; + validUntil?: Date; + validDays?: number; + last_IP: string; } diff --git a/src/models/betterzon/users/user.interface.ts b/src/models/betterzon/users/user.interface.ts index fbbe5a6..bd7b572 100644 --- a/src/models/betterzon/users/user.interface.ts +++ b/src/models/betterzon/users/user.interface.ts @@ -1,9 +1,9 @@ export interface User { - user_id: number; - username: string; - email: string; - password_hash: string; - registration_date: Date; - last_login_date: Date; - is_admin: boolean; + user_id: number; + username: string; + email: string; + password_hash: string; + registration_date: Date; + last_login_date: Date; + is_admin: boolean; } diff --git a/src/models/betterzon/users/users.interface.ts b/src/models/betterzon/users/users.interface.ts index 9a81dcf..4abd5cb 100644 --- a/src/models/betterzon/users/users.interface.ts +++ b/src/models/betterzon/users/users.interface.ts @@ -1,5 +1,5 @@ import {User} from './user.interface'; export interface Users { - [key: number]: User; + [key: number]: User; } diff --git a/src/models/betterzon/users/users.service.ts b/src/models/betterzon/users/users.service.ts index b844b32..f02cbfe 100644 --- a/src/models/betterzon/users/users.service.ts +++ b/src/models/betterzon/users/users.service.ts @@ -21,7 +21,7 @@ dotenv.config(); * Creates a user record in the database, also creates a session. Returns the session if successful. */ export const createUser = async (username: string, password: string, email: string, ip: string): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); try { // Hash password and generate + hash session key const pwHash = bcrypt.hashSync(password, 10); @@ -63,6 +63,9 @@ export const createUser = async (username: string, password: string, email: stri } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } }; @@ -71,7 +74,7 @@ export const createUser = async (username: string, password: string, email: stri * Returns the session information in case of a successful login */ export const login = async (username: string, password: string, ip: string): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); try { // Get saved password hash const query = 'SELECT user_id, bcrypt_password_hash FROM users WHERE username = ?'; @@ -123,6 +126,9 @@ export const login = async (username: string, password: string, ip: string): Pro } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } }; @@ -130,7 +136,7 @@ export const login = async (username: string, password: string, ip: string): Pro * Checks if the given session information are valid and returns the user information if they are */ export const checkSession = async (sessionId: string, sessionKey: string, ip: string): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); try { // Get saved session key hash const query = 'SELECT user_id, session_key_hash, validUntil FROM sessions WHERE session_id = ?'; @@ -198,6 +204,9 @@ export const checkSession = async (sessionId: string, sessionKey: string, ip: st } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } }; @@ -230,7 +239,7 @@ export interface Status { * @param email The email to check */ export const checkUsernameAndEmail = async (username: string, email: string): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); try { // Create user entry in SQL const usernameQuery = 'SELECT username FROM users WHERE username = ?'; @@ -278,5 +287,8 @@ export const checkUsernameAndEmail = async (username: string, email: string): Pr } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } }; diff --git a/src/models/betterzon/vendors/vendor.interface.ts b/src/models/betterzon/vendors/vendor.interface.ts index 51afc49..c8c0ee2 100644 --- a/src/models/betterzon/vendors/vendor.interface.ts +++ b/src/models/betterzon/vendors/vendor.interface.ts @@ -1,10 +1,10 @@ export interface Vendor { - vendor_id: number; - name: string; - streetname: string; - zip_code: string; - city: string; - country_code: string; - phone: string; - website: string; + vendor_id: number; + name: string; + streetname: string; + zip_code: string; + city: string; + country_code: string; + phone: string; + website: string; } diff --git a/src/models/betterzon/vendors/vendors.interface.ts b/src/models/betterzon/vendors/vendors.interface.ts index 3d460bf..cfaada7 100644 --- a/src/models/betterzon/vendors/vendors.interface.ts +++ b/src/models/betterzon/vendors/vendors.interface.ts @@ -1,5 +1,5 @@ import {Vendor} from './vendor.interface'; export interface Vendors { - [key: number]: Vendor; + [key: number]: Vendor; } diff --git a/src/models/betterzon/vendors/vendors.service.ts b/src/models/betterzon/vendors/vendors.service.ts index 61f5eb9..d28cc52 100644 --- a/src/models/betterzon/vendors/vendors.service.ts +++ b/src/models/betterzon/vendors/vendors.service.ts @@ -18,7 +18,7 @@ dotenv.config(); * Fetches and returns all known vendors */ export const findAll = async (): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); let vendorRows = []; try { const rows = await conn.query('SELECT vendor_id, name, streetname, zip_code, city, country_code, phone, website FROM vendors WHERE isActive = true'); @@ -50,6 +50,9 @@ export const findAll = async (): Promise => { } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } return vendorRows; @@ -60,7 +63,7 @@ export const findAll = async (): Promise => { * @param id The id of the vendor to fetch */ export const find = async (id: number): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); let vendor: any; try { const rows = await conn.query('SELECT vendor_id, name, streetname, zip_code, city, country_code, phone, website FROM vendors WHERE vendor_id = ? AND isActive = true', id); @@ -72,6 +75,9 @@ export const find = async (id: number): Promise => { } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } return vendor; @@ -82,7 +88,7 @@ export const find = async (id: number): Promise => { * @param term the term to match */ export const findBySearchTerm = async (term: string): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); let vendorRows = []; try { term = '%' + term + '%'; @@ -95,6 +101,9 @@ export const findBySearchTerm = async (term: string): Promise => { } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } return vendorRows; @@ -105,7 +114,7 @@ export const findBySearchTerm = async (term: string): Promise => { * @param user The user to return the managed shops for */ export const getManagedShops = async (user_id: number): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); let vendorRows = []; try { const rows = await conn.query('SELECT vendor_id, name, streetname, zip_code, city, country_code, phone, website FROM vendors WHERE admin_id LIKE ?', user_id); @@ -117,6 +126,9 @@ export const getManagedShops = async (user_id: number): Promise => { } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } return vendorRows; @@ -129,7 +141,7 @@ export const getManagedShops = async (user_id: number): Promise => { * @param product_id The product id of the product to deactivate the listing for */ export const deactivateListing = async (user_id: number, vendor_id: number, product_id: number): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); try { // Check if the user is authorized to manage the requested vendor const user_vendor_rows = await conn.query('SELECT vendor_id FROM vendors WHERE vendor_id = ? AND admin_id = ?', [vendor_id, user_id]); @@ -142,6 +154,9 @@ export const deactivateListing = async (user_id: number, vendor_id: number, prod return status.affectedRows > 0; } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } }; @@ -152,7 +167,7 @@ export const deactivateListing = async (user_id: number, vendor_id: number, prod * @param isActive The new active state */ export const setShopStatus = async (user_id: number, vendor_id: number, isActive: boolean): Promise => { - let conn = BetterzonDB.getConnection(); + let conn = await BetterzonDB.getConnection(); try { // Check if the user is authorized to manage the requested vendor const user_vendor_rows = await conn.query('SELECT vendor_id FROM vendors WHERE vendor_id = ? AND admin_id = ?', [vendor_id, user_id]); @@ -166,5 +181,8 @@ export const setShopStatus = async (user_id: number, vendor_id: number, isActive return status.affectedRows > 0; } catch (err) { throw err; + } finally { + // Return connection + await conn.end(); } }; diff --git a/src/models/climbing-route-rating/ClimbingRouteRating.db.ts b/src/models/climbing-route-rating/ClimbingRouteRating.db.ts index 2c4aa54..2f7be1a 100644 --- a/src/models/climbing-route-rating/ClimbingRouteRating.db.ts +++ b/src/models/climbing-route-rating/ClimbingRouteRating.db.ts @@ -5,15 +5,15 @@ const mariadb = require('mariadb'); dotenv.config(); export namespace ClimbingRouteRatingDB { - const pool = mariadb.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.CRR_DATABASE, - connectionLimit: 5 - }); + const pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.CRR_DATABASE, + connectionLimit: 5 + }); - export function getConnection() { - return pool; - } + export const getConnection = async () => { + return pool.getConnection(); + }; } diff --git a/src/models/climbing-route-rating/climbing_gyms/ClimbingGym.interface.ts b/src/models/climbing-route-rating/climbing_gyms/ClimbingGym.interface.ts index b3d5f9a..87bc87f 100644 --- a/src/models/climbing-route-rating/climbing_gyms/ClimbingGym.interface.ts +++ b/src/models/climbing-route-rating/climbing_gyms/ClimbingGym.interface.ts @@ -1,6 +1,6 @@ export interface ClimbingGym { - gym_id: number; - name: string; - city: string; - verified: boolean; + gym_id: number; + name: string; + city: string; + verified: boolean; } diff --git a/src/models/climbing-route-rating/climbing_gyms/climbingGyms.service.ts b/src/models/climbing-route-rating/climbing_gyms/climbingGyms.service.ts index 6fe5d50..3e512b1 100644 --- a/src/models/climbing-route-rating/climbing_gyms/climbingGyms.service.ts +++ b/src/models/climbing-route-rating/climbing_gyms/climbingGyms.service.ts @@ -6,12 +6,15 @@ import {ClimbingGym} from './ClimbingGym.interface'; * @return Promise The climbing halls */ export const findAll = async (): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); - try { - return await conn.query('SELECT gym_id, name, city, verified FROM climbing_gyms'); - } catch (err) { - throw err; - } + let conn = await ClimbingRouteRatingDB.getConnection(); + try { + return await conn.query('SELECT gym_id, name, city, verified FROM climbing_gyms'); + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -21,13 +24,16 @@ export const findAll = async (): Promise => { * @return number The id of the climbing hall */ export const createGym = async (name: string, city: string): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); + let conn = await ClimbingRouteRatingDB.getConnection(); - try { - let res = await conn.query('INSERT INTO climbing_gyms (name, city) VALUES (?, ?) RETURNING gym_id', [name, city]); + try { + let res = await conn.query('INSERT INTO climbing_gyms (name, city) VALUES (?, ?) RETURNING gym_id', [name, city]); - return res[0].gym_id; - } catch (err) { - throw err; - } + return res[0].gym_id; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/climbing-route-rating/climbing_routes/ClimbingRoute.interface.ts b/src/models/climbing-route-rating/climbing_routes/ClimbingRoute.interface.ts index c655623..2539b8d 100644 --- a/src/models/climbing-route-rating/climbing_routes/ClimbingRoute.interface.ts +++ b/src/models/climbing-route-rating/climbing_routes/ClimbingRoute.interface.ts @@ -1,7 +1,7 @@ export interface ClimbingRoute { - route_id: string; - gym_id: number; - name: string; - difficulty: string; - route_setting_date: Date; + route_id: string; + gym_id: number; + name: string; + difficulty: string; + route_setting_date: Date; } diff --git a/src/models/climbing-route-rating/climbing_routes/climbingRoutes.service.ts b/src/models/climbing-route-rating/climbing_routes/climbingRoutes.service.ts index 420500b..18d2d5c 100644 --- a/src/models/climbing-route-rating/climbing_routes/climbingRoutes.service.ts +++ b/src/models/climbing-route-rating/climbing_routes/climbingRoutes.service.ts @@ -7,12 +7,15 @@ import random from 'random-words'; * @return Promise The climbing routes */ export const findAll = async (): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); - try { - return await conn.query('SELECT route_id, gym_id, name, difficulty, route_setting_date FROM climbing_routes'); - } catch (err) { - throw err; - } + let conn = await ClimbingRouteRatingDB.getConnection(); + try { + return await conn.query('SELECT route_id, gym_id, name, difficulty, route_setting_date FROM climbing_routes'); + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -21,12 +24,15 @@ export const findAll = async (): Promise => { * @return Promise The climbing route */ export const findById = async (route_id: string): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); - try { - return await conn.query('SELECT route_id, gym_id, name, difficulty, route_setting_date FROM climbing_routes WHERE route_id = ?', route_id); - } catch (err) { - throw err; - } + let conn = await ClimbingRouteRatingDB.getConnection(); + try { + return await conn.query('SELECT route_id, gym_id, name, difficulty, route_setting_date FROM climbing_routes WHERE route_id = ?', route_id); + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -37,23 +43,26 @@ export const findById = async (route_id: string): Promise => { * @return string The id of the created route */ export const createRoute = async (gym_id: number, name: string, difficulty: string): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); + let conn = await ClimbingRouteRatingDB.getConnection(); - // Generate route id - let route_id = ''; - let randWords = random(3); - for (let i = 0; i <= 2; i++) { - route_id += randWords[i]; - if (i < 2) { - route_id += '-'; - } - } + // Generate route id + let route_id = ''; + let randWords = random(3); + for (let i = 0; i <= 2; i++) { + route_id += randWords[i]; + if (i < 2) { + route_id += '-'; + } + } - try { - await conn.query('INSERT INTO climbing_routes (route_id, gym_id, name, difficulty) VALUES (?, ?, ?, ?)', [route_id, gym_id, name, difficulty]); + try { + await conn.query('INSERT INTO climbing_routes (route_id, gym_id, name, difficulty) VALUES (?, ?, ?, ?)', [route_id, gym_id, name, difficulty]); - return route_id; - } catch (err) { - throw err; - } + return route_id; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/climbing-route-rating/common/VerifyCaptcha.ts b/src/models/climbing-route-rating/common/VerifyCaptcha.ts index 3922b95..3f0671c 100644 --- a/src/models/climbing-route-rating/common/VerifyCaptcha.ts +++ b/src/models/climbing-route-rating/common/VerifyCaptcha.ts @@ -5,11 +5,11 @@ import axios from 'axios'; dotenv.config(); export const verifyCaptcha = async (captcha_token: string): Promise => { - let postData = querystring.stringify({ - response: captcha_token, - secret: process.env.HCAPTCHA_SECRET - }); + let postData = querystring.stringify({ + response: captcha_token, + secret: process.env.HCAPTCHA_SECRET + }); - let res = await axios.post('https://hcaptcha.com/siteverify', postData); - return res.data.success; + let res = await axios.post('https://hcaptcha.com/siteverify', postData); + return res.data.success; }; diff --git a/src/models/climbing-route-rating/route_comments/RouteComment.interface.ts b/src/models/climbing-route-rating/route_comments/RouteComment.interface.ts index 2891847..c3cf4ab 100644 --- a/src/models/climbing-route-rating/route_comments/RouteComment.interface.ts +++ b/src/models/climbing-route-rating/route_comments/RouteComment.interface.ts @@ -1,6 +1,6 @@ export interface RouteComment { - comment_id: number; - route_id: string; - comment: string; - timestamp: Date; + comment_id: number; + route_id: string; + comment: string; + timestamp: Date; } diff --git a/src/models/climbing-route-rating/route_comments/routeComments.service.ts b/src/models/climbing-route-rating/route_comments/routeComments.service.ts index 09818fe..08f2a10 100644 --- a/src/models/climbing-route-rating/route_comments/routeComments.service.ts +++ b/src/models/climbing-route-rating/route_comments/routeComments.service.ts @@ -6,12 +6,15 @@ import {RouteComment} from './RouteComment.interface'; * @return Promise The comments */ export const findByRoute = async (route_id: string): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); - try { - return await conn.query('SELECT comment_id, route_id, comment, timestamp FROM route_comments WHERE route_id = ?', route_id); - } catch (err) { - throw err; - } + let conn = await ClimbingRouteRatingDB.getConnection(); + try { + return await conn.query('SELECT comment_id, route_id, comment, timestamp FROM route_comments WHERE route_id = ?', route_id); + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -21,12 +24,15 @@ export const findByRoute = async (route_id: string): Promise => * @return number The id of the comment */ export const createComment = async (route_id: string, comment: string): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); - try { - let res = await conn.query('INSERT INTO route_comments (route_id, comment) VALUES (?, ?) RETURNING comment_id', [route_id, comment]); + let conn = await ClimbingRouteRatingDB.getConnection(); + try { + let res = await conn.query('INSERT INTO route_comments (route_id, comment) VALUES (?, ?) RETURNING comment_id', [route_id, comment]); - return res[0].comment_id; - } catch (err) { - throw err; - } + return res[0].comment_id; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/climbing-route-rating/route_ratings/RouteRating.interface.ts b/src/models/climbing-route-rating/route_ratings/RouteRating.interface.ts index f9f4c6c..8748207 100644 --- a/src/models/climbing-route-rating/route_ratings/RouteRating.interface.ts +++ b/src/models/climbing-route-rating/route_ratings/RouteRating.interface.ts @@ -1,6 +1,6 @@ export interface RouteRating { - rating_id: number; - route_id: string; - stars: number; - timestamp: Date; + rating_id: number; + route_id: string; + stars: number; + timestamp: Date; } diff --git a/src/models/climbing-route-rating/route_ratings/routeRatings.service.ts b/src/models/climbing-route-rating/route_ratings/routeRatings.service.ts index 2d9f8db..99f38b7 100644 --- a/src/models/climbing-route-rating/route_ratings/routeRatings.service.ts +++ b/src/models/climbing-route-rating/route_ratings/routeRatings.service.ts @@ -7,12 +7,15 @@ import {RouteRating} from './RouteRating.interface'; * @return Promise The ratings */ export const findByRoute = async (route_id: string): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); - try { - return await conn.query('SELECT rating_id, route_id, stars, timestamp FROM route_ratings WHERE route_id = ?', route_id); - } catch (err) { - throw err; - } + let conn = await ClimbingRouteRatingDB.getConnection(); + try { + return await conn.query('SELECT rating_id, route_id, stars, timestamp FROM route_ratings WHERE route_id = ?', route_id); + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -21,17 +24,17 @@ export const findByRoute = async (route_id: string): Promise => { * @return number The median amount of stars with 1 fraction digit. */ export const getStarsForRoute = async (route_id: string): Promise => { - let ratings = await findByRoute(route_id); + let ratings = await findByRoute(route_id); - let starsSum = 0; - let starsAmount = 0; + let starsSum = 0; + let starsAmount = 0; - for (let rating of ratings) { - starsSum += rating.stars; - starsAmount++; - } + for (let rating of ratings) { + starsSum += rating.stars; + starsAmount++; + } - return Number((starsSum / starsAmount).toFixed(1)); + return Number((starsSum / starsAmount).toFixed(1)); }; /** @@ -41,12 +44,15 @@ export const getStarsForRoute = async (route_id: string): Promise => { * @return number The id of the created rating */ export const createRating = async (route_id: string, stars: number): Promise => { - let conn = ClimbingRouteRatingDB.getConnection(); - try { - let res = await conn.query('INSERT INTO route_ratings (route_id, stars) VALUES (?, ?) RETURNING rating_id', [route_id, stars]); + let conn = await ClimbingRouteRatingDB.getConnection(); + try { + let res = await conn.query('INSERT INTO route_ratings (route_id, stars) VALUES (?, ?) RETURNING rating_id', [route_id, stars]); - return res[0].comment_id; - } catch (err) { - throw err; - } + return res[0].comment_id; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/dhbw-rapla-changes/DHBWRaPlaChanges.db.ts b/src/models/dhbw-rapla-changes/DHBWRaPlaChanges.db.ts index e691196..abf4f33 100644 --- a/src/models/dhbw-rapla-changes/DHBWRaPlaChanges.db.ts +++ b/src/models/dhbw-rapla-changes/DHBWRaPlaChanges.db.ts @@ -5,15 +5,15 @@ const mariadb = require('mariadb'); dotenv.config(); export namespace RaPlaChangesDB { - const pool = mariadb.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.RAPLACHANGES_DATABASE, - connectionLimit: 5 - }); + const pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.RAPLACHANGES_DATABASE, + connectionLimit: 5 + }); - export function getConnection() { - return pool; - } + export const getConnection = async () => { + return pool.getConnection(); + }; } diff --git a/src/models/dhbw-rapla-changes/changes/Change.interface.ts b/src/models/dhbw-rapla-changes/changes/Change.interface.ts index 1b09280..1fe1a68 100644 --- a/src/models/dhbw-rapla-changes/changes/Change.interface.ts +++ b/src/models/dhbw-rapla-changes/changes/Change.interface.ts @@ -1,16 +1,16 @@ export interface Change { - change_id: string; - event_id: string; - change_timestamp: Date; - is_deleted: boolean; - new_summary: string; - new_description: string; - new_start: Date; - new_end: Date; - new_last_modified: Date; - new_created: Date; - new_location: string; - new_organizer: string; - new_categories: string; - new_recurring: string; + change_id: string; + event_id: string; + change_timestamp: Date; + is_deleted: boolean; + new_summary: string; + new_description: string; + new_start: Date; + new_end: Date; + new_last_modified: Date; + new_created: Date; + new_location: string; + new_organizer: string; + new_categories: string; + new_recurring: string; } diff --git a/src/models/dhbw-rapla-changes/changes/Event.interface.ts b/src/models/dhbw-rapla-changes/changes/Event.interface.ts index 15d4bc2..9ca42bf 100644 --- a/src/models/dhbw-rapla-changes/changes/Event.interface.ts +++ b/src/models/dhbw-rapla-changes/changes/Event.interface.ts @@ -1,9 +1,9 @@ import {Change} from './Change.interface'; export interface Event { - event_id: string; - event_uid: string; - latest_event_summary: string; - latest_start_date: Date; - changes: Change[]; + event_id: string; + event_uid: string; + latest_event_summary: string; + latest_start_date: Date; + changes: Change[]; } diff --git a/src/models/dhbw-rapla-changes/changes/changes.service.ts b/src/models/dhbw-rapla-changes/changes/changes.service.ts index b205dcd..8c92036 100644 --- a/src/models/dhbw-rapla-changes/changes/changes.service.ts +++ b/src/models/dhbw-rapla-changes/changes/changes.service.ts @@ -6,122 +6,128 @@ import {RaPlaChangesDB} from '../DHBWRaPlaChanges.db'; dotenv.config(); export const getChanges = async (course: string, week: string): Promise => { - let conn = RaPlaChangesDB.getConnection(); - try { - let relevantEventsRows = await conn.query('SELECT DISTINCT(entry_id) FROM rapla_changes WHERE new_start > ? AND new_start < DATE_ADD(?, INTERVAL 7 DAY)', [week, week]); + let conn = await RaPlaChangesDB.getConnection(); + try { + let relevantEventsRows = await conn.query('SELECT DISTINCT(entry_id) FROM rapla_changes WHERE new_start > ? AND new_start < DATE_ADD(?, INTERVAL 7 DAY)', [week, week]); - let relevantEventIds: string[] = []; - relevantEventsRows.forEach((row: { entry_id: string; }) => { - relevantEventIds.push(row.entry_id); - }); + let relevantEventIds: string[] = []; + relevantEventsRows.forEach((row: { entry_id: string; }) => { + relevantEventIds.push(row.entry_id); + }); - if (relevantEventIds.length < 1) { - return []; - } + if (relevantEventIds.length < 1) { + return []; + } - let rows = await conn.query('SELECT c.change_id, c.entry_id, c.change_timestamp, c.isDeleted, c.new_summary, c.new_description, c.new_start, c.new_last_modified, c.new_end, c.new_created, c.new_location, c.new_organizer, c.new_categories, e.uid FROM rapla_changes c LEFT OUTER JOIN rapla_entries e ON c.entry_id = e.entry_id WHERE c.entry_id IN (?) ORDER BY c.change_id', [relevantEventIds]); + let rows = await conn.query('SELECT c.change_id, c.entry_id, c.change_timestamp, c.isDeleted, c.new_summary, c.new_description, c.new_start, c.new_last_modified, c.new_end, c.new_created, c.new_location, c.new_organizer, c.new_categories, e.uid FROM rapla_changes c LEFT OUTER JOIN rapla_entries e ON c.entry_id = e.entry_id WHERE c.entry_id IN (?) ORDER BY c.change_id', [relevantEventIds]); - let eventsMap = new Map(); + let eventsMap = new Map(); - for (let row of rows) { - let change: Change = { - change_id: row.change_id, - event_id: row.event_id, - change_timestamp: row.change_timestamp, - is_deleted: row.isDeleted, - new_summary: row.new_summary, - new_description: row.new_description, - new_start: row.new_start, - new_end: row.new_end, - new_last_modified: row.new_last_modified, - new_created: row.new_created, - new_location: row.new_location, - new_organizer: row.new_organizer, - new_categories: row.new_categories, - new_recurring: row.new_recurring - }; + for (let row of rows) { + let change: Change = { + change_id: row.change_id, + event_id: row.event_id, + change_timestamp: row.change_timestamp, + is_deleted: row.isDeleted, + new_summary: row.new_summary, + new_description: row.new_description, + new_start: row.new_start, + new_end: row.new_end, + new_last_modified: row.new_last_modified, + new_created: row.new_created, + new_location: row.new_location, + new_organizer: row.new_organizer, + new_categories: row.new_categories, + new_recurring: row.new_recurring + }; - if (eventsMap.has(row.entry_id)) { - let event = eventsMap.get(row.entry_id); + if (eventsMap.has(row.entry_id)) { + let event = eventsMap.get(row.entry_id); - // Only adjust these fields if the event is not deleted as otherwise they would be null - if (!row.isDeleted) { - event.latest_event_summary = row.new_summary; - event.latest_start_date = row.new_start; - } - event.changes.push(change); + // Only adjust these fields if the event is not deleted as otherwise they would be null + if (!row.isDeleted) { + event.latest_event_summary = row.new_summary; + event.latest_start_date = row.new_start; + } + event.changes.push(change); - eventsMap.set(row.entry_id, event); - } else { - let event: Event = { - event_id: row.event_id, - event_uid: row.uid, - latest_event_summary: row.new_summary, - latest_start_date: row.new_start, - changes: [change] - }; + eventsMap.set(row.entry_id, event); + } else { + let event: Event = { + event_id: row.event_id, + event_uid: row.uid, + latest_event_summary: row.new_summary, + latest_start_date: row.new_start, + changes: [change] + }; - eventsMap.set(row.entry_id, event); - } - } + eventsMap.set(row.entry_id, event); + } + } - return Array.from(eventsMap.values()) as Event[]; - } catch (err) { - throw err; - } + return Array.from(eventsMap.values()) as Event[]; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; export const getEventById = async (course: string, id: string): Promise => { - let conn = RaPlaChangesDB.getConnection(); - try { - let rows = await conn.query('SELECT c.change_id, c.entry_id, c.change_timestamp, c.isDeleted, c.new_summary, c.new_description, c.new_start, c.new_last_modified, c.new_end, c.new_created, c.new_location, c.new_organizer, c.new_categories, e.uid FROM rapla_changes c LEFT OUTER JOIN rapla_entries e ON c.entry_id = e.entry_id WHERE e.uid = ? ORDER BY c.change_id', id); + let conn = await RaPlaChangesDB.getConnection(); + try { + let rows = await conn.query('SELECT c.change_id, c.entry_id, c.change_timestamp, c.isDeleted, c.new_summary, c.new_description, c.new_start, c.new_last_modified, c.new_end, c.new_created, c.new_location, c.new_organizer, c.new_categories, e.uid FROM rapla_changes c LEFT OUTER JOIN rapla_entries e ON c.entry_id = e.entry_id WHERE e.uid = ? ORDER BY c.change_id', id); - let eventsMap = new Map(); + let eventsMap = new Map(); - for (let row of rows) { - let change: Change = { - change_id: row.change_id, - event_id: row.event_id, - change_timestamp: row.change_timestamp, - is_deleted: row.isDeleted, - new_summary: row.new_summary, - new_description: row.new_description, - new_start: row.new_start, - new_end: row.new_end, - new_last_modified: row.new_last_modified, - new_created: row.new_created, - new_location: row.new_location, - new_organizer: row.new_organizer, - new_categories: row.new_categories, - new_recurring: row.new_recurring - }; + for (let row of rows) { + let change: Change = { + change_id: row.change_id, + event_id: row.event_id, + change_timestamp: row.change_timestamp, + is_deleted: row.isDeleted, + new_summary: row.new_summary, + new_description: row.new_description, + new_start: row.new_start, + new_end: row.new_end, + new_last_modified: row.new_last_modified, + new_created: row.new_created, + new_location: row.new_location, + new_organizer: row.new_organizer, + new_categories: row.new_categories, + new_recurring: row.new_recurring + }; - if (eventsMap.has(row.entry_id)) { - let event = eventsMap.get(row.entry_id); + if (eventsMap.has(row.entry_id)) { + let event = eventsMap.get(row.entry_id); - // Only adjust these fields if the event is not deleted as otherwise they would be null - if (!row.isDeleted) { - event.latest_event_summary = row.new_summary; - event.latest_start_date = row.new_start; - } - event.changes.push(change); + // Only adjust these fields if the event is not deleted as otherwise they would be null + if (!row.isDeleted) { + event.latest_event_summary = row.new_summary; + event.latest_start_date = row.new_start; + } + event.changes.push(change); - eventsMap.set(row.entry_id, event); - } else { - let event: Event = { - event_id: row.event_id, - event_uid: row.uid, - latest_event_summary: row.new_summary, - latest_start_date: row.new_start, - changes: [change] - }; + eventsMap.set(row.entry_id, event); + } else { + let event: Event = { + event_id: row.event_id, + event_uid: row.uid, + latest_event_summary: row.new_summary, + latest_start_date: row.new_start, + changes: [change] + }; - eventsMap.set(row.entry_id, event); - } - } + eventsMap.set(row.entry_id, event); + } + } - return Array.from(eventsMap.values())[0]; - } catch (err) { - throw err; - } + return Array.from(eventsMap.values())[0]; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/partyplaner/PartyPlaner.db.ts b/src/models/partyplaner/PartyPlaner.db.ts index 0977db8..b2d760e 100644 --- a/src/models/partyplaner/PartyPlaner.db.ts +++ b/src/models/partyplaner/PartyPlaner.db.ts @@ -5,25 +5,25 @@ const mariadb = require('mariadb'); dotenv.config(); export namespace PartyPlanerDB { - const prod_pool = mariadb.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.PARTYPLANER_PROD_DATABASE, - connectionLimit: 5 - }); - const dev_pool = mariadb.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.PARTYPLANER_DEV_DATABASE, - connectionLimit: 5 - }); + const prod_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_PROD_DATABASE, + connectionLimit: 5 + }); + const dev_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_DEV_DATABASE, + connectionLimit: 5 + }); - export function getConnection(useDev: boolean = false) { - if (useDev) { - return dev_pool; - } - return prod_pool; - } + export const getConnection = async (useDev: boolean = false) => { + if (useDev) { + return dev_pool.getConnection(); + } + return prod_pool.getConnection(); + }; } diff --git a/src/models/partyplaner/event/Event.interface.ts b/src/models/partyplaner/event/Event.interface.ts index 14c3a7d..ead7d4e 100644 --- a/src/models/partyplaner/event/Event.interface.ts +++ b/src/models/partyplaner/event/Event.interface.ts @@ -5,12 +5,12 @@ import {Registration} from './Registration.interface'; * Used in the getEventData method as a return value */ export interface Event { - eventId: string; - name: string; - description: string; - takesPlaceDate: Date; - registrationUntilDate: Date; - maxParticipants: number; - invites: Invite[]; - registrations: Registration[]; + eventId: string; + name: string; + description: string; + takesPlaceDate: Date; + registrationUntilDate: Date; + maxParticipants: number; + invites: Invite[]; + registrations: Registration[]; } diff --git a/src/models/partyplaner/event/Invite.interface.ts b/src/models/partyplaner/event/Invite.interface.ts index e4ecd8c..4f51e2a 100644 --- a/src/models/partyplaner/event/Invite.interface.ts +++ b/src/models/partyplaner/event/Invite.interface.ts @@ -2,9 +2,9 @@ * Used in the getEventData method */ export interface Invite { - inviteId: string; - inviteKey: string; - validUntil: Date; - alreadyUsed: boolean; - invitedPersonName: string; + inviteId: string; + inviteKey: string; + validUntil: Date; + alreadyUsed: boolean; + invitedPersonName: string; } diff --git a/src/models/partyplaner/event/Registration.interface.ts b/src/models/partyplaner/event/Registration.interface.ts index 207b40e..0cc05e6 100644 --- a/src/models/partyplaner/event/Registration.interface.ts +++ b/src/models/partyplaner/event/Registration.interface.ts @@ -2,9 +2,9 @@ * Used in the getEventData method */ export interface Registration { - registrationId: string; - name: string; - registeredDate: Date; - takesPart: boolean; - comment: string; + registrationId: string; + name: string; + registeredDate: Date; + takesPart: boolean; + comment: string; } diff --git a/src/models/partyplaner/event/event.service.ts b/src/models/partyplaner/event/event.service.ts index ea66470..19870f2 100644 --- a/src/models/partyplaner/event/event.service.ts +++ b/src/models/partyplaner/event/event.service.ts @@ -11,63 +11,66 @@ dotenv.config(); * @return Event[] A list of events */ export const getEventData = async (useDev: boolean, userId: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - let eventRows = await conn.query('SELECT event_id, name, description, takes_place_date, registration_until_date, max_participants FROM events WHERE creator_id = ?', userId); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + let eventRows = await conn.query('SELECT event_id, name, description, takes_place_date, registration_until_date, max_participants FROM events WHERE creator_id = ?', userId); - let eventsMap = new Map(); - let eventIds: string[] = []; + let eventsMap = new Map(); + let eventIds: string[] = []; - for (let row of eventRows) { - eventIds.push(row.event_id); - let event = { - eventId: row.event_id, - name: row.name, - description: row.description, - takesPlaceDate: row.takes_place_date, - registrationUntilDate: row.registration_until_date, - maxParticipants: row.max_participants, - invites: [], - registrations: [] - }; - eventsMap.set(row.event_id, event); - } + for (let row of eventRows) { + eventIds.push(row.event_id); + let event = { + eventId: row.event_id, + name: row.name, + description: row.description, + takesPlaceDate: row.takes_place_date, + registrationUntilDate: row.registration_until_date, + maxParticipants: row.max_participants, + invites: [], + registrations: [] + }; + eventsMap.set(row.event_id, event); + } - let registrationRows = await conn.query('SELECT registration_id, name, registered_date, takes_part, comment, event_id FROM event_registration WHERE event_id IN (?)', eventIds); + let registrationRows = await conn.query('SELECT registration_id, name, registered_date, takes_part, comment, event_id FROM event_registration WHERE event_id IN (?)', eventIds); - for (let row of registrationRows) { - let event = eventsMap.get(row.event_id); - if (!event) continue; - event.registrations.push({ - registrationId: row.registration_id, - name: row.name, - registeredDate: row.registered_date, - takesPart: row.takes_part, - comment: row.comment - }); - } + for (let row of registrationRows) { + let event = eventsMap.get(row.event_id); + if (!event) continue; + event.registrations.push({ + registrationId: row.registration_id, + name: row.name, + registeredDate: row.registered_date, + takesPart: row.takes_part, + comment: row.comment + }); + } - let inviteRows = await conn.query('SELECT invite_id, invite_key, valid_until, already_used, invited_person_name, event_id FROM invitations WHERE event_id IN (?)', eventIds); + let inviteRows = await conn.query('SELECT invite_id, invite_key, valid_until, already_used, invited_person_name, event_id FROM invitations WHERE event_id IN (?)', eventIds); - for (let row of inviteRows) { - let event = eventsMap.get(row.event_id); - if (!event) continue; - event.invites.push({ - inviteId: row.invite_id, - inviteKey: row.invite_key, - validUntil: row.valid_until, - alreadyUsed: row.already_used, - invitedPersonName: row.invited_person_name - }); - } + for (let row of inviteRows) { + let event = eventsMap.get(row.event_id); + if (!event) continue; + event.invites.push({ + inviteId: row.invite_id, + inviteKey: row.invite_key, + validUntil: row.valid_until, + alreadyUsed: row.already_used, + invitedPersonName: row.invited_person_name + }); + } - let eventsList: Event[] = []; - for (let event of eventsMap.values()) { - eventsList.push(event); - } + let eventsList: Event[] = []; + for (let event of eventsMap.values()) { + eventsList.push(event); + } - return eventsList; - } catch (err) { - throw err; - } + return eventsList; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/partyplaner/friendship/Friendship.interface.ts b/src/models/partyplaner/friendship/Friendship.interface.ts index 5d4e6ca..d50035f 100644 --- a/src/models/partyplaner/friendship/Friendship.interface.ts +++ b/src/models/partyplaner/friendship/Friendship.interface.ts @@ -2,9 +2,9 @@ * Used in the getFriendshipData method as a return value */ export interface Friendship { - friendshipId: string; - friendId: string; - friendFirstName: string; - friendLastName: string; - friendUsername: string; + friendshipId: string; + friendId: string; + friendFirstName: string; + friendLastName: string; + friendUsername: string; } diff --git a/src/models/partyplaner/friendship/friendship.service.ts b/src/models/partyplaner/friendship/friendship.service.ts index 2db8e71..a2f3bb9 100644 --- a/src/models/partyplaner/friendship/friendship.service.ts +++ b/src/models/partyplaner/friendship/friendship.service.ts @@ -11,24 +11,27 @@ dotenv.config(); * @return Friendship[] A list of friends */ export const getFriendshipData = async (useDev: boolean, userId: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - let rows = await conn.query('SELECT f.friendship_id, f.friend_id, u.first_name as friend_first_name, u.last_name as friend_last_name, u.username as friend_username FROM friendships f LEFT OUTER JOIN users u ON f.friend_id = u.user_id WHERE f.user_id = ?', userId); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + let rows = await conn.query('SELECT f.friendship_id, f.friend_id, u.first_name as friend_first_name, u.last_name as friend_last_name, u.username as friend_username FROM friendships f LEFT OUTER JOIN users u ON f.friend_id = u.user_id WHERE f.user_id = ?', userId); - let friends: Friendship[] = []; + let friends: Friendship[] = []; - for (let row of rows) { - friends.push({ - friendshipId: row.friendship_id, - friendId: row.friend_id, - friendFirstName: row.friend_first_name, - friendLastName: row.friend_last_name, - friendUsername: row.friend_username - }); - } + for (let row of rows) { + friends.push({ + friendshipId: row.friendship_id, + friendId: row.friend_id, + friendFirstName: row.friend_first_name, + friendLastName: row.friend_last_name, + friendUsername: row.friend_username + }); + } - return friends; - } catch (err) { - throw err; - } + return friends; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/partyplaner/invite/ReceivedInvite.interface.ts b/src/models/partyplaner/invite/ReceivedInvite.interface.ts index 322ce68..4a7bb84 100644 --- a/src/models/partyplaner/invite/ReceivedInvite.interface.ts +++ b/src/models/partyplaner/invite/ReceivedInvite.interface.ts @@ -2,16 +2,16 @@ * Used in the getInvitesData method as a return value */ export interface ReceivedInvite { - inviteId: string; - validUntil: Date; - alreadyUsed: boolean; - inviteKey: string; - eventName: string; - eventDescription: string; - takesPlaceDate: Date; - registrationUntilDate: Date; - maxParticipants: number; - eventCreatorId: string; - creatorFirstName: string; - creatorLastName: string; + inviteId: string; + validUntil: Date; + alreadyUsed: boolean; + inviteKey: string; + eventName: string; + eventDescription: string; + takesPlaceDate: Date; + registrationUntilDate: Date; + maxParticipants: number; + eventCreatorId: string; + creatorFirstName: string; + creatorLastName: string; } diff --git a/src/models/partyplaner/invite/invite.service.ts b/src/models/partyplaner/invite/invite.service.ts index 37bc5d6..9326158 100644 --- a/src/models/partyplaner/invite/invite.service.ts +++ b/src/models/partyplaner/invite/invite.service.ts @@ -11,31 +11,34 @@ dotenv.config(); * @return ReceivedInvite[] A list of invites */ export const getInvitesData = async (useDev: boolean, userId: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - let rows = await conn.query('SELECT i.invite_id, i.valid_until, i.already_used, i.invite_key, e.name as event_name, e.description as event_description, e.takes_place_date, e.registration_until_date, e.max_participants, e.creator_id, u.first_name, u.last_name FROM invitations i LEFT OUTER JOIN events e ON e.event_id = i.event_id LEFT OUTER JOIN users u ON u.user_id = e.creator_id WHERE i.user_id = ?', userId); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + let rows = await conn.query('SELECT i.invite_id, i.valid_until, i.already_used, i.invite_key, e.name as event_name, e.description as event_description, e.takes_place_date, e.registration_until_date, e.max_participants, e.creator_id, u.first_name, u.last_name FROM invitations i LEFT OUTER JOIN events e ON e.event_id = i.event_id LEFT OUTER JOIN users u ON u.user_id = e.creator_id WHERE i.user_id = ?', userId); - let invites: ReceivedInvite[] = []; + let invites: ReceivedInvite[] = []; - for (let row of rows) { - invites.push({ - inviteId: row.invite_id, - validUntil: row.valid_until, - alreadyUsed: row.already_used, - inviteKey: row.invite_key, - eventName: row.event_name, - eventDescription: row.event_description, - takesPlaceDate: row.takes_place_date, - registrationUntilDate: row.registration_until_date, - maxParticipants: row.max_participants, - eventCreatorId: row.creator_id, - creatorFirstName: row.first_name, - creatorLastName: row.last_name - }); - } + for (let row of rows) { + invites.push({ + inviteId: row.invite_id, + validUntil: row.valid_until, + alreadyUsed: row.already_used, + inviteKey: row.invite_key, + eventName: row.event_name, + eventDescription: row.event_description, + takesPlaceDate: row.takes_place_date, + registrationUntilDate: row.registration_until_date, + maxParticipants: row.max_participants, + eventCreatorId: row.creator_id, + creatorFirstName: row.first_name, + creatorLastName: row.last_name + }); + } - return invites; - } catch (err) { - throw err; - } + return invites; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/partyplaner/session/SessionData.interface.ts b/src/models/partyplaner/session/SessionData.interface.ts index 8c8cbd2..b27398c 100644 --- a/src/models/partyplaner/session/SessionData.interface.ts +++ b/src/models/partyplaner/session/SessionData.interface.ts @@ -2,8 +2,8 @@ * Used in the getSessionData method as return value */ export interface SessionData { - sessionId: string; - type: string; - lastLogin: string; - lastIp: string; + sessionId: string; + type: string; + lastLogin: string; + lastIp: string; } diff --git a/src/models/partyplaner/session/session.service.ts b/src/models/partyplaner/session/session.service.ts index 60196eb..1ffe6c0 100644 --- a/src/models/partyplaner/session/session.service.ts +++ b/src/models/partyplaner/session/session.service.ts @@ -11,23 +11,26 @@ dotenv.config(); * @return SessionData[] A list containing objects with the session data */ export const getSessionData = async (useDev: boolean, userId: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - let rows = await conn.query('SELECT session_id, type, last_login, last_ip FROM sessions WHERE user_id = ? AND valid_until > NOW()', userId); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + let rows = await conn.query('SELECT session_id, type, last_login, last_ip FROM sessions WHERE user_id = ? AND valid_until > NOW()', userId); - let sessions: SessionData[] = []; + let sessions: SessionData[] = []; - for (let row of rows) { - sessions.push({ - sessionId: row.session_id, - type: row.type, - lastLogin: row.last_login, - lastIp: row.last_ip - }); - } + for (let row of rows) { + sessions.push({ + sessionId: row.session_id, + type: row.type, + lastLogin: row.last_login, + lastIp: row.last_ip + }); + } - return sessions; - } catch (err) { - throw err; - } + return sessions; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/partyplaner/user/Session.interface.ts b/src/models/partyplaner/user/Session.interface.ts index 048c6ec..9c89472 100644 --- a/src/models/partyplaner/user/Session.interface.ts +++ b/src/models/partyplaner/user/Session.interface.ts @@ -2,7 +2,7 @@ * Used in the registerUser and loginUser methods as return value */ export interface Session { - userId: string; - sessionId: string; - sessionKey: string; + userId: string; + sessionId: string; + sessionKey: string; } diff --git a/src/models/partyplaner/user/Status.interface.ts b/src/models/partyplaner/user/Status.interface.ts index 8b0e3f8..4125aa0 100644 --- a/src/models/partyplaner/user/Status.interface.ts +++ b/src/models/partyplaner/user/Status.interface.ts @@ -2,7 +2,7 @@ * Used in the checkUsernameAndEmail method as return value */ export interface Status { - hasProblems: boolean; - messages: string[]; - status: string[]; + hasProblems: boolean; + messages: string[]; + status: string[]; } diff --git a/src/models/partyplaner/user/UserData.interface.ts b/src/models/partyplaner/user/UserData.interface.ts index 9c8b27c..d6c8b07 100644 --- a/src/models/partyplaner/user/UserData.interface.ts +++ b/src/models/partyplaner/user/UserData.interface.ts @@ -2,11 +2,11 @@ * Used in the getUserData method as return value */ export interface UserData { - username: string; - email: string; - firstName: string; - lastName: string; - lastLogin: string; - emailIsVerified: string; - isPremiumUser: string; + username: string; + email: string; + firstName: string; + lastName: string; + lastLogin: string; + emailIsVerified: string; + isPremiumUser: string; } diff --git a/src/models/partyplaner/user/user.service.ts b/src/models/partyplaner/user/user.service.ts index aef533e..dc99298 100644 --- a/src/models/partyplaner/user/user.service.ts +++ b/src/models/partyplaner/user/user.service.ts @@ -15,28 +15,31 @@ dotenv.config(); * @return UserData An object containing the user data */ export const getUserData = async (useDev: boolean, userId: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - let rows = await conn.query('SELECT username, email, first_name, last_Name, last_login, email_is_verified, is_premium_user FROM users WHERE user_id = ?', userId); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + let rows = await conn.query('SELECT username, email, first_name, last_Name, last_login, email_is_verified, is_premium_user FROM users WHERE user_id = ?', userId); - let user: UserData = {} as UserData; + let user: UserData = {} as UserData; - for (let row of rows) { - user = { - username: row.username, - email: row.email, - firstName: row.first_name, - lastName: row.last_name, - lastLogin: row.last_login, - emailIsVerified: row.email_is_verified, - isPremiumUser: row.is_premium_user - }; - } + for (let row of rows) { + user = { + username: row.username, + email: row.email, + firstName: row.first_name, + lastName: row.last_name, + lastLogin: row.last_login, + emailIsVerified: row.email_is_verified, + isPremiumUser: row.is_premium_user + }; + } - return user; - } catch (err) { - throw err; - } + return user; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -45,25 +48,28 @@ export const getUserData = async (useDev: boolean, userId: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - const rows = await conn.query('SELECT username, email FROM users'); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + const rows = await conn.query('SELECT username, email FROM users'); - let usernames: string[] = []; - let emails: string[] = []; + let usernames: string[] = []; + let emails: string[] = []; - for (let row of rows) { - usernames.push(row.username); - emails.push(row.email); - } + for (let row of rows) { + usernames.push(row.username); + emails.push(row.email); + } - return { - 'usernames': usernames, - 'emails': emails - }; - } catch (err) { - throw err; - } + return { + 'usernames': usernames, + 'emails': emails + }; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -78,54 +84,57 @@ export const getExistingUsernamesAndEmails = async (useDev: boolean): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - const pwHash = bcrypt.hashSync(password, 10); - const sessionKey = Guid.create().toString(); - const sessionKeyHash = bcrypt.hashSync(sessionKey, 10); - const verifyEmailCode = Guid.create().toString(); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + const pwHash = bcrypt.hashSync(password, 10); + const sessionKey = Guid.create().toString(); + const sessionKeyHash = bcrypt.hashSync(sessionKey, 10); + const verifyEmailCode = Guid.create().toString(); - // Create user - const userQuery = 'INSERT INTO users (username, email, first_name, last_name, password_hash, verify_email_code, registration_date, last_login) VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW()) RETURNING user_id'; - const userIdRes = await conn.query(userQuery, [username, email, firstName, lastName, pwHash, verifyEmailCode]); - await conn.commit(); + // Create user + const userQuery = 'INSERT INTO users (username, email, first_name, last_name, password_hash, verify_email_code, registration_date, last_login) VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW()) RETURNING user_id'; + const userIdRes = await conn.query(userQuery, [username, email, firstName, lastName, pwHash, verifyEmailCode]); + await conn.commit(); - // Get user id of the created user - let userId: number = -1; - for (const row of userIdRes) { - if (row.user_id != null) { - userId = row.user_id; - } - } + // Get user id of the created user + let userId: number = -1; + for (const row of userIdRes) { + if (row.user_id != null) { + userId = row.user_id; + } + } - let deviceType = 'unknown'; - if (deviceInfo.includes('PartyPlaner') || deviceInfo.includes('Dart')) { - deviceType = 'mobile'; - } else { - deviceType = 'desktop'; - } + let deviceType = 'unknown'; + if (deviceInfo.includes('PartyPlaner') || deviceInfo.includes('Dart')) { + deviceType = 'mobile'; + } else { + deviceType = 'desktop'; + } - // Create session - const sessionQuery = 'INSERT INTO sessions (user_id, session_key_hash, created_Date, last_login, valid_until, valid_days, last_ip, device_info, type) VALUES (?,?,NOW(),NOW(),DATE_ADD(NOW(), INTERVAL 365 DAY),365,?, ?, ?) RETURNING session_id'; - const sessionIdRes = await conn.query(sessionQuery, [userId, sessionKeyHash, ip, deviceInfo, deviceType]); - await conn.commit(); + // Create session + const sessionQuery = 'INSERT INTO sessions (user_id, session_key_hash, created_Date, last_login, valid_until, valid_days, last_ip, device_info, type) VALUES (?,?,NOW(),NOW(),DATE_ADD(NOW(), INTERVAL 365 DAY),365,?, ?, ?) RETURNING session_id'; + const sessionIdRes = await conn.query(sessionQuery, [userId, sessionKeyHash, ip, deviceInfo, deviceType]); + await conn.commit(); - // Get session id of the created session - let sessionId: number = -1; - for (const row of sessionIdRes) { - if (row.session_id != null) { - sessionId = row.session_id; - } - } + // Get session id of the created session + let sessionId: number = -1; + for (const row of sessionIdRes) { + if (row.session_id != null) { + sessionId = row.session_id; + } + } - return { - 'userId': userId.toString(), - 'sessionId': sessionId.toString(), - 'sessionKey': sessionKey - }; - } catch (err) { - throw err; - } + return { + 'userId': userId.toString(), + 'sessionId': sessionId.toString(), + 'sessionKey': sessionKey + }; + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -138,66 +147,69 @@ export const registerUser = async (useDev: boolean, username: string, email: str * @param deviceInfo The user agent of the new user */ export const loginUser = async (useDev: boolean, username: string, email: string, password: string, ip: string, deviceInfo: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - let query_result; + let conn = await PartyPlanerDB.getConnection(useDev); + try { + let query_result; - // Get the saved hash - if (username !== '') { - query_result = await conn.query('SELECT user_id, password_hash FROM users WHERE username = ?', username); - } else { - query_result = await conn.query('SELECT user_id, password_hash FROM users WHERE email = ?', email); - } + // Get the saved hash + if (username !== '') { + query_result = await conn.query('SELECT user_id, password_hash FROM users WHERE username = ?', username); + } else { + query_result = await conn.query('SELECT user_id, password_hash FROM users WHERE email = ?', email); + } - let passwordHash: string = ''; - let userId: string = ''; + let passwordHash: string = ''; + let userId: string = ''; - for (let row of query_result) { - passwordHash = row.password_hash; - userId = row.user_id; - } + for (let row of query_result) { + passwordHash = row.password_hash; + userId = row.user_id; + } - // Wrong password - if (!bcrypt.compareSync(password, passwordHash)) { - return {} as Session; - } + // Wrong password + if (!bcrypt.compareSync(password, passwordHash)) { + return {} as Session; + } - // Update user last login - await conn.query('UPDATE users SET last_login = NOW() WHERE user_id = ?', userId); - await conn.commit(); + // Update user last login + await conn.query('UPDATE users SET last_login = NOW() WHERE user_id = ?', userId); + await conn.commit(); - // Create session - const sessionKey = Guid.create().toString(); - const sessionKeyHash = bcrypt.hashSync(sessionKey, 10); + // Create session + const sessionKey = Guid.create().toString(); + const sessionKeyHash = bcrypt.hashSync(sessionKey, 10); - let deviceType = 'unknown'; - if (deviceInfo.includes('PartyPlaner') || deviceInfo.includes('Dart')) { - deviceType = 'mobile'; - } else { - deviceType = 'desktop'; - } + let deviceType = 'unknown'; + if (deviceInfo.includes('PartyPlaner') || deviceInfo.includes('Dart')) { + deviceType = 'mobile'; + } else { + deviceType = 'desktop'; + } - const sessionQuery = 'INSERT INTO sessions (user_id, session_key_hash, created_Date, last_login, valid_until, valid_days, last_ip, device_info, type) VALUES (?,?,NOW(),NOW(),DATE_ADD(NOW(), INTERVAL 365 DAY),365,?, ?, ?) RETURNING session_id'; - const sessionIdRes = await conn.query(sessionQuery, [userId, sessionKeyHash, ip, deviceInfo, deviceType]); - await conn.commit(); + const sessionQuery = 'INSERT INTO sessions (user_id, session_key_hash, created_Date, last_login, valid_until, valid_days, last_ip, device_info, type) VALUES (?,?,NOW(),NOW(),DATE_ADD(NOW(), INTERVAL 365 DAY),365,?, ?, ?) RETURNING session_id'; + const sessionIdRes = await conn.query(sessionQuery, [userId, sessionKeyHash, ip, deviceInfo, deviceType]); + await conn.commit(); - // Get session id of the created session - let sessionId: number = -1; - for (const row of sessionIdRes) { - if (row.session_id != null) { - sessionId = row.session_id; - } - } + // Get session id of the created session + let sessionId: number = -1; + for (const row of sessionIdRes) { + if (row.session_id != null) { + sessionId = row.session_id; + } + } - return { - 'userId': userId.toString(), - 'sessionId': sessionId.toString(), - 'sessionKey': sessionKey - }; + return { + 'userId': userId.toString(), + 'sessionId': sessionId.toString(), + 'sessionKey': sessionKey + }; - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; /** @@ -207,68 +219,74 @@ export const loginUser = async (useDev: boolean, username: string, email: string * @param email The email to check */ export const checkUsernameAndEmail = async (useDev: boolean, username: string, email: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - const usernameQuery = 'SELECT username FROM users WHERE username = ?'; - const emailQuery = 'SELECT email FROM users WHERE email = ?'; - const usernameRes = await conn.query(usernameQuery, username); - const emailRes = await conn.query(emailQuery, email); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + const usernameQuery = 'SELECT username FROM users WHERE username = ?'; + const emailQuery = 'SELECT email FROM users WHERE email = ?'; + const usernameRes = await conn.query(usernameQuery, username); + const emailRes = await conn.query(emailQuery, email); - let res: Status = { - hasProblems: false, - messages: [], - status: [] - }; + let res: Status = { + hasProblems: false, + messages: [], + status: [] + }; - const usernameRegex = RegExp('^[a-zA-Z0-9\\-\\_]{4,20}$'); // Can contain a-z, A-Z, 0-9, -, _ and has to be 4-20 chars long - if (!usernameRegex.test(username)) { - // Username doesn't match requirements - res.hasProblems = true; - res.messages.push('The username contains illegal characters or is not the allowed size'); - res.status.push('INVALID_USERNAME'); - } + const usernameRegex = RegExp('^[a-zA-Z0-9\\-\\_]{4,20}$'); // Can contain a-z, A-Z, 0-9, -, _ and has to be 4-20 chars long + if (!usernameRegex.test(username)) { + // Username doesn't match requirements + res.hasProblems = true; + res.messages.push('The username contains illegal characters or is not the allowed size'); + res.status.push('INVALID_USERNAME'); + } - const emailRegex = RegExp('^[a-zA-Z0-9\\-\\_.]{1,30}\\@[a-zA-Z0-9\\-.]{1,20}\\.[a-z]{1,20}$'); // Normal email regex, user@plutodev.de - if (!emailRegex.test(email)) { - // Username doesn't match requirements - res.hasProblems = true; - res.messages.push('The email contains illegal characters or is not the allowed size'); - res.status.push('INVALID_EMAIL'); - } + const emailRegex = RegExp('^[a-zA-Z0-9\\-\\_.]{1,30}\\@[a-zA-Z0-9\\-.]{1,20}\\.[a-z]{1,20}$'); // Normal email regex, user@plutodev.de + if (!emailRegex.test(email)) { + // Username doesn't match requirements + res.hasProblems = true; + res.messages.push('The email contains illegal characters or is not the allowed size'); + res.status.push('INVALID_EMAIL'); + } - if (usernameRes.length > 0) { - // Username is a duplicate - res.hasProblems = true; - res.messages.push('This username is already in use'); - res.status.push('DUPLICATE_USERNAME'); - } + if (usernameRes.length > 0) { + // Username is a duplicate + res.hasProblems = true; + res.messages.push('This username is already in use'); + res.status.push('DUPLICATE_USERNAME'); + } - if (emailRes.length > 0) { - // Email is a duplicate - res.hasProblems = true; - res.messages.push('This email is already in use'); - res.status.push('DUPLICATE_EMAIL'); - } + if (emailRes.length > 0) { + // Email is a duplicate + res.hasProblems = true; + res.messages.push('This email is already in use'); + res.status.push('DUPLICATE_EMAIL'); + } - return res; + return res; - } catch (err) { - throw err; - } + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; export const checkSession = async (useDev: boolean, userId: string, sessionId: string, sessionKey: string): Promise => { - let conn = PartyPlanerDB.getConnection(useDev); - try { - let rows = await conn.query('SELECT session_key_hash FROM sessions WHERE user_id = ? AND session_id = ?', [userId, sessionId]); + let conn = await PartyPlanerDB.getConnection(useDev); + try { + let rows = await conn.query('SELECT session_key_hash FROM sessions WHERE user_id = ? AND session_id = ?', [userId, sessionId]); - let savedHash = ''; - for (let row of rows) { - savedHash = row.session_key_hash; - } + let savedHash = ''; + for (let row of rows) { + savedHash = row.session_key_hash; + } - return bcrypt.compareSync(sessionKey, savedHash); - } catch (err) { - throw err; - } + return bcrypt.compareSync(sessionKey, savedHash); + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } }; diff --git a/src/models/rapla-middleware/icalgenerator/icalgenerator.service.ts b/src/models/rapla-middleware/icalgenerator/icalgenerator.service.ts index ff81f8b..d5bc526 100644 --- a/src/models/rapla-middleware/icalgenerator/icalgenerator.service.ts +++ b/src/models/rapla-middleware/icalgenerator/icalgenerator.service.ts @@ -1,222 +1,222 @@ const fetch = require('node-fetch'); export const getiCalFile = async (user: string, file: string, showBlockers: boolean, electiveModule: string, profileModule: string): Promise => { - try { - let iCalFileContents = ''; + try { + let iCalFileContents = ''; - let baseUrl = 'https://rapla.dhbw-karlsruhe.de/rapla?page=ical'; - baseUrl += '&user=' + user; - baseUrl += '&file=' + file; + let baseUrl = 'https://rapla.dhbw-karlsruhe.de/rapla?page=ical'; + baseUrl += '&user=' + user; + baseUrl += '&file=' + file; - const response = await fetch(baseUrl); + const response = await fetch(baseUrl); - let body = await response.text(); + let body = await response.text(); - // Parse the ical file - let iCalFile = parseIcal(body); + // Parse the ical file + let iCalFile = parseIcal(body); - // Now remove unwanted shit from the iCal file - if (!showBlockers) { - iCalFile = removeBlockers(iCalFile); - } + // Now remove unwanted shit from the iCal file + if (!showBlockers) { + iCalFile = removeBlockers(iCalFile); + } - if (electiveModule !== '') { - iCalFile = removeElective(iCalFile, electiveModule); - } + if (electiveModule !== '') { + iCalFile = removeElective(iCalFile, electiveModule); + } - if (profileModule !== '') { - iCalFile = removeProfile(iCalFile, profileModule); - } + if (profileModule !== '') { + iCalFile = removeProfile(iCalFile, profileModule); + } - // Turn into one file again - let resultingFile = serializeIcal(iCalFile); + // Turn into one file again + let resultingFile = serializeIcal(iCalFile); - return resultingFile; - } catch (err) { - throw err; - } + return resultingFile; + } catch (err) { + throw err; + } }; export const parseIcal = function (icalContents: string): iCalFile { - const fileHeaderRegex: RegExp = /^BEGIN:VCALENDAR.*?BEGIN:VEVENT$/ms; - const eventRegex: RegExp = /^BEGIN:VEVENT.*?END:VEVENT$/msg; + const fileHeaderRegex: RegExp = /^BEGIN:VCALENDAR.*?BEGIN:VEVENT$/ms; + const eventRegex: RegExp = /^BEGIN:VEVENT.*?END:VEVENT$/msg; - let headerMatch = fileHeaderRegex.exec(icalContents); - let header = ''; + let headerMatch = fileHeaderRegex.exec(icalContents); + let header = ''; - if (headerMatch) { - header = headerMatch[0]; - } + if (headerMatch) { + header = headerMatch[0]; + } - header = header.substr(0, header.lastIndexOf('\n') + 1); + header = header.substr(0, header.lastIndexOf('\n') + 1); - let events: iCalEvent[] = []; - let match: any; - while (match = eventRegex.exec(icalContents)) { - if (match) { - events.push({ - content: match[0], - duration: getDuration(match[0]) - }); - } - } + let events: iCalEvent[] = []; + let match: any; + while (match = eventRegex.exec(icalContents)) { + if (match) { + events.push({ + content: match[0], + duration: getDuration(match[0]) + }); + } + } - return { - head: header, - body: events - }; + return { + head: header, + body: events + }; }; export const getDuration = function (event: string): number { - let startRegex: RegExp = /DTSTART.*?(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z?\r/gm; - let endRegex: RegExp = /DTEND.*?(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z?\r/gm; + let startRegex: RegExp = /DTSTART.*?(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z?\r/gm; + let endRegex: RegExp = /DTEND.*?(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z?\r/gm; - let startMatch = startRegex.exec(event); + let startMatch = startRegex.exec(event); - let startDtYear = 0; - let startDtMonth = 0; - let startDtDay = 0; - let startDtHour = 0; - let startDtMinute = 0; - if (startMatch) { - startDtYear = parseInt(startMatch[1]); - startDtMonth = parseInt(startMatch[2]); - startDtDay = parseInt(startMatch[3]); - startDtHour = parseInt(startMatch[4]); - startDtMinute = parseInt(startMatch[5]); - } + let startDtYear = 0; + let startDtMonth = 0; + let startDtDay = 0; + let startDtHour = 0; + let startDtMinute = 0; + if (startMatch) { + startDtYear = parseInt(startMatch[1]); + startDtMonth = parseInt(startMatch[2]); + startDtDay = parseInt(startMatch[3]); + startDtHour = parseInt(startMatch[4]); + startDtMinute = parseInt(startMatch[5]); + } - let endMatch = endRegex.exec(event); - let endDtYear = 0; - let endDtMonth = 0; - let endDtDay = 0; - let endDtHour = 0; - let endDtMinute = 0; - if (endMatch) { - endDtYear = parseInt(endMatch[1]); - endDtMonth = parseInt(endMatch[2]); - endDtDay = parseInt(endMatch[3]); - endDtHour = parseInt(endMatch[4]); - endDtMinute = parseInt(endMatch[5]); - } + let endMatch = endRegex.exec(event); + let endDtYear = 0; + let endDtMonth = 0; + let endDtDay = 0; + let endDtHour = 0; + let endDtMinute = 0; + if (endMatch) { + endDtYear = parseInt(endMatch[1]); + endDtMonth = parseInt(endMatch[2]); + endDtDay = parseInt(endMatch[3]); + endDtHour = parseInt(endMatch[4]); + endDtMinute = parseInt(endMatch[5]); + } - let startDt = new Date(startDtYear, startDtMonth - 1, startDtDay, startDtHour, startDtMinute); - let endDt = new Date(endDtYear, endDtMonth - 1, endDtDay, endDtHour, endDtMinute); + let startDt = new Date(startDtYear, startDtMonth - 1, startDtDay, startDtHour, startDtMinute); + let endDt = new Date(endDtYear, endDtMonth - 1, endDtDay, endDtHour, endDtMinute); - let hourDifference = endDt.getHours() - startDt.getHours(); - let minuteDifference = 0; + let hourDifference = endDt.getHours() - startDt.getHours(); + let minuteDifference = 0; - if (hourDifference === 0) { - minuteDifference = endDt.getMinutes() - startDt.getMinutes(); - } + if (hourDifference === 0) { + minuteDifference = endDt.getMinutes() - startDt.getMinutes(); + } - return hourDifference + (minuteDifference / 60); + return hourDifference + (minuteDifference / 60); }; export const serializeIcal = function (ical: iCalFile): string { - let resString = ical.head; - ical.body.forEach((event) => { - resString += event.content + '\n'; - }); - resString += 'END:VCALENDAR\n'; + let resString = ical.head; + ical.body.forEach((event) => { + resString += event.content + '\n'; + }); + resString += 'END:VCALENDAR\n'; - return resString; + return resString; }; export const removeBlockers = function (ical: iCalFile): iCalFile { - let remainingEvents: iCalEvent[] = []; + let remainingEvents: iCalEvent[] = []; - ical.body.forEach((event) => { - if ( - !event.content.includes('SUMMARY:Beginn Theorie') - && !event.content.includes('SUMMARY:Präsenz') - && event.duration < 10 - && event.duration > 0.25 - ) { - remainingEvents.push(event); - } - }); + ical.body.forEach((event) => { + if ( + !event.content.includes('SUMMARY:Beginn Theorie') + && !event.content.includes('SUMMARY:Präsenz') + && event.duration < 10 + && event.duration > 0.25 + ) { + remainingEvents.push(event); + } + }); - ical.body = remainingEvents; + ical.body = remainingEvents; - return ical; + return ical; }; export const removeElective = function (ical: iCalFile, chosenElective: string): iCalFile { - let remainingEvents: iCalEvent[] = []; + let remainingEvents: iCalEvent[] = []; - let electiveToRemove = [ - {name: 'ERP-Systeme'}, - {name: 'Ethik für Informatiker'}, - {name: 'Evolutionäre Algorithmen'}, - {name: 'Forensik'}, - {name: 'Kryptographische Verfahren'}, - {name: 'Robotik'}, - {name: 'Web-Services'}, - {name: 'High Performance Computing'}, - {name: 'Digitale Audiosignalverarbeitung'}, - {name: 'Psychologische Grundlagen für Informatiker'}, - {name: 'Erklärbare Künstliche Intelligenz'}, - {name: 'Innovation Management'} - ]; - electiveToRemove.splice(parseInt(chosenElective), 1); + let electiveToRemove = [ + {name: 'ERP-Systeme'}, + {name: 'Ethik für Informatiker'}, + {name: 'Evolutionäre Algorithmen'}, + {name: 'Forensik'}, + {name: 'Kryptographische Verfahren'}, + {name: 'Robotik'}, + {name: 'Web-Services'}, + {name: 'High Performance Computing'}, + {name: 'Digitale Audiosignalverarbeitung'}, + {name: 'Psychologische Grundlagen für Informatiker'}, + {name: 'Erklärbare Künstliche Intelligenz'}, + {name: 'Innovation Management'} + ]; + electiveToRemove.splice(parseInt(chosenElective), 1); - ical.body.forEach((event) => { - let addEvent = true; - electiveToRemove.forEach((module) => { - if (event.content.includes(module.name)) { - addEvent = false; - } - }); + ical.body.forEach((event) => { + let addEvent = true; + electiveToRemove.forEach((module) => { + if (event.content.includes(module.name)) { + addEvent = false; + } + }); - if (addEvent) { - remainingEvents.push(event); - } - }); + if (addEvent) { + remainingEvents.push(event); + } + }); - ical.body = remainingEvents; + ical.body = remainingEvents; - return ical; + return ical; }; export const removeProfile = function (ical: iCalFile, chosenProfile: string): iCalFile { - let remainingEvents: iCalEvent[] = []; + let remainingEvents: iCalEvent[] = []; - let profileToRemove = [ - {names: ['.Grundlagen der KI (KI und BV)', 'Bildverarbeitung (KI und BV)']}, - {names: ['Bildverarbeitung', 'Computergraphik']}, - {names: ['Interaktive Systeme', 'Grundlagen der KI']}, - {names: ['e Business', 'angewandtes Projektmanagement']}, - {names: ['Kommunikations und Netztechnik II']} - ]; - profileToRemove.splice(parseInt(chosenProfile), 1); + let profileToRemove = [ + {names: ['.Grundlagen der KI (KI und BV)', 'Bildverarbeitung (KI und BV)']}, + {names: ['Bildverarbeitung', 'Computergraphik']}, + {names: ['Interaktive Systeme', 'Grundlagen der KI']}, + {names: ['e Business', 'angewandtes Projektmanagement']}, + {names: ['Kommunikations und Netztechnik II']} + ]; + profileToRemove.splice(parseInt(chosenProfile), 1); - ical.body.forEach((event) => { - let addEvent = true; - profileToRemove.forEach((module) => { - module.names.forEach((name) => { - if (event.content.includes(name)) { - addEvent = false; - } - }); - }); + ical.body.forEach((event) => { + let addEvent = true; + profileToRemove.forEach((module) => { + module.names.forEach((name) => { + if (event.content.includes(name)) { + addEvent = false; + } + }); + }); - if (addEvent) { - remainingEvents.push(event); - } - }); + if (addEvent) { + remainingEvents.push(event); + } + }); - ical.body = remainingEvents; + ical.body = remainingEvents; - return ical; + return ical; }; export interface iCalFile { - head: string; - body: iCalEvent[]; + head: string; + body: iCalEvent[]; } export interface iCalEvent { - content: string; - duration: number; // Duration in hours + content: string; + duration: number; // Duration in hours } diff --git a/src/models/twitch-highlight-marker/HighlightMarker.db.ts b/src/models/twitch-highlight-marker/HighlightMarker.db.ts index 6d5f3d1..d977d8e 100644 --- a/src/models/twitch-highlight-marker/HighlightMarker.db.ts +++ b/src/models/twitch-highlight-marker/HighlightMarker.db.ts @@ -5,15 +5,15 @@ const mariadb = require('mariadb'); dotenv.config(); export namespace HighlightMarkerDB { - const pool = mariadb.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.BETTERZON_DATABASE, - connectionLimit: 5 - }); + const pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.BETTERZON_DATABASE, + connectionLimit: 5 + }); - export function getConnection() { - return pool; - } + export const getConnection = async () => { + return pool.getConnection(); + }; } diff --git a/src/models/twitch-highlight-marker/addHighlight/addHighlights.service.ts b/src/models/twitch-highlight-marker/addHighlight/addHighlights.service.ts index b258330..beb3e54 100644 --- a/src/models/twitch-highlight-marker/addHighlight/addHighlights.service.ts +++ b/src/models/twitch-highlight-marker/addHighlight/addHighlights.service.ts @@ -8,21 +8,24 @@ dotenv.config(); * @param req_body The request body */ export const createHighlightEntry = async (req_body: any) => { - let conn = HighlightMarkerDB.getConnection(); - try { - const streamers = await conn.query('SELECT streamer_id FROM streamers WHERE username = ?', req_body.streamer); - let streamer_id: number = -1; + let conn = await HighlightMarkerDB.getConnection(); + try { + const streamers = await conn.query('SELECT streamer_id FROM streamers WHERE username = ?', req_body.streamer); + let streamer_id: number = -1; - for (let row in streamers) { - if (row !== 'meta') { - streamer_id = streamers[row].streamer_id; - } - } + for (let row in streamers) { + if (row !== 'meta') { + streamer_id = streamers[row].streamer_id; + } + } - const params = [streamer_id, req_body.stream_id, req_body.description, req_body.timestamp, req_body.username, req_body.stream_game]; + const params = [streamer_id, req_body.stream_id, req_body.description, req_body.timestamp, req_body.username, req_body.stream_game]; - const rows = await conn.query('INSERT INTO highlights (streamer_id, stream_id, description, stream_timestamp, issuing_user, game) VALUES (?, ?, ?, ?, ?, ?)', params); - } catch (err) { - throw err; - } + const rows = await conn.query('INSERT INTO highlights (streamer_id, stream_id, description, stream_timestamp, issuing_user, game) VALUES (?, ?, ?, ?, ?, ?)', params); + } catch (err) { + throw err; + } finally { + // Return connection + await conn.end(); + } };