Compare commits

..

2 Commits

9 changed files with 263 additions and 18 deletions

View File

@ -16,6 +16,7 @@ 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'; import {contactpersonsRouter} from './models/contact_persons/contact_persons.router';
import {favoriteshopsRouter} from './models/favorite_shops/favoriteshops.router';
const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser');
@ -51,6 +52,7 @@ 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('/contactpersons', contactpersonsRouter);
app.use('/favoriteshops', favoriteshopsRouter);
app.use(errorHandler); app.use(errorHandler);
app.use(notFoundHandler); app.use(notFoundHandler);

View File

@ -0,0 +1,5 @@
export interface FavoriteShop {
favorite_id: number;
vendor_id: number;
user_id: number;
}

View File

@ -0,0 +1,5 @@
import {FavoriteShop} from './favoriteshop.interface';
export interface FavoriteShops {
[key: number]: FavoriteShop;
}

View File

@ -0,0 +1,100 @@
/**
* Required External Modules and Interfaces
*/
import express, {Request, Response} from 'express';
import * as FavoriteShopsService from './favoriteshops.service';
import {FavoriteShop} from './favoriteshop.interface';
import {FavoriteShops} from './favoriteshops.interface';
import * as UserService from '../users/users.service';
/**
* Router Definition
*/
export const favoriteshopsRouter = express.Router();
/**
* Controller Definitions
*/
//GET favoriteshops/
favoriteshopsRouter.get('/', async (req: Request, res: Response) => {
try {
// Authenticate user
const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip);
const priceAlarms = await FavoriteShopsService.getFavoriteShops(user.user_id);
res.status(200).send(priceAlarms);
} catch (e) {
console.log('Error handling a request: ' + e.message);
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
}
});
// POST favoriteshops/
favoriteshopsRouter.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 info for price alarm creation
const vendor_id = req.body.vendor_id;
if (!vendor_id) {
// Missing
res.status(400).send(JSON.stringify({message: 'Missing parameters'}));
return;
}
// Create price alarm
const success = await FavoriteShopsService.createFavoriteShop(user.user_id, vendor_id);
if (success) {
res.status(201).send(JSON.stringify({success: true}));
return;
} else {
res.status(500).send(JSON.stringify({success: false}));
return;
}
} catch (e) {
console.log('Error handling a request: ' + e.message);
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
}
});
// DELETE favoriteshops/
favoriteshopsRouter.delete('/: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 info for price alarm creation
const favorite_id = parseInt(req.params.id, 10);
if (!favorite_id) {
// Missing
res.status(400).send(JSON.stringify({message: 'Missing parameters'}));
return;
}
// Create price alarm
const success = await FavoriteShopsService.deleteFavoriteShop(user.user_id, favorite_id);
if (success) {
res.status(201).send(JSON.stringify({success: true}));
return;
} else {
res.status(500).send(JSON.stringify({success: false}));
return;
}
} 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

@ -0,0 +1,92 @@
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 {FavoriteShop} from './favoriteshop.interface';
import {FavoriteShops} from './favoriteshops.interface';
/**
* Service Methods
*/
/**
* Creates a favorite shop entry for the given user for the given shop
* @param user_id The id of the user to create the favorite shop entry for
* @param vendor_id The id of the vendor to set as favorite
*/
export const createFavoriteShop = async (user_id: number, vendor_id: number): Promise<boolean> => {
let conn;
try {
conn = await pool.getConnection();
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;
} finally {
if (conn) {
conn.end();
}
}
};
/**
* Fetches and returns all favorite shops for the given user
* @param user_id
*/
export const getFavoriteShops = async (user_id: number): Promise<FavoriteShops> => {
let conn;
let shops = [];
try {
conn = await pool.getConnection();
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;
} finally {
if (conn) {
conn.end();
}
}
};
/**
* Deletes the given favorite shop entry
* @param user_id The id of the user that wants to delete the favorite shop entry
* @param favorite_id The favorite shop to delete
*/
export const deleteFavoriteShop = async (user_id: number, favorite_id: number): Promise<boolean> => {
let conn;
try {
conn = await pool.getConnection();
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;
} finally {
if (conn) {
conn.end();
}
}
};

View File

