Compare commits

..

No commits in common. "faecd72cf8824a9477ba67d0b8490c64f378d684" and "63cbac5490ada4c97808bac84a6c28ef7aab5572" have entirely different histories.

13 changed files with 13 additions and 444 deletions

View File

@ -15,7 +15,6 @@ import {errorHandler} from './middleware/error.middleware';
import {notFoundHandler} from './middleware/notFound.middleware'; import {notFoundHandler} from './middleware/notFound.middleware';
import {usersRouter} from './models/users/users.router'; import {usersRouter} from './models/users/users.router';
import {pricealarmsRouter} from './models/pricealarms/pricealarms.router'; import {pricealarmsRouter} from './models/pricealarms/pricealarms.router';
import {contactpersonsRouter} from './models/contact_persons/contact_persons.router';
const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser');
@ -50,7 +49,6 @@ app.use('/prices', pricesRouter);
app.use('/users', usersRouter); app.use('/users', usersRouter);
app.use('/vendors', vendorsRouter); app.use('/vendors', vendorsRouter);
app.use('/pricealarms', pricealarmsRouter); app.use('/pricealarms', pricealarmsRouter);
app.use('/contactpersons', contactpersonsRouter);
app.use(errorHandler); app.use(errorHandler);
app.use(notFoundHandler); app.use(notFoundHandler);

View File

@ -1,9 +0,0 @@
export interface Contact_Person {
contact_person_id: number;
first_name: string;
last_name: string;
gender: string;
email: string;
phone: string;
vendor_id: number;
}

View File

@ -1,5 +0,0 @@
import {Contact_Person} from './contact_person.interface';
export interface Contact_Persons {
[key: number]: Contact_Person;
}

View File

@ -1,129 +0,0 @@
/**
* 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.'}));
}
});

View File

@ -1,175 +0,0 @@
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();
}
}
};

View File

@ -19,7 +19,7 @@ export const manufacturersRouter = express.Router();
* Controller Definitions * Controller Definitions
*/ */
// GET manufacturers/ // GET items/
manufacturersRouter.get('/', async (req: Request, res: Response) => { manufacturersRouter.get('/', async (req: Request, res: Response) => {
try { try {
const manufacturers: Manufacturers = await ManufacturerService.findAll(); const manufacturers: Manufacturers = await ManufacturerService.findAll();
@ -31,7 +31,7 @@ manufacturersRouter.get('/', async (req: Request, res: Response) => {
} }
}); });
// GET manufacturers/:id // GET items/:id
manufacturersRouter.get('/:id', async (req: Request, res: Response) => { manufacturersRouter.get('/:id', async (req: Request, res: Response) => {
const id: number = parseInt(req.params.id, 10); const id: number = parseInt(req.params.id, 10);
@ -50,7 +50,7 @@ manufacturersRouter.get('/:id', async (req: Request, res: Response) => {
} }
}); });
// GET manufacturers/:term // GET items/:term
manufacturersRouter.get('/search/:term', async (req: Request, res: Response) => { manufacturersRouter.get('/search/:term', async (req: Request, res: Response) => {
const term: string = req.params.term; const term: string = req.params.term;

View File

@ -6,7 +6,6 @@ import express, {Request, Response} from 'express';
import * as PriceService from './prices.service'; import * as PriceService from './prices.service';
import {Price} from './price.interface'; import {Price} from './price.interface';
import {Prices} from './prices.interface'; import {Prices} from './prices.interface';
import * as UserService from '../users/users.service';
/** /**
@ -101,28 +100,3 @@ pricesRouter.get('/byProduct/list/:ids', async (req: Request, res: Response) =>
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'})); 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.'}));
}
});

View File

@ -376,29 +376,3 @@ export const findListByProducts = async (productIds: [number]): Promise<Prices>
return priceRows; 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();
}
}
};

View File

@ -87,22 +87,3 @@ productsRouter.get('/list/:ids', async (req: Request, res: Response) => {
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'})); 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.'}));
}
});

View File

@ -159,41 +159,3 @@ export const findList = async (ids: [number]): Promise<Products> => {
return prodRows; 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;
};

View File

@ -99,7 +99,7 @@ vendorsRouter.put('/manage/deactivatelisting', async (req: Request, res: Respons
const success = await VendorService.deactivateListing(user.user_id, vendor_id, product_id); const success = await VendorService.deactivateListing(user.user_id, vendor_id, product_id);
if (success) { if(success) {
res.sendStatus(200); res.sendStatus(200);
} else { } else {
res.sendStatus(500); res.sendStatus(500);

View File

@ -171,7 +171,10 @@ 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]); const status = await conn.query('UPDATE prices SET active_listing = false WHERE vendor_id = ? and product_id = ?', [vendor_id, product_id]);
return status.affectedRows > 0; if(status.affectedRows > 0){
return true;
}
return false;
} catch (err) { } catch (err) {
throw err; throw err;
} finally { } finally {

View File

@ -3,8 +3,8 @@ import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
HEADERS = ({'User-Agent': HEADERS = ({'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 ' 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 '
'Safari/537.36'}) 'Safari/537.36'})
def crawl(product_ids: [int]) -> dict: def crawl(product_ids: [int]) -> dict:
@ -62,21 +62,16 @@ def crawl(product_ids: [int]) -> dict:
'products_with_problems': products_with_problems 'products_with_problems': products_with_problems
} }
def __crawl_amazon__(product_info: dict) -> tuple: def __crawl_amazon__(product_info: dict) -> tuple:
""" """
Crawls the price for the given product from amazon Crawls the price for the given product from amazon
:param product_info: A dict with product info containing product_id, vendor_id, url :param product_info: A dict with product info containing product_id, vendor_id, url
:return: A tuple with the crawled data, containing (product_id, vendor_id, price_in_cents) :return: A tuple with the crawled data, containing (product_id, vendor_id, price_in_cents)
""" """
page = requests.get(product_info['url'], headers=HEADERS) page = requests.get(product_info['url'], headers= HEADERS)
soup = BeautifulSoup(page.content, features="lxml") soup = BeautifulSoup(page.content, features="lxml")
try: try:
price = int( price = int(soup.find(id='priceblock_ourprice').get_text().replace(".", "").replace(",", "").replace("", "").strip())
soup.find(id='priceblock_ourprice').get_text().replace(".", "").replace(",", "").replace("", "").strip())
if not price:
price = int(soup.find(id='price_inside_buybox').get_text().replace(".", "").replace(",", "").replace("", "").strip())
except RuntimeError: except RuntimeError:
price = -1 price = -1
except AttributeError: except AttributeError:
@ -94,7 +89,7 @@ def __crawl_apple__(product_info: dict) -> tuple:
:param product_info: A dict with product info containing product_id, vendor_id, url :param product_info: A dict with product info containing product_id, vendor_id, url
:return: A tuple with the crawled data, containing (product_id, vendor_id, price_in_cents) :return: A tuple with the crawled data, containing (product_id, vendor_id, price_in_cents)
""" """
# return (product_info['product_id'], product_info['vendor_id'], 123) #return (product_info['product_id'], product_info['vendor_id'], 123)
pass pass