mirror of
https://github.com/Mueller-Patrick/Betterzon.git
synced 2026-09-16 18:03:45 +00:00
Merge branch 'develop' into BETTERZON-107
This commit is contained in:
@@ -15,6 +15,7 @@ import {errorHandler} from './middleware/error.middleware';
|
||||
import {notFoundHandler} from './middleware/notFound.middleware';
|
||||
import {usersRouter} from './models/users/users.router';
|
||||
import {pricealarmsRouter} from './models/pricealarms/pricealarms.router';
|
||||
import {contactpersonsRouter} from './models/contact_persons/contact_persons.router';
|
||||
|
||||
const cookieParser = require('cookie-parser');
|
||||
|
||||
@@ -49,6 +50,7 @@ app.use('/prices', pricesRouter);
|
||||
app.use('/users', usersRouter);
|
||||
app.use('/vendors', vendorsRouter);
|
||||
app.use('/pricealarms', pricealarmsRouter);
|
||||
app.use('/contactpersons', contactpersonsRouter);
|
||||
|
||||
app.use(errorHandler);
|
||||
app.use(notFoundHandler);
|
||||
|
||||
@@ -0,0 +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;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import {Contact_Person} from './contact_person.interface';
|
||||
|
||||
export interface Contact_Persons {
|
||||
[key: number]: Contact_Person;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Required External Modules and Interfaces
|
||||
*/
|
||||
|
||||
import express, {Request, Response} from 'express';
|
||||
import * as ContactPersonService from './contact_persons.service';
|
||||
import {Contact_Person} from './contact_person.interface';
|
||||
import {Contact_Persons} from './contact_persons.interface';
|
||||
import * as UserService from '../users/users.service';
|
||||
import * as PriceService from '../prices/prices.service';
|
||||
|
||||
|
||||
/**
|
||||
* Router Definition
|
||||
*/
|
||||
|
||||
export const contactpersonsRouter = express.Router();
|
||||
|
||||
|
||||
/**
|
||||
* Controller Definitions
|
||||
*/
|
||||
|
||||
// GET contactpersons/
|
||||
contactpersonsRouter.get('/', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const contacts: Contact_Persons = await ContactPersonService.findAll();
|
||||
|
||||
res.status(200).send(contacts);
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
// GET contactpersons/:id
|
||||
contactpersonsRouter.get('/:id', async (req: Request, res: Response) => {
|
||||
const id: number = parseInt(req.params.id, 10);
|
||||
|
||||
if (!id) {
|
||||
res.status(400).send('Missing parameters.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const contact: Contact_Person = await ContactPersonService.find(id);
|
||||
|
||||
res.status(200).send(contact);
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
// GET contactpersons/byvendor/:id
|
||||
contactpersonsRouter.get('/byvendor/:id', async (req: Request, res: Response) => {
|
||||
const id: number = parseInt(req.params.id, 10);
|
||||
|
||||
if (!id) {
|
||||
res.status(400).send('Missing parameters.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const contacts: Contact_Persons = await ContactPersonService.findByVendor(id);
|
||||
|
||||
res.status(200).send(contacts);
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
// POST contactpersons/
|
||||
contactpersonsRouter.post('/', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Authenticate user
|
||||
const user_ip = req.connection.remoteAddress ?? '';
|
||||
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip);
|
||||
|
||||
// Get required parameters
|
||||
const vendor_id = req.body.vendor_id;
|
||||
const first_name = req.body.first_name;
|
||||
const last_name = req.body.last_name;
|
||||
const gender = req.body.gender;
|
||||
const email = req.body.email;
|
||||
const phone = req.body.phone;
|
||||
|
||||
const success = await ContactPersonService.createContactEntry(user.user_id, vendor_id, first_name, last_name, gender, email, phone);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
// PUT contactpersons/:id
|
||||
contactpersonsRouter.put('/:id', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Authenticate user
|
||||
const user_ip = req.connection.remoteAddress ?? '';
|
||||
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip);
|
||||
|
||||
// Get required parameters
|
||||
const contact_person_id = parseInt(req.params.id, 10);
|
||||
const vendor_id = req.body.vendor_id;
|
||||
const first_name = req.body.first_name;
|
||||
const last_name = req.body.last_name;
|
||||
const gender = req.body.gender;
|
||||
const email = req.body.email;
|
||||
const phone = req.body.phone;
|
||||
|
||||
const success = await ContactPersonService.updateContactEntry(user.user_id, contact_person_id, vendor_id, first_name, last_name, gender, email, phone);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,175 @@
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const mariadb = require('mariadb');
|
||||
const pool = mariadb.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE,
|
||||
connectionLimit: 5
|
||||
});
|
||||
|
||||
/**
|
||||
* Data Model Interfaces
|
||||
*/
|
||||
|
||||
import {Contact_Person} from './contact_person.interface';
|
||||
import {Contact_Persons} from './contact_persons.interface';
|
||||
|
||||
|
||||
/**
|
||||
* Service Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetches and returns all known contact persons
|
||||
*/
|
||||
export const findAll = async (): Promise<Contact_Persons> => {
|
||||
let conn;
|
||||
let contRows = [];
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
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;
|
||||
} finally {
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
|
||||
return contRows;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches and returns the contact person with the specified id
|
||||
* @param id The id of the contact person to fetch
|
||||
*/
|
||||
export const find = async (id: number): Promise<Contact_Person> => {
|
||||
let conn;
|
||||
let cont: any;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
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;
|
||||
} finally {
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
|
||||
return cont;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches and returns the contact persons for the specified vendor
|
||||
* @param id The id of the vendor to fetch contact persons for
|
||||
*/
|
||||
export const findByVendor = async (id: number): Promise<Contact_Persons> => {
|
||||
let conn;
|
||||
let contRows = [];
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
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;
|
||||
} finally {
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
|
||||
return contRows;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a contact entry record
|
||||
* @param user_id The user id of the issuing user
|
||||
* @param vendor_id The vendor id of the vendor to create the record for
|
||||
* @param first_name The first name of the contact person
|
||||
* @param last_name The last name of the contact person
|
||||
* @param gender The gender of the contact person
|
||||
* @param email The email of the contact person
|
||||
* @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<Boolean> => {
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
|
||||
// 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]);
|
||||
|
||||
// If there are more / less than 1 affected rows, return false
|
||||
return res.affectedRows === 1;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
} finally {
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates a contact entry record
|
||||
* @param user_id The user id of the issuing user
|
||||
* @param contact_person_id The id of the record to update
|
||||
* @param vendor_id The vendor id of the vendor to create the record for
|
||||
* @param first_name The first name of the contact person
|
||||
* @param last_name The last name of the contact person
|
||||
* @param gender The gender of the contact person
|
||||
* @param email The email of the contact person
|
||||
* @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<Boolean> => {
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
|
||||
// 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]);
|
||||
|
||||
// If there are more / less than 1 affected rows, return false
|
||||
return res.affectedRows === 1;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
} finally {
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -19,7 +19,7 @@ export const manufacturersRouter = express.Router();
|
||||
* Controller Definitions
|
||||
*/
|
||||
|
||||
// GET items/
|
||||
// GET manufacturers/
|
||||
manufacturersRouter.get('/', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const manufacturers: Manufacturers = await ManufacturerService.findAll();
|
||||
@@ -31,7 +31,7 @@ manufacturersRouter.get('/', async (req: Request, res: Response) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET items/:id
|
||||
// GET manufacturers/:id
|
||||
manufacturersRouter.get('/:id', async (req: Request, res: Response) => {
|
||||
const id: number = parseInt(req.params.id, 10);
|
||||
|
||||
@@ -50,7 +50,7 @@ manufacturersRouter.get('/:id', async (req: Request, res: Response) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET items/:term
|
||||
// GET manufacturers/:term
|
||||
manufacturersRouter.get('/search/:term', async (req: Request, res: Response) => {
|
||||
const term: string = req.params.term;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ pricealarmsRouter.get('/', async (req: Request, res: Response) => {
|
||||
});
|
||||
|
||||
// POST pricealarms/create
|
||||
pricealarmsRouter.post('/create', async (req: Request, res: Response) => {
|
||||
pricealarmsRouter.post('/', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Authenticate user
|
||||
const user_ip = req.connection.remoteAddress ?? '';
|
||||
@@ -69,7 +69,7 @@ pricealarmsRouter.post('/create', async (req: Request, res: Response) => {
|
||||
});
|
||||
|
||||
// PUT pricealarms/update
|
||||
pricealarmsRouter.put('/update', async (req: Request, res: Response) => {
|
||||
pricealarmsRouter.put('/', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Authenticate user
|
||||
const user_ip = req.connection.remoteAddress ?? '';
|
||||
|
||||
@@ -6,6 +6,7 @@ import express, {Request, Response} from 'express';
|
||||
import * as PriceService from './prices.service';
|
||||
import {Price} from './price.interface';
|
||||
import {Prices} from './prices.interface';
|
||||
import * as UserService from '../users/users.service';
|
||||
|
||||
|
||||
/**
|
||||
@@ -100,3 +101,28 @@ pricesRouter.get('/byProduct/list/:ids', async (req: Request, res: Response) =>
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
// POST prices/
|
||||
pricesRouter.post('/', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Authenticate user
|
||||
const user_ip = req.connection.remoteAddress ?? '';
|
||||
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip);
|
||||
|
||||
// Get required parameters
|
||||
const vendor_id = req.body.vendor_id;
|
||||
const product_id = req.body.product_id;
|
||||
const price_in_cents = req.body.price_in_cents;
|
||||
|
||||
const success = await PriceService.createPriceEntry(user.user_id, vendor_id, product_id, price_in_cents);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ export const findAll = async (): Promise<Prices> => {
|
||||
let priceRows = [];
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
const rows = await conn.query('SELECT price_id, product_id, vendor_id, price_in_cents, timestamp FROM prices WHERE active_listing = true');
|
||||
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 = {
|
||||
@@ -72,7 +72,7 @@ export const find = async (id: number): Promise<Price> => {
|
||||
let price: any;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
const rows = await conn.query('SELECT price_id, product_id, vendor_id, price_in_cents, timestamp FROM prices WHERE price_id = ? AND active_listing = true', id);
|
||||
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];
|
||||
@@ -99,7 +99,7 @@ export const findByProduct = async (product: number): Promise<Prices> => {
|
||||
let priceRows = [];
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
const rows = await conn.query('SELECT price_id, product_id, vendor_id, price_in_cents, timestamp FROM prices WHERE product_id = ? AND active_listing = true', product);
|
||||
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]);
|
||||
@@ -142,16 +142,17 @@ export const findByType = async (product: string, type: string): Promise<Prices>
|
||||
'PARTITION BY p.vendor_id ' +
|
||||
'ORDER BY p.timestamp DESC) AS rk ' +
|
||||
'FROM prices p ' +
|
||||
'WHERE product_id = ? AND vendor_id != 1 AND active_listing = true) ' +
|
||||
'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, vendor_id, MIN(price_in_cents) as price_in_cents, timestamp FROM prices WHERE product_id = ? AND vendor_id != 1 AND active_listing = true GROUP BY DAY(timestamp) ORDER BY timestamp', product);
|
||||
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, vendor_id, price_in_cents, timestamp FROM prices WHERE product_id = ? AND vendor_id != 1 AND active_listing = true', 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) {
|
||||
@@ -188,13 +189,13 @@ export const findByVendor = async (product: string, vendor: string, type: string
|
||||
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, vendor_id, price_in_cents, timestamp FROM prices WHERE product_id = ? AND vendor_id = ? AND active_listing = true ORDER BY timestamp DESC LIMIT 1', [product, 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, vendor_id, MIN(price_in_cents) as price_in_cents, timestamp FROM prices WHERE product_id = ? AND vendor_id = ? AND active_listing = true LIMIT 1', [product, vendor]);
|
||||
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, vendor_id, price_in_cents, timestamp FROM prices WHERE product_id = ? AND vendor_id = ? AND active_listing = true', [product, 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) {
|
||||
@@ -237,7 +238,7 @@ export const getBestDeals = async (amount: number): Promise<Prices> => {
|
||||
' ROW_NUMBER() OVER(\n' +
|
||||
' PARTITION BY p.product_id, p.vendor_id\n' +
|
||||
' ORDER BY p.timestamp DESC) AS rk\n' +
|
||||
' FROM prices p WHERE active_listing = true)\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');
|
||||
@@ -300,7 +301,6 @@ export const getBestDeals = async (amount: number): Promise<Prices> => {
|
||||
for (let dealIndex = 0; dealIndex < maxAmt; dealIndex++) {
|
||||
priceRows.push(deals[dealIndex] as Price);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
@@ -315,7 +315,7 @@ export const getBestDeals = async (amount: number): Promise<Prices> => {
|
||||
|
||||
/**
|
||||
* Fetches and returns the lowest, latest, non-amazon price for each given product
|
||||
* @param ids the ids of the products
|
||||
* @param productIds the ids of the products
|
||||
*/
|
||||
export const findListByProducts = async (productIds: [number]): Promise<Prices> => {
|
||||
let conn;
|
||||
@@ -335,8 +335,8 @@ export const findListByProducts = async (productIds: [number]): Promise<Prices>
|
||||
' ROW_NUMBER() OVER(\n' +
|
||||
' PARTITION BY p.product_id, p.vendor_id\n' +
|
||||
' ORDER BY p.timestamp DESC) AS rk\n' +
|
||||
' FROM prices p' +
|
||||
' WHERE p.product_id IN (?)' +
|
||||
' 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' +
|
||||
@@ -365,7 +365,6 @@ export const findListByProducts = async (productIds: [number]): Promise<Prices>
|
||||
priceRows.push(pricesForProd[0]);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
throw err;
|
||||
} finally {
|
||||
@@ -376,3 +375,28 @@ export const findListByProducts = async (productIds: [number]): Promise<Prices>
|
||||
|
||||
return priceRows;
|
||||
};
|
||||
|
||||
export const createPriceEntry = async (user_id: number, vendor_id: number, product_id: number, price_in_cents: number): Promise<Boolean> => {
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
|
||||
// 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]);
|
||||
|
||||
// If there are more / less than 1 affected rows, return false
|
||||
return res.affectedRows === 1;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
} finally {
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -87,3 +87,22 @@ productsRouter.get('/list/:ids', async (req: Request, res: Response) => {
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
// GET products/vendor/:id
|
||||
productsRouter.get('/vendor/:id', async (req: Request, res: Response) => {
|
||||
const id: number = parseInt(req.params.id, 10);
|
||||
|
||||
if (!id) {
|
||||
res.status(400).send('Missing parameters.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const products: Products = await ProductService.findByVendor(id);
|
||||
|
||||
res.status(200).send(products);
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -159,3 +159,41 @@ export const findList = async (ids: [number]): Promise<Products> => {
|
||||
|
||||
return prodRows;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches and returns the products that the given vendor has price entries for
|
||||
* @param id The id of the vendor to fetch the products for
|
||||
*/
|
||||
export const findByVendor = async (id: number): Promise<Products> => {
|
||||
let conn;
|
||||
let prodRows = [];
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
throw err;
|
||||
} finally {
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
|
||||
return prodRows;
|
||||
};
|
||||
|
||||
+47
-1
@@ -99,7 +99,53 @@ vendorsRouter.put('/manage/deactivatelisting', async (req: Request, res: Respons
|
||||
|
||||
const success = await VendorService.deactivateListing(user.user_id, vendor_id, product_id);
|
||||
|
||||
if(success) {
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
// PUT /manage/shop/deactivate/:id
|
||||
vendorsRouter.put('/manage/shop/deactivate/:id', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Authenticate user
|
||||
const user_ip = req.connection.remoteAddress ?? '';
|
||||
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip);
|
||||
|
||||
// Get required parameters
|
||||
const vendor_id = parseInt(req.params.id, 10);
|
||||
|
||||
const success = await VendorService.setShopStatus(user.user_id, vendor_id, false);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
});
|
||||
|
||||
// PUT /manage/shop/activate/:id
|
||||
vendorsRouter.put('/manage/shop/activate/:id', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Authenticate user
|
||||
const user_ip = req.connection.remoteAddress ?? '';
|
||||
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip);
|
||||
|
||||
// Get required parameters
|
||||
const vendor_id = parseInt(req.params.id, 10);
|
||||
|
||||
const success = await VendorService.setShopStatus(user.user_id, vendor_id, true);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
|
||||
+36
-7
@@ -32,7 +32,7 @@ export const findAll = async (): Promise<Vendors> => {
|
||||
let vendorRows = [];
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
const rows = await conn.query('SELECT vendor_id, name, streetname, zip_code, city, country_code, phone, website FROM vendors');
|
||||
const rows = await conn.query('SELECT vendor_id, name, streetname, zip_code, city, country_code, phone, website FROM vendors WHERE isActive = true');
|
||||
for (let row in rows) {
|
||||
if (row !== 'meta') {
|
||||
let vendor: Vendor = {
|
||||
@@ -79,7 +79,7 @@ export const find = async (id: number): Promise<Vendor> => {
|
||||
let vendor: any;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
const rows = await conn.query('SELECT vendor_id, name, streetname, zip_code, city, country_code, phone, website FROM vendors WHERE vendor_id = ?', id);
|
||||
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);
|
||||
for (let row in rows) {
|
||||
if (row !== 'meta') {
|
||||
vendor = rows[row];
|
||||
@@ -107,7 +107,7 @@ export const findBySearchTerm = async (term: string): Promise<Vendors> => {
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
term = '%' + term + '%';
|
||||
const rows = await conn.query('SELECT vendor_id, name, streetname, zip_code, city, country_code, phone, website FROM vendors WHERE name LIKE ?', term);
|
||||
const rows = await conn.query('SELECT vendor_id, name, streetname, zip_code, city, country_code, phone, website FROM vendors WHERE name LIKE ? AND isActive = true', term);
|
||||
for (let row in rows) {
|
||||
if (row !== 'meta') {
|
||||
vendorRows.push(rows[row]);
|
||||
@@ -171,10 +171,39 @@ export const deactivateListing = async (user_id: number, vendor_id: number, prod
|
||||
|
||||
const status = await conn.query('UPDATE prices SET active_listing = false WHERE vendor_id = ? and product_id = ?', [vendor_id, product_id]);
|
||||
|
||||
if(status.affectedRows > 0){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return status.affectedRows > 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
} finally {
|
||||
if (conn) {
|
||||
conn.end();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the specified shop to either active or not active
|
||||
* @param user_id The user id of the issuing user
|
||||
* @param vendor_id The vendor id of the shop to update
|
||||
* @param isActive The new active state
|
||||
*/
|
||||
export const setShopStatus = async (user_id: number, vendor_id: number, isActive: boolean): Promise<Boolean> => {
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Update the vendor state
|
||||
const status = await conn.query('UPDATE vendors SET isActive = ? WHERE vendor_id = ?', [isActive, vendor_id]);
|
||||
|
||||
return status.affectedRows > 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user