mirror of
https://github.com/Mueller-Patrick/Betterzon.git
synced 2024-12-22 19:55:12 +00:00
Merge remote-tracking branch 'origin/develop' into BETTERZON-140
This commit is contained in:
commit
62795fd3f8
|
@ -89,9 +89,9 @@ contactpersonsRouter.post('/', async (req: Request, res: Response) => {
|
|||
const success = await ContactPersonService.createContactEntry(user.user_id, vendor_id, first_name, last_name, gender, email, phone);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(201);
|
||||
res.status(201).send({});
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
res.status(500).send({});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
|
@ -118,9 +118,9 @@ contactpersonsRouter.put('/:id', async (req: Request, res: Response) => {
|
|||
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);
|
||||
res.status(200).send({});
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
res.status(500).send({});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
|
|
|
@ -28,7 +28,7 @@ crawlingstatusRouter.get('/', async (req: Request, res: Response) => {
|
|||
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip);
|
||||
|
||||
if (!user.is_admin) {
|
||||
res.sendStatus(403);
|
||||
res.status(403).send({});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -117,9 +117,9 @@ pricesRouter.post('/', async (req: Request, res: Response) => {
|
|||
const success = await PriceService.createPriceEntry(user.user_id, vendor_id, product_id, price_in_cents);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(201);
|
||||
res.status(201).send({});
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
res.status(500).send({});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
|
|
|
@ -120,7 +120,7 @@ productsRouter.post('/', async (req: Request, res: Response) => {
|
|||
const result: boolean = await ProductService.addNewProduct(asin);
|
||||
|
||||
if (result) {
|
||||
res.sendStatus(201);
|
||||
res.status(201).send({});
|
||||
} else {
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ usersRouter.post('/register', async (req: Request, res: Response) => {
|
|||
res.cookie('betterauth', JSON.stringify({
|
||||
id: session.session_id,
|
||||
key: session.session_key
|
||||
}), {expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30)}).sendStatus(201);
|
||||
}), {expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30)}).status(201).send({});
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
|
@ -83,7 +83,7 @@ usersRouter.post('/login', async (req: Request, res: Response) => {
|
|||
res.cookie('betterauth', JSON.stringify({
|
||||
id: session.session_id,
|
||||
key: session.session_key
|
||||
}), {expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30)}).sendStatus(200);
|
||||
}), {expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30)}).status(200).send({});
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
|
||||
|
|
12
Backend/src/models/vendors/vendors.router.ts
vendored
12
Backend/src/models/vendors/vendors.router.ts
vendored
|
@ -100,9 +100,9 @@ vendorsRouter.put('/manage/deactivatelisting', async (req: Request, res: Respons
|
|||
const success = await VendorService.deactivateListing(user.user_id, vendor_id, product_id);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
res.status(200).send({});
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
res.status(500).send({});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
|
@ -123,9 +123,9 @@ vendorsRouter.put('/manage/shop/deactivate/:id', async (req: Request, res: Respo
|
|||
const success = await VendorService.setShopStatus(user.user_id, vendor_id, false);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
res.status(200).send({});
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
res.status(500).send({});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
|
@ -146,9 +146,9 @@ vendorsRouter.put('/manage/shop/activate/:id', async (req: Request, res: Respons
|
|||
const success = await VendorService.setShopStatus(user.user_id, vendor_id, true);
|
||||
|
||||
if (success) {
|
||||
res.sendStatus(200);
|
||||
res.status(200).send({});
|
||||
} else {
|
||||
res.sendStatus(500);
|
||||
res.status(500).send({});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error handling a request: ' + e.message);
|
||||
|
|
|
@ -92,7 +92,8 @@
|
|||
"karmaConfig": "karma.conf.js",
|
||||
"codeCoverage": true,
|
||||
"codeCoverageExclude": [
|
||||
"src/app/mocks/mock.service.ts"
|
||||
"src/app/mocks/mock.service.ts",
|
||||
"src/app/services/api.service.ts"
|
||||
],
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
|
|
|
@ -47,7 +47,9 @@ export class ProductDetailsComponent implements OnInit {
|
|||
}
|
||||
|
||||
getProduct(): void {
|
||||
this.apiService.getProduct(this.productId).subscribe(product => {this.product = product});
|
||||
this.apiService.getProduct(this.productId).subscribe(product => {
|
||||
this.product = product;
|
||||
});
|
||||
}
|
||||
|
||||
getPrices(): void {
|
||||
|
|
|
@ -5,3 +5,24 @@ export interface Price {
|
|||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import {Injectable} from '@angular/core';
|
|||
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
|
||||
import process from 'process';
|
||||
import {Product} from '../models/product';
|
||||
import {Price} from '../models/price';
|
||||
import {Deal, Price} from '../models/price';
|
||||
import {Observable, of} from 'rxjs';
|
||||
import {Vendor} from '../models/vendor';
|
||||
import {PriceAlarm} from '../models/pricealarm';
|
||||
|
@ -71,6 +71,60 @@ export class ApiService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all specified products
|
||||
* @param ids The ids of the products to get
|
||||
* @return Observable<Product[]> An observable list of products
|
||||
*/
|
||||
getProductsByIds(ids: number[]): Observable<Product[]> {
|
||||
try {
|
||||
return this.http.get<Product[]>((this.apiUrl + '/products/list/[' + ids.toString() + ']'));
|
||||
} catch (exception) {
|
||||
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all products that are available at the specified vendor
|
||||
* @param vendor The vendor to get the products for
|
||||
* @return Observable<Product[]> An observable list of products
|
||||
*/
|
||||
getProductsByVendor(vendor: number): Observable<Product[]> {
|
||||
try {
|
||||
return this.http.get<Product[]>((this.apiUrl + '/products/vendor/' + vendor));
|
||||
} catch (exception) {
|
||||
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new product entry
|
||||
* @param asinOrLink The amazon link or asin of the product
|
||||
* @return Observable<any> The observable response of the api
|
||||
*/
|
||||
addNewProduct(asinOrLink: string): Observable<any> {
|
||||
let asin = '';
|
||||
|
||||
// Check if the parameter is a link or an asin
|
||||
const linkRegex: RegExp = /^http[s]{0,1}:\/\/.*\/dp\/(.[^\/]*)\/{0,1}.*$/;
|
||||
const matches = linkRegex.exec(asinOrLink);
|
||||
if (matches) {
|
||||
// param is a link, extract asin
|
||||
asin = matches[1] ?? '';
|
||||
} else {
|
||||
// param is not a link, suspect it is an asin
|
||||
asin = asinOrLink;
|
||||
}
|
||||
|
||||
try {
|
||||
return this.http.post((this.apiUrl + '/products'), JSON.stringify({
|
||||
asin
|
||||
}));
|
||||
} catch (exception) {
|
||||
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ____ _
|
||||
/ __ \_____(_)_______ _____
|
||||
|
@ -79,6 +133,19 @@ export class ApiService {
|
|||
/_/ /_/ /_/\___/\___/____/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the specified price from the API
|
||||
* @param id The id of the price to get
|
||||
* @return Observable<Price> An observable containing a single price
|
||||
*/
|
||||
getPrice(id: number): Observable<Price> {
|
||||
try {
|
||||
return this.http.get<Price>((this.apiUrl + '/prices/' + id));
|
||||
} catch (exception) {
|
||||
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all prices
|
||||
* @return Observable<Price[]> An observable list of prices
|
||||
|
@ -140,6 +207,51 @@ export class ApiService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently best deals
|
||||
* @param amount The amount of deals to get
|
||||
* @return Observable<Deal[]> An observable list of deals
|
||||
*/
|
||||
getBestDeals(amount: number): Observable<Deal[]> {
|
||||
try {
|
||||
return this.http.get<Deal[]>((this.apiUrl + '/prices/bestDeals/' + amount));
|
||||
} catch (exception) {
|
||||
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all prices for the specified product
|
||||
* @param product The product to get prices for
|
||||
* @return Observable<Price[]> An observable list of prices
|
||||
*/
|
||||
getPricesByProduct(products: number[]): Observable<Price[]> {
|
||||
try {
|
||||
console.log('IDs: ' + products.toString());
|
||||
return this.http.get<Price[]>((this.apiUrl + '/prices/byProduct/list/[' + products.toString() + ']'));
|
||||
} catch (exception) {
|
||||
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new price entry
|
||||
* @param vendorId The vendor to add the price for
|
||||
* @param productId The product to add the price to
|
||||
* @param price The price in cents to add
|
||||
* @return Observable<any> The observable response of the api
|
||||
*/
|
||||
addNewPrice(vendorId: number, productId: number, price: number): Observable<any> {
|
||||
try {
|
||||
return this.http.post((this.apiUrl + '/prices'), JSON.stringify({
|
||||
vendor_id: vendorId,
|
||||
product_id: productId,
|
||||
price_in_cents: price
|
||||
}));
|
||||
} catch (exception) {
|
||||
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
/* _ __ __
|
||||
| | / /__ ____ ____/ /___ __________
|
||||
|
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Patrick Müller, Georg Reichert, Henning Sextro
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
185
doku/betterzon_sql_script.txt
Normal file
185
doku/betterzon_sql_script.txt
Normal file
|
@ -0,0 +1,185 @@
|
|||
CREATE DATABASE `Betterzon`;
|
||||
|
||||
USE `Betterzon`;
|
||||
|
||||
create table categories
|
||||
(
|
||||
category_id int auto_increment
|
||||
primary key,
|
||||
name text null
|
||||
);
|
||||
|
||||
create table crawling_processes
|
||||
(
|
||||
process_id int auto_increment
|
||||
primary key,
|
||||
started_timestamp datetime default current_timestamp() null,
|
||||
combinations_to_crawl int null
|
||||
);
|
||||
|
||||
create table manufacturers
|
||||
(
|
||||
manufacturer_id int auto_increment
|
||||
primary key,
|
||||
name text null
|
||||
);
|
||||
|
||||
create table products
|
||||
(
|
||||
product_id int auto_increment
|
||||
primary key,
|
||||
asin text null,
|
||||
is_active tinyint null,
|
||||
name text null,
|
||||
short_description text null,
|
||||
long_description text null,
|
||||
image_guid text null,
|
||||
date_added date null,
|
||||
last_modified datetime null,
|
||||
manufacturer_id int null,
|
||||
selling_rank text null,
|
||||
category_id int null,
|
||||
constraint FK_products_categories
|
||||
foreign key (category_id) references categories (category_id),
|
||||
constraint FK_products_manufacturers
|
||||
foreign key (manufacturer_id) references manufacturers (manufacturer_id)
|
||||
);
|
||||
|
||||
create table users
|
||||
(
|
||||
user_id int auto_increment
|
||||
primary key,
|
||||
username text not null,
|
||||
email text null,
|
||||
bcrypt_password_hash text null,
|
||||
registration_date datetime default current_timestamp() null,
|
||||
last_login_date datetime default current_timestamp() null,
|
||||
is_admin tinyint(1) default 0 null,
|
||||
constraint users_username_uindex
|
||||
unique (username) using hash
|
||||
);
|
||||
|
||||
create table price_alarms
|
||||
(
|
||||
alarm_id int auto_increment
|
||||
primary key,
|
||||
user_id int not null,
|
||||
product_id int not null,
|
||||
defined_price int null,
|
||||
constraint price_alarms_products_product_id_fk
|
||||
foreign key (product_id) references products (product_id)
|
||||
on update cascade on delete cascade,
|
||||
constraint price_alarms_users_user_id_fk
|
||||
foreign key (user_id) references users (user_id)
|
||||
on update cascade on delete cascade
|
||||
);
|
||||
|
||||
create table sessions
|
||||
(
|
||||
session_id int auto_increment
|
||||
primary key,
|
||||
user_id int not null,
|
||||
session_key_hash text null,
|
||||
createdDate datetime default current_timestamp() null,
|
||||
lastLogin datetime null,
|
||||
validUntil datetime null,
|
||||
validDays int null,
|
||||
last_IP text null,
|
||||
constraint sessions_users_user_id_fk
|
||||
foreign key (user_id) references users (user_id)
|
||||
on update cascade on delete cascade
|
||||
);
|
||||
|
||||
create table vendors
|
||||
(
|
||||
vendor_id int auto_increment
|
||||
primary key,
|
||||
admin_id int null,
|
||||
name text null,
|
||||
streetname text null,
|
||||
zip_code int null,
|
||||
city text null,
|
||||
country_code text null,
|
||||
phone text null,
|
||||
website text null,
|
||||
isActive tinyint(1) default 1 not null,
|
||||
constraint vendors_users_user_id_fk
|
||||
foreign key (admin_id) references users (user_id)
|
||||
on update set null on delete set null
|
||||
);
|
||||
|
||||
create table contact_persons
|
||||
(
|
||||
contact_person_id int auto_increment
|
||||
primary key,
|
||||
first_name text default '0' not null,
|
||||
last_name text default '0' not null,
|
||||
gender text default '0' not null,
|
||||
email text default '0' not null,
|
||||
phone text default '0' not null,
|
||||
vendor_id int default 0 not null,
|
||||
constraint FK_contact_persons_vendors
|
||||
foreign key (vendor_id) references vendors (vendor_id)
|
||||
);
|
||||
|
||||
create table crawling_status
|
||||
(
|
||||
status_id int auto_increment
|
||||
primary key,
|
||||
process_id int not null,
|
||||
instance_url text null,
|
||||
product_id int not null,
|
||||
vendor_id int not null,
|
||||
success tinyint(1) not null,
|
||||
constraint crawling_status_crawling_processes_process_id_fk
|
||||
foreign key (process_id) references crawling_processes (process_id)
|
||||
on update cascade on delete cascade,
|
||||
constraint crawling_status_products_product_id_fk
|
||||
foreign key (product_id) references products (product_id)
|
||||
on update cascade on delete cascade,
|
||||
constraint crawling_status_vendors_vendor_id_fk
|
||||
foreign key (vendor_id) references vendors (vendor_id)
|
||||
on update cascade on delete cascade
|
||||
);
|
||||
|
||||
create table favorite_shops
|
||||
(
|
||||
favorite_id int auto_increment
|
||||
primary key,
|
||||
vendor_id int not null,
|
||||
user_id int not null,
|
||||
constraint favorite_shops_users_user_id_fk
|
||||
foreign key (user_id) references users (user_id)
|
||||
on update cascade on delete cascade,
|
||||
constraint favorite_shops_vendors_vendor_id_fk
|
||||
foreign key (vendor_id) references vendors (vendor_id)
|
||||
on update cascade on delete cascade
|
||||
);
|
||||
|
||||
create table prices
|
||||
(
|
||||
price_id int auto_increment
|
||||
primary key,
|
||||
product_id int default 0 null,
|
||||
vendor_id int null,
|
||||
price_in_cents int null,
|
||||
timestamp datetime default current_timestamp() null,
|
||||
active_listing tinyint(1) default 1 not null,
|
||||
constraint FK_prices_products
|
||||
foreign key (product_id) references products (product_id),
|
||||
constraint FK_prices_vendors
|
||||
foreign key (vendor_id) references vendors (vendor_id)
|
||||
);
|
||||
|
||||
create table product_links
|
||||
(
|
||||
product_link_id int auto_increment
|
||||
primary key,
|
||||
product_id int default 0 not null,
|
||||
vendor_id int default 0 not null,
|
||||
url text default '0' not null,
|
||||
constraint FK__products
|
||||
foreign key (product_id) references products (product_id),
|
||||
constraint FK__vendors
|
||||
foreign key (vendor_id) references vendors (vendor_id)
|
||||
);
|
Loading…
Reference in New Issue
Block a user