@ -35,7 +35,7 @@ pricealarmsRouter.get('/', async (req: Request, res: Response) => {
} }
}); });
// POST pricealarms/create // POST pricealarms/
pricealarmsRouter.post('/', async (req: Request, res: Response) => { pricealarmsRouter.post('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
@ -68,7 +68,7 @@ pricealarmsRouter.post('/', async (req: Request, res: Response) => {
} }
}); });
// PUT pricealarms/update // PUT pricealarms/
pricealarmsRouter.put('/', async (req: Request, res: Response) => { pricealarmsRouter.put('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user

View File

@ -29,17 +29,13 @@ import {PriceAlarms} from './pricealarms.interface';
* @param product_id The id of the product to create the price alarm for * @param product_id The id of the product to create the price alarm for
* @param defined_price The defined price for the price alarm * @param defined_price The defined price for the price alarm
*/ */
export const createPriceAlarm = async (user_id: number, product_id: number, defined_price: number): Promise<Boolean> => { export const createPriceAlarm = async (user_id: number, product_id: number, defined_price: number): Promise<boolean> => {
let conn; let conn;
try { try {
conn = await pool.getConnection(); conn = await pool.getConnection();
const res = await conn.query('INSERT INTO price_alarms (user_id, product_id, defined_price) VALUES (?, ?, ?)', [user_id, product_id, defined_price]); const res = await conn.query('INSERT INTO price_alarms (user_id, product_id, defined_price) VALUES (?, ?, ?)', [user_id, product_id, defined_price]);
if (res.affectedRows === 1) { return res.affectedRows === 1;
return true;
} else {
return false;
}
} catch (err) { } catch (err) {
throw err; throw err;
} finally { } finally {
@ -47,8 +43,6 @@ export const createPriceAlarm = async (user_id: number, product_id: number, defi
conn.end(); conn.end();
} }
} }
return false;
}; };
/** /**
@ -83,17 +77,13 @@ export const getPriceAlarms = async (user_id: number): Promise<PriceAlarms> => {
* @param user_id The id of the user that wants to update the price alarm * @param user_id The id of the user that wants to update the price alarm
* @param defined_price The defined price for the price alarm * @param defined_price The defined price for the price alarm
*/ */
export const updatePriceAlarm = async (alarm_id: number, user_id: number, defined_price: number): Promise<Boolean> => { export const updatePriceAlarm = async (alarm_id: number, user_id: number, defined_price: number): Promise<boolean> => {
let conn; let conn;
try { try {
conn = await pool.getConnection(); conn = await pool.getConnection();
const res = await conn.query('UPDATE price_alarms SET defined_price = ? WHERE alarm_id = ? AND user_id = ?', [defined_price, alarm_id, user_id]); const res = await conn.query('UPDATE price_alarms SET defined_price = ? WHERE alarm_id = ? AND user_id = ?', [defined_price, alarm_id, user_id]);
if (res.affectedRows === 1) { return res.affectedRows === 1;
return true;
} else {
return false;
}
} catch (err) { } catch (err) {
throw err; throw err;
} finally { } finally {
@ -101,6 +91,4 @@ export const updatePriceAlarm = async (alarm_id: number, user_id: number, define
conn.end(); conn.end();
} }
} }
return false;
}; };

View File

@ -106,3 +106,26 @@ productsRouter.get('/vendor/:id', 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 products/
productsRouter.post('/', async (req: Request, res: Response) => {
const asin: string = req.body.asin;
if (!asin) {
res.status(400).send('Missing parameters.');
return;
}
try {
const result: boolean = await ProductService.addNewProduct(asin);
if (result) {
res.sendStatus(201);
} else {
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
}
} 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

@ -17,6 +17,7 @@ const pool = mariadb.createPool({
import {Product} from './product.interface'; import {Product} from './product.interface';
import {Products} from './products.interface'; import {Products} from './products.interface';
import * as http from 'http';
/** /**
@ -197,3 +198,32 @@ export const findByVendor = async (id: number): Promise<Products> => {
return prodRows; return prodRows;
}; };
/**
* Makes a callout to a crawler instance to search for the requested product
* @param asin The amazon asin of the product to look for
*/
export const addNewProduct = async (asin: string): Promise<boolean> => {
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);
}
return false;
};