mirror of
				https://github.com/Mueller-Patrick/Betterzon.git
				synced 2025-11-04 02:25:48 +00:00 
			
		
		
		
	Merge branch 'develop' into BETTERZON-78
This commit is contained in:
		
						commit
						493a8faf42
					
				| 
						 | 
				
			
			@ -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');
 | 
			
		||||
        const rows = await conn.query('SELECT price_id, product_id, vendor_id, price_in_cents, timestamp FROM prices WHERE active_listing = 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 = ?', id);
 | 
			
		||||
        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);
 | 
			
		||||
        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 = ?', product);
 | 
			
		||||
        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);
 | 
			
		||||
        for (let row in rows) {
 | 
			
		||||
            if (row !== 'meta') {
 | 
			
		||||
                priceRows.push(rows[row]);
 | 
			
		||||
| 
						 | 
				
			
			@ -142,16 +142,16 @@ 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) ' +
 | 
			
		||||
                'WHERE product_id = ? AND vendor_id != 1 AND active_listing = 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 GROUP BY DAY(timestamp) ORDER BY timestamp', product);
 | 
			
		||||
            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);
 | 
			
		||||
        } 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', 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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let row in rows) {
 | 
			
		||||
| 
						 | 
				
			
			@ -188,13 +188,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 = ? ORDER BY timestamp DESC LIMIT 1', [product, 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]);
 | 
			
		||||
        } 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 = ? LIMIT 1', [product, vendor]);
 | 
			
		||||
            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]);
 | 
			
		||||
        } 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 = ?', [product, 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]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let row in rows) {
 | 
			
		||||
| 
						 | 
				
			
			@ -237,7 +237,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)\n' +
 | 
			
		||||
            '    FROM prices p WHERE active_listing = true)\n' +
 | 
			
		||||
            'SELECT s.*\n' +
 | 
			
		||||
            'FROM summary s\n' +
 | 
			
		||||
            'WHERE s.rk = 1');
 | 
			
		||||
| 
						 | 
				
			
			@ -298,7 +298,6 @@ export const getBestDeals = async (amount: number): Promise<Prices> => {
 | 
			
		|||
        let maxAmt = Math.min(amount, deals.length);
 | 
			
		||||
 | 
			
		||||
        for (let dealIndex = 0; dealIndex < maxAmt; dealIndex++) {
 | 
			
		||||
            //console.log(deals[dealIndex]);
 | 
			
		||||
            priceRows.push(deals[dealIndex] as Price);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -338,7 +337,7 @@ export const findListByProducts = async (productIds: [number]): Promise<Prices>
 | 
			
		|||
            '               ORDER BY p.timestamp DESC) AS rk\n' +
 | 
			
		||||
            '    FROM prices p' +
 | 
			
		||||
            '    WHERE p.product_id IN (?)' +
 | 
			
		||||
            '    AND p.vendor_id != 1)\n' +
 | 
			
		||||
            '    AND p.vendor_id != 1 AND active_listing = true)\n' +
 | 
			
		||||
            'SELECT s.*\n' +
 | 
			
		||||
            'FROM summary s\n' +
 | 
			
		||||
            'WHERE s.rk = 1', [productIds]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										47
									
								
								Backend/src/models/vendors/vendors.router.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								Backend/src/models/vendors/vendors.router.ts
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -6,6 +6,7 @@ import express, {Request, Response} from 'express';
 | 
			
		|||
import * as VendorService from './vendors.service';
 | 
			
		||||
import {Vendor} from './vendor.interface';
 | 
			
		||||
import {Vendors} from './vendors.interface';
 | 
			
		||||
import * as UserService from '../users/users.service';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +20,7 @@ export const vendorsRouter = express.Router();
 | 
			
		|||
 * Controller Definitions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// GET items/
 | 
			
		||||
// GET vendors/
 | 
			
		||||
vendorsRouter.get('/', async (req: Request, res: Response) => {
 | 
			
		||||
    try {
 | 
			
		||||
        const vendors: Vendors = await VendorService.findAll();
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +32,23 @@ vendorsRouter.get('/', async (req: Request, res: Response) => {
 | 
			
		|||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// GET items/:id
 | 
			
		||||
// GET vendors/managed
 | 
			
		||||
vendorsRouter.get('/managed', 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 vendors = await VendorService.getManagedShops(user.user_id);
 | 
			
		||||
 | 
			
		||||
        res.status(200).send(vendors);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        console.log('Error handling a request: ' + e.message);
 | 
			
		||||
        res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// GET vendors/:id
 | 
			
		||||
vendorsRouter.get('/:id', async (req: Request, res: Response) => {
 | 
			
		||||
    const id: number = parseInt(req.params.id, 10);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +67,7 @@ vendorsRouter.get('/:id', async (req: Request, res: Response) => {
 | 
			
		|||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// GET items/:name
 | 
			
		||||
// GET vendors/search/:term
 | 
			
		||||
vendorsRouter.get('/search/:term', async (req: Request, res: Response) => {
 | 
			
		||||
    const term: string = req.params.term;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,3 +85,27 @@ vendorsRouter.get('/search/:term', async (req: Request, res: Response) => {
 | 
			
		|||
        res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// PUT /manage/deactivatelisting
 | 
			
		||||
vendorsRouter.put('/manage/deactivatelisting', 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 success = await VendorService.deactivateListing(user.user_id, vendor_id, product_id);
 | 
			
		||||
 | 
			
		||||
        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.'}));
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										62
									
								
								Backend/src/models/vendors/vendors.service.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								Backend/src/models/vendors/vendors.service.ts
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -17,6 +17,7 @@ const pool = mariadb.createPool({
 | 
			
		|||
 | 
			
		||||
import {Vendor} from './vendor.interface';
 | 
			
		||||
import {Vendors} from './vendors.interface';
 | 
			
		||||
import {User} from '../users/user.interface';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -123,3 +124,64 @@ export const findBySearchTerm = async (term: string): Promise<Vendors> => {
 | 
			
		|||
 | 
			
		||||
    return vendorRows;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get all vendors that have the given user as admin
 | 
			
		||||
 * @param user The user to return the managed shops for
 | 
			
		||||
 */
 | 
			
		||||
export const getManagedShops = async (user_id: number): Promise<Vendors> => {
 | 
			
		||||
    let conn;
 | 
			
		||||
    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 WHERE admin_id LIKE ?', user_id);
 | 
			
		||||
        for (let row in rows) {
 | 
			
		||||
            if (row !== 'meta') {
 | 
			
		||||
                vendorRows.push(rows[row]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        throw err;
 | 
			
		||||
    } finally {
 | 
			
		||||
        if (conn) {
 | 
			
		||||
            conn.end();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return vendorRows;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Deactivates a product listing for a specific vendor
 | 
			
		||||
 * @param user_id The user id of the issuing user
 | 
			
		||||
 * @param vendor_id The vendor id of the vendor to deactivate the listing for
 | 
			
		||||
 * @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<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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        throw err;
 | 
			
		||||
    } finally {
 | 
			
		||||
        if (conn) {
 | 
			
		||||
            conn.end();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user