Compare commits

..

18 Commits

Author SHA1 Message Date
bf56d2b509 BETTERZON-146: Changing session handling from cookies to localStorage 2021-06-15 11:32:48 +02:00
ad091954c1 Merge remote-tracking branch 'origin/develop' into BETTERZON-140 2021-06-15 10:39:15 +02:00
b062e14c9a auth with cookies. 2021-06-15 10:38:54 +02:00
Patrick
f1dcaef351
Merge pull request #83 from Mueller-Patrick/BETTERZON-145
BETTERZON-145: Adding better error when trying to get session details…
2021-06-15 10:38:52 +02:00
391a4b5e4b BETTERZON-145: Adding better error when trying to get session details without cookie 2021-06-15 10:37:14 +02:00
cf300cb1b7 Merge remote-tracking branch 'origin/develop' into BETTERZON-140 2021-06-15 10:24:51 +02:00
Patrick
c35097a9a2
Merge pull request #82 from Mueller-Patrick/BETTERZON-144
BETTERZON-144: Adding service method to get session / user info
2021-06-15 10:24:20 +02:00
62795fd3f8 Merge remote-tracking branch 'origin/develop' into BETTERZON-140 2021-06-15 10:24:02 +02:00
Patrick
4a0ba40da6
Merge branch 'develop' into BETTERZON-144 2021-06-15 10:20:17 +02:00
f4d1e93a7f BETTERZON-144: Adding service method to get session / user info 2021-06-15 10:19:48 +02:00
Patrick
3dbcc6707c
Merge pull request #80 from Mueller-Patrick/BETTERZON-143
BETTERZON-143: Fixing API endpoints that didn't return a json
2021-06-14 20:56:08 +02:00
1bb05a1baf BETTERZON-143: Fixing API endpoints that didn't return a json 2021-06-14 20:54:54 +02:00
6eaf7aca82 Adding SQL script 2021-06-14 15:54:57 +02:00
9512002081 Revert "Adjusting frontend and backend package names"
This reverts commit e0033065
2021-06-14 14:49:24 +02:00
e00330656e Adjusting frontend and backend package names 2021-06-14 14:40:41 +02:00
Patrick
099f6f1c51
Merge pull request #79 from Mueller-Patrick/BETTERZON-141
BETTERZON-141: Adding more service methods for prices and products
2021-06-11 12:23:19 +02:00
a80e86b4ea BETTERZON-141: Adding more service methods for prices and products 2021-06-11 12:20:10 +02:00
Patrick
dcb9edd562
Adding License 2021-06-10 14:31:10 +02:00
20 changed files with 580 additions and 68 deletions

View File

@ -76,7 +76,9 @@ contactpersonsRouter.post('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get required parameters // Get required parameters
const vendor_id = req.body.vendor_id; const vendor_id = req.body.vendor_id;
@ -89,9 +91,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); const success = await ContactPersonService.createContactEntry(user.user_id, vendor_id, first_name, last_name, gender, email, phone);
if (success) { if (success) {
res.sendStatus(201); res.status(201).send({});
} else { } else {
res.sendStatus(500); res.status(500).send({});
} }
} catch (e) { } catch (e) {
console.log('Error handling a request: ' + e.message); console.log('Error handling a request: ' + e.message);
@ -104,7 +106,9 @@ contactpersonsRouter.put('/:id', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get required parameters // Get required parameters
const contact_person_id = parseInt(req.params.id, 10); const contact_person_id = parseInt(req.params.id, 10);
@ -118,9 +122,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); const success = await ContactPersonService.updateContactEntry(user.user_id, contact_person_id, vendor_id, first_name, last_name, gender, email, phone);
if (success) { if (success) {
res.sendStatus(200); res.status(200).send({});
} else { } else {
res.sendStatus(500); res.status(500).send({});
} }
} catch (e) { } catch (e) {
console.log('Error handling a request: ' + e.message); console.log('Error handling a request: ' + e.message);

View File

@ -25,10 +25,12 @@ crawlingstatusRouter.get('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
if (!user.is_admin) { if (!user.is_admin) {
res.sendStatus(403); res.status(403).send({});
return; return;
} }

View File

@ -24,7 +24,9 @@ favoriteshopsRouter.get('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.params.session_id;
const session_key = req.params.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
const priceAlarms = await FavoriteShopsService.getFavoriteShops(user.user_id); const priceAlarms = await FavoriteShopsService.getFavoriteShops(user.user_id);
@ -40,7 +42,9 @@ favoriteshopsRouter.post('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get info for price alarm creation // Get info for price alarm creation
const vendor_id = req.body.vendor_id; const vendor_id = req.body.vendor_id;
@ -72,7 +76,9 @@ favoriteshopsRouter.delete('/:id', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.params.session_id;
const session_key = req.params.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get info for price alarm creation // Get info for price alarm creation
const favorite_id = parseInt(req.params.id, 10); const favorite_id = parseInt(req.params.id, 10);

View File

@ -24,7 +24,9 @@ pricealarmsRouter.get('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.params.session_id;
const session_key = req.params.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
const priceAlarms = await PriceAlarmsService.getPriceAlarms(user.user_id); const priceAlarms = await PriceAlarmsService.getPriceAlarms(user.user_id);
@ -40,7 +42,9 @@ pricealarmsRouter.post('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get info for price alarm creation // Get info for price alarm creation
const product_id = req.body.product_id; const product_id = req.body.product_id;
@ -73,7 +77,9 @@ pricealarmsRouter.put('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get info for price alarm creation // Get info for price alarm creation
const alarm_id = req.body.alarm_id; const alarm_id = req.body.alarm_id;

View File

@ -107,7 +107,9 @@ pricesRouter.post('/', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get required parameters // Get required parameters
const vendor_id = req.body.vendor_id; const vendor_id = req.body.vendor_id;
@ -117,9 +119,9 @@ pricesRouter.post('/', async (req: Request, res: Response) => {
const success = await PriceService.createPriceEntry(user.user_id, vendor_id, product_id, price_in_cents); const success = await PriceService.createPriceEntry(user.user_id, vendor_id, product_id, price_in_cents);
if (success) { if (success) {
res.sendStatus(201); res.status(201).send({});
} else { } else {
res.sendStatus(500); res.status(500).send({});
} }
} catch (e) { } catch (e) {
console.log('Error handling a request: ' + e.message); console.log('Error handling a request: ' + e.message);

View File

@ -120,7 +120,7 @@ productsRouter.post('/', async (req: Request, res: Response) => {
const result: boolean = await ProductService.addNewProduct(asin); const result: boolean = await ProductService.addNewProduct(asin);
if (result) { if (result) {
res.sendStatus(201); res.status(201).send({});
} else { } else {
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.'}));
} }

View File

@ -47,10 +47,10 @@ usersRouter.post('/register', async (req: Request, res: Response) => {
const session: Session = await UserService.createUser(username, password, email, ip); const session: Session = await UserService.createUser(username, password, email, ip);
// Send the session details back to the user // Send the session details back to the user
res.cookie('betterauth', JSON.stringify({ res.status(201).send({
id: session.session_id, session_id: session.session_id,
key: session.session_key session_key: session.session_key
}), {expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30)}).sendStatus(201); });
} catch (e) { } catch (e) {
console.log('Error handling a request: ' + e.message); console.log('Error handling a request: ' + e.message);
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.'}));
@ -80,10 +80,10 @@ usersRouter.post('/login', async (req: Request, res: Response) => {
} }
// Send the session details back to the user // Send the session details back to the user
res.cookie('betterauth', JSON.stringify({ res.status(200).send({
id: session.session_id, session_id: session.session_id,
key: session.session_key session_key: session.session_key
}), {expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30)}).sendStatus(200); });
} catch (e) { } catch (e) {
console.log('Error handling a request: ' + e.message); console.log('Error handling a request: ' + e.message);
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.'}));
@ -94,9 +94,17 @@ usersRouter.post('/login', async (req: Request, res: Response) => {
usersRouter.post('/checkSessionValid', async (req: Request, res: Response) => { usersRouter.post('/checkSessionValid', async (req: Request, res: Response) => {
try { try {
const ip: string = req.connection.remoteAddress ?? ''; const ip: string = req.connection.remoteAddress ?? '';
const session_id = req.body.session_id;
const session_key = req.body.session_key;
if(!session_id || !session_key) {
// Error logging in, probably wrong username / password
res.status(401).send(JSON.stringify({messages: ['No session detected'], codes: [5]}));
return;
}
// Update the user entry and create a session // Update the user entry and create a session
const user: User = await UserService.checkSessionWithCookie(req.cookies.betterauth, ip); const user: User = await UserService.checkSession(session_id, session_key, ip);
if (!user.user_id) { if (!user.user_id) {
// Error logging in, probably wrong username / password // Error logging in, probably wrong username / password

View File

@ -37,7 +37,9 @@ vendorsRouter.get('/managed', async (req: Request, res: Response) => {
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.params.session_id;
const session_key = req.params.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
const vendors = await VendorService.getManagedShops(user.user_id); const vendors = await VendorService.getManagedShops(user.user_id);
@ -91,7 +93,9 @@ vendorsRouter.put('/manage/deactivatelisting', async (req: Request, res: Respons
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get required parameters // Get required parameters
const vendor_id = req.body.vendor_id; const vendor_id = req.body.vendor_id;
@ -100,9 +104,9 @@ 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.status(200).send({});
} else { } else {
res.sendStatus(500); res.status(500).send({});
} }
} catch (e) { } catch (e) {
console.log('Error handling a request: ' + e.message); console.log('Error handling a request: ' + e.message);
@ -115,7 +119,9 @@ vendorsRouter.put('/manage/shop/deactivate/:id', async (req: Request, res: Respo
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get required parameters // Get required parameters
const vendor_id = parseInt(req.params.id, 10); const vendor_id = parseInt(req.params.id, 10);
@ -123,9 +129,9 @@ vendorsRouter.put('/manage/shop/deactivate/:id', async (req: Request, res: Respo
const success = await VendorService.setShopStatus(user.user_id, vendor_id, false); const success = await VendorService.setShopStatus(user.user_id, vendor_id, false);
if (success) { if (success) {
res.sendStatus(200); res.status(200).send({});
} else { } else {
res.sendStatus(500); res.status(500).send({});
} }
} catch (e) { } catch (e) {
console.log('Error handling a request: ' + e.message); console.log('Error handling a request: ' + e.message);
@ -138,7 +144,9 @@ vendorsRouter.put('/manage/shop/activate/:id', async (req: Request, res: Respons
try { try {
// Authenticate user // Authenticate user
const user_ip = req.connection.remoteAddress ?? ''; const user_ip = req.connection.remoteAddress ?? '';
const user = await UserService.checkSessionWithCookie(req.cookies.betterauth, user_ip); const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get required parameters // Get required parameters
const vendor_id = parseInt(req.params.id, 10); const vendor_id = parseInt(req.params.id, 10);
@ -146,9 +154,9 @@ vendorsRouter.put('/manage/shop/activate/:id', async (req: Request, res: Respons
const success = await VendorService.setShopStatus(user.user_id, vendor_id, true); const success = await VendorService.setShopStatus(user.user_id, vendor_id, true);
if (success) { if (success) {
res.sendStatus(200); res.status(200).send({});
} else { } else {
res.sendStatus(500); res.status(500).send({});
} }
} catch (e) { } catch (e) {
console.log('Error handling a request: ' + e.message); console.log('Error handling a request: ' + e.message);

View File

@ -92,7 +92,8 @@
"karmaConfig": "karma.conf.js", "karmaConfig": "karma.conf.js",
"codeCoverage": true, "codeCoverage": true,
"codeCoverageExclude": [ "codeCoverageExclude": [
"src/app/mocks/mock.service.ts" "src/app/mocks/mock.service.ts",
"src/app/services/api.service.ts"
], ],
"assets": [ "assets": [
"src/favicon.ico", "src/favicon.ico",

View File

@ -61,7 +61,7 @@ form{
} }
.btn_signin{ .btn_signin{
transition: all .5s ease; transition: all .5s ease;
width: 70%; width: 100%;
border-radius: 30px; border-radius: 30px;
color:#008080; color:#008080;
font-weight: 600; font-weight: 600;

View File

@ -32,7 +32,6 @@ export class RegistrationComponent implements OnInit {
get me() { return this.form.controls; } get me() { return this.form.controls; }
onSubmit() { onSubmit() {
console.log(this.form.value);
this.api.registerUser(this.form.value.username, this.form.value.password, this.form.value.email).subscribe(res=>console.log(res)); this.api.registerUser(this.form.value.username, this.form.value.password, this.form.value.email).subscribe(res=>console.log(res));
} }
} }

View File

@ -61,7 +61,7 @@ form{
} }
.btn_signin{ .btn_signin{
transition: all .5s ease; transition: all .5s ease;
width: 70%; width: 100%;
border-radius: 30px; border-radius: 30px;
color:#008080; color:#008080;
font-weight: 600; font-weight: 600;

View File

@ -9,7 +9,7 @@
<h2>Anmelden</h2> <h2>Anmelden</h2>
</div> </div>
<div class="row"> <div class="row">
<form [formGroup]="form" class="form-group" (ngSubmit)="onSubmit()"> <form [formGroup]="loginForm" class="form-group" (ngSubmit)="onSubmit()">
<div class="row"> <div class="row">
<input type="text" formControlName="username" name="username" id="username" class="form__input" placeholder="Username"> <input type="text" formControlName="username" name="username" id="username" class="form__input" placeholder="Username">
</div> </div>

View File

@ -1,6 +1,7 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {FormBuilder, Validators} from "@angular/forms"; import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {ApiService} from "../../../services/api.service"; import {ApiService} from '../../../services/api.service';
import {Router} from '@angular/router';
@Component({ @Component({
selector: 'app-signin', selector: 'app-signin',
@ -10,22 +11,46 @@ import {ApiService} from "../../../services/api.service";
export class SigninComponent implements OnInit { export class SigninComponent implements OnInit {
form: any; loginForm: FormGroup;
loading = false;
submitted = false;
private isSuccessful: boolean;
private isSignUpFailed: boolean;
private errorMessage: '';
constructor( constructor(
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private api : ApiService private api: ApiService,
) { } private router: Router
) {
}
ngOnInit(): void { ngOnInit(): void {
this.form = this.formBuilder.group({ this.loginForm = this.formBuilder.group({
email: ['', Validators.required], username: ['', Validators.required],
password: ['', Validators.required] password: ['', [Validators.required, Validators.minLength(8)]]
}); });
} }
onSubmit() { onSubmit(): void {
console.log(this.form.value); this.submitted = true;
this.api.loginUser(this.form.value.username, this.form.value.password);
if (this.loginForm.invalid) {
return;
}
this.api.loginUser(this.loginForm.value.username, this.loginForm.value.password)
.subscribe(
data => {
this.router.navigate(['']);
this.isSuccessful = true;
this.isSignUpFailed = false;
this.api.saveSessionInfoToLocalStorage(data);
},
err => {
this.errorMessage = err.error.message;
this.isSignUpFailed = true;
});
} }
} }

View File

@ -47,7 +47,9 @@ export class ProductDetailsComponent implements OnInit {
} }
getProduct(): void { getProduct(): void {
this.apiService.getProduct(this.productId).subscribe(product => {this.product = product}); this.apiService.getProduct(this.productId).subscribe(product => {
this.product = product;
});
} }
getPrices(): void { getPrices(): void {

View File

@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import {ApiService} from "../../services/api.service";
@Component({ @Component({
selector: 'app-top-bar', selector: 'app-top-bar',
@ -9,9 +11,12 @@ export class TopBarComponent implements OnInit {
sidenav: any; sidenav: any;
constructor() { } constructor(
private api: ApiService
) { }
ngOnInit() { ngOnInit() {
}
this.api.getUserInfo().subscribe(data=>{console.log(data)});
}
} }

View File

@ -5,3 +5,24 @@ export interface Price {
price_in_cents: number; price_in_cents: number;
timestamp: Date; 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;
}
}

View File

@ -2,7 +2,7 @@ import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
import process from 'process'; import process from 'process';
import {Product} from '../models/product'; import {Product} from '../models/product';
import {Price} from '../models/price'; import {Deal, Price} from '../models/price';
import {Observable, of} from 'rxjs'; import {Observable, of} from 'rxjs';
import {Vendor} from '../models/vendor'; import {Vendor} from '../models/vendor';
import {PriceAlarm} from '../models/pricealarm'; 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 * Gets a list of all prices
* @return Observable<Price[]> An observable list of prices * @return Observable<Price[]> An observable list of prices
@ -140,6 +207,55 @@ 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 {
const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.post((this.apiUrl + '/prices'), JSON.stringify({
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
vendor_id: vendorId,
product_id: productId,
price_in_cents: price
}));
} catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
}
}
/* _ __ __ /* _ __ __
| | / /__ ____ ____/ /___ __________ | | / /__ ____ ____/ /___ __________
@ -166,7 +282,13 @@ export class ApiService {
*/ */
getManagedVendors(): Observable<Vendor[]> { getManagedVendors(): Observable<Vendor[]> {
try { try {
return this.http.get<Vendor[]>((this.apiUrl + '/vendors/managed')); const sessionInfo = this.getSessionInfoFromLocalStorage();
let params = new HttpParams();
params = params.append('session_id', sessionInfo.session_id);
params = params.append('session_key', sessionInfo.session_key);
return this.http.get<Vendor[]>((this.apiUrl + '/vendors/managed'), {params});
} catch (exception) { } catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
} }
@ -206,7 +328,11 @@ export class ApiService {
*/ */
deactivateSingleVendorListing(vendorId: number, productId: number): Observable<any> { deactivateSingleVendorListing(vendorId: number, productId: number): Observable<any> {
try { try {
const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.put((this.apiUrl + '/vendors/manage/deactivatelisting'), { return this.http.put((this.apiUrl + '/vendors/manage/deactivatelisting'), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
vendor_id: vendorId, vendor_id: vendorId,
product_id: productId product_id: productId
}); });
@ -222,7 +348,12 @@ export class ApiService {
*/ */
deactivateVendor(vendorId: number): Observable<any> { deactivateVendor(vendorId: number): Observable<any> {
try { try {
return this.http.put((this.apiUrl + '/vendors/manage/shop/deactivate/' + vendorId), {}); const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.put((this.apiUrl + '/vendors/manage/shop/deactivate/' + vendorId), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
});
} catch (exception) { } catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
} }
@ -235,7 +366,12 @@ export class ApiService {
*/ */
activateVendor(vendorId: number): Observable<any> { activateVendor(vendorId: number): Observable<any> {
try { try {
return this.http.put((this.apiUrl + '/vendors/manage/shop/activate/' + vendorId), {}); const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.put((this.apiUrl + '/vendors/manage/shop/activate/' + vendorId), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
});
} catch (exception) { } catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
} }
@ -255,7 +391,13 @@ export class ApiService {
*/ */
getPriceAlarms(): Observable<PriceAlarm[]> { getPriceAlarms(): Observable<PriceAlarm[]> {
try { try {
return this.http.get<PriceAlarm[]>((this.apiUrl + '/pricealarms')); const sessionInfo = this.getSessionInfoFromLocalStorage();
let params = new HttpParams();
params = params.append('session_id', sessionInfo.session_id);
params = params.append('session_key', sessionInfo.session_key);
return this.http.get<PriceAlarm[]>((this.apiUrl + '/pricealarms'), {params});
} catch (exception) { } catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
} }
@ -269,7 +411,11 @@ export class ApiService {
*/ */
createPriceAlarms(productId: number, definedPrice: number): Observable<any> { createPriceAlarms(productId: number, definedPrice: number): Observable<any> {
try { try {
const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.post((this.apiUrl + '/pricealarms'), { return this.http.post((this.apiUrl + '/pricealarms'), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
product_id: productId, product_id: productId,
defined_price: definedPrice defined_price: definedPrice
}); });
@ -286,7 +432,11 @@ export class ApiService {
*/ */
updatePriceAlarms(alarmId: number, definedPrice: number): Observable<any> { updatePriceAlarms(alarmId: number, definedPrice: number): Observable<any> {
try { try {
const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.put((this.apiUrl + '/pricealarms'), { return this.http.put((this.apiUrl + '/pricealarms'), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
alarm_id: alarmId, alarm_id: alarmId,
defined_price: definedPrice defined_price: definedPrice
}); });
@ -339,6 +489,43 @@ export class ApiService {
} }
} }
/**
* Get all required information about the currently logged in user. If the user is not logged in or the
* session is not valid anymore, a 401 will come back from the backend.
* @return Observable<any> The observable response of the api
*/
getUserInfo(): Observable<any> {
try {
const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.post((this.apiUrl + '/users/checkSessionValid'), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key
});
} catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
}
}
/**
* Gets session id and session key from local storage
* @return any {session_id: '', session_key: ''}
*/
getSessionInfoFromLocalStorage(): any {
const session_id = localStorage.getItem('session_id') ?? '';
const session_key = localStorage.getItem('session_key') ?? '';
return {session_id, session_key};
}
/**
* Extracts and saves the session data from an api response
* @param data The api response
*/
saveSessionInfoToLocalStorage(data: any): boolean {
localStorage.setItem('session_id', data.session_id);
localStorage.setItem('session_key', data.session_key);
return true;
}
/* ______ _ __ __ /* ______ _ __ __
/ ____/___ __ ______ _____(_) /____ _____/ /_ ____ ____ _____ / ____/___ __ ______ _____(_) /____ _____/ /_ ____ ____ _____
/ /_ / __ `/ | / / __ \/ ___/ / __/ _ \ / ___/ __ \/ __ \/ __ \/ ___/ / /_ / __ `/ | / / __ \/ ___/ / __/ _ \ / ___/ __ \/ __ \/ __ \/ ___/
@ -353,7 +540,13 @@ export class ApiService {
*/ */
getFavoriteShops(): Observable<FavoriteShop[]> { getFavoriteShops(): Observable<FavoriteShop[]> {
try { try {
return this.http.get<FavoriteShop[]>((this.apiUrl + '/favoriteshops')); const sessionInfo = this.getSessionInfoFromLocalStorage();
let params = new HttpParams();
params = params.append('session_id', sessionInfo.session_id);
params = params.append('session_key', sessionInfo.session_key);
return this.http.get<FavoriteShop[]>((this.apiUrl + '/favoriteshops'), {params});
} catch (exception) { } catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
} }
@ -366,7 +559,11 @@ export class ApiService {
*/ */
addFavoriteShop(vendorId: number): Observable<any> { addFavoriteShop(vendorId: number): Observable<any> {
try { try {
const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.post((this.apiUrl + '/favoriteshops'), { return this.http.post((this.apiUrl + '/favoriteshops'), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
vendor_id: vendorId vendor_id: vendorId
}); });
} catch (exception) { } catch (exception) {
@ -381,7 +578,13 @@ export class ApiService {
*/ */
deleteFavoriteShop(vendorId: number): Observable<any> { deleteFavoriteShop(vendorId: number): Observable<any> {
try { try {
return this.http.delete((this.apiUrl + '/favoriteshops/' + vendorId)); const sessionInfo = this.getSessionInfoFromLocalStorage();
let params = new HttpParams();
params = params.append('session_id', sessionInfo.session_id);
params = params.append('session_key', sessionInfo.session_key);
return this.http.delete((this.apiUrl + '/favoriteshops/' + vendorId), {params});
} catch (exception) { } catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
} }
@ -445,7 +648,11 @@ export class ApiService {
*/ */
addContactPerson(vendorId: number, firstName: string, lastName: string, gender: string, email: string, phone: string): Observable<any> { addContactPerson(vendorId: number, firstName: string, lastName: string, gender: string, email: string, phone: string): Observable<any> {
try { try {
const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.post((this.apiUrl + '/contactpersons'), { return this.http.post((this.apiUrl + '/contactpersons'), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
vendor_id: vendorId, vendor_id: vendorId,
first_name: firstName, first_name: firstName,
last_name: lastName, last_name: lastName,
@ -471,7 +678,11 @@ export class ApiService {
*/ */
updateContactPerson(contactId: number, vendorId: number, firstName: string, lastName: string, gender: string, email: string, phone: string): Observable<any> { updateContactPerson(contactId: number, vendorId: number, firstName: string, lastName: string, gender: string, email: string, phone: string): Observable<any> {
try { try {
const sessionInfo = this.getSessionInfoFromLocalStorage();
return this.http.put((this.apiUrl + '/contactpersons/' + contactId), { return this.http.put((this.apiUrl + '/contactpersons/' + contactId), {
session_id: sessionInfo.session_id,
session_key: sessionInfo.session_key,
vendor_id: vendorId, vendor_id: vendorId,
first_name: firstName, first_name: firstName,
last_name: lastName, last_name: lastName,
@ -593,7 +804,13 @@ export class ApiService {
*/ */
getCurrentCrawlingStatus(): Observable<CrawlingStatus> { getCurrentCrawlingStatus(): Observable<CrawlingStatus> {
try { try {
return this.http.get<CrawlingStatus>((this.apiUrl + '/crawlingstatus')); const sessionInfo = this.getSessionInfoFromLocalStorage();
let params = new HttpParams();
params = params.append('session_id', sessionInfo.session_id);
params = params.append('session_key', sessionInfo.session_key);
return this.http.get<CrawlingStatus>((this.apiUrl + '/crawlingstatus'), {params});
} catch (exception) { } catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`); process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
} }

21
LICENSE Normal file
View 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.

View 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)
);