From 05d4795f9dc11c854abf83de28fbf4c6fad601b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20M=C3=BCller?= Date: Thu, 1 Apr 2021 10:34:35 +0200 Subject: [PATCH 1/6] BETTERZON-49: Creating Module for Crawler --- .idea/modules.xml | 1 + Backend/src/models/categories/categories.router.ts | 6 +++--- Backend/src/models/products/products.router.ts | 8 +++++--- Crawler/requirements.txt | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 Crawler/requirements.txt diff --git a/.idea/modules.xml b/.idea/modules.xml index 66aebf2..44a6847 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -4,6 +4,7 @@ + diff --git a/Backend/src/models/categories/categories.router.ts b/Backend/src/models/categories/categories.router.ts index 409ca71..1af2db5 100644 --- a/Backend/src/models/categories/categories.router.ts +++ b/Backend/src/models/categories/categories.router.ts @@ -19,7 +19,7 @@ export const categoriesRouter = express.Router(); * Controller Definitions */ -// GET items/ +// GET categories/ categoriesRouter.get('/', async (req: Request, res: Response) => { try { @@ -31,7 +31,7 @@ categoriesRouter.get('/', async (req: Request, res: Response) => { } }); -// GET items/:id +// GET categories/:id categoriesRouter.get('/:id', async (req: Request, res: Response) => { const id: number = parseInt(req.params.id, 10); @@ -50,7 +50,7 @@ categoriesRouter.get('/:id', async (req: Request, res: Response) => { } }); -// GET items/:name +// GET categories/search/:term categoriesRouter.get('/search/:term', async (req: Request, res: Response) => { const term: string = req.params.term; diff --git a/Backend/src/models/products/products.router.ts b/Backend/src/models/products/products.router.ts index 0c7cc5c..f2f3353 100644 --- a/Backend/src/models/products/products.router.ts +++ b/Backend/src/models/products/products.router.ts @@ -19,7 +19,7 @@ export const productsRouter = express.Router(); * Controller Definitions */ -// GET items/ +// GET products/ productsRouter.get('/', async (req: Request, res: Response) => { try { @@ -31,7 +31,7 @@ productsRouter.get('/', async (req: Request, res: Response) => { } }); -// GET items/:id +// GET products/:id productsRouter.get('/:id', async (req: Request, res: Response) => { const id: number = parseInt(req.params.id, 10); @@ -50,7 +50,7 @@ productsRouter.get('/:id', async (req: Request, res: Response) => { } }); -// GET items/:name +// GET products/search/:term productsRouter.get('/search/:term', async (req: Request, res: Response) => { const term: string = req.params.term; @@ -69,6 +69,8 @@ productsRouter.get('/search/:term', async (req: Request, res: Response) => { } }); +// GET products/bestDeals + // POST items/ diff --git a/Crawler/requirements.txt b/Crawler/requirements.txt new file mode 100644 index 0000000..d4a7eda --- /dev/null +++ b/Crawler/requirements.txt @@ -0,0 +1 @@ +pymysql From bebf1b12365ad5714fd7f035509cc17f537d744c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20M=C3=BCller?= Date: Thu, 1 Apr 2021 11:37:20 +0200 Subject: [PATCH 2/6] BETTERZON-49: Adding module .iml --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 103250b..ff35e3c 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ speed-measure-plugin*.json !Frontend.iml !Backend.iml !CucumberTests.iml +!Crawler.iml # Include IntelliJ modules !/.idea/modules.xml From 8055f811d76e1d86b41eef9f68e185c33c0941d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20M=C3=BCller?= Date: Thu, 1 Apr 2021 11:37:20 +0200 Subject: [PATCH 3/6] BETTERZON-49: Adding module .iml --- .gitignore | 1 + Crawler/Crawler.iml | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 Crawler/Crawler.iml diff --git a/.gitignore b/.gitignore index 103250b..ff35e3c 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ speed-measure-plugin*.json !Frontend.iml !Backend.iml !CucumberTests.iml +!Crawler.iml # Include IntelliJ modules !/.idea/modules.xml diff --git a/Crawler/Crawler.iml b/Crawler/Crawler.iml new file mode 100644 index 0000000..80cc739 --- /dev/null +++ b/Crawler/Crawler.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From fa4a14b6ad9f2290d4a14dd51ac123e8bd9da7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20M=C3=BCller?= Date: Mon, 5 Apr 2021 12:56:21 +0200 Subject: [PATCH 4/6] BETTERZON-36: Adding imprint and privacy policy --- Frontend/src/app/app.module.ts | 6 +- Frontend/src/app/app.routing.ts | 4 + .../components/footer/footer.component.css | 19 +- .../components/footer/footer.component.html | 8 +- .../app/components/footer/footer.component.ts | 10 +- .../app/pages/imprint/imprint.component.css | 4 + .../app/pages/imprint/imprint.component.html | 59 +++ .../pages/imprint/imprint.component.spec.ts | 25 ++ .../app/pages/imprint/imprint.component.ts | 15 + .../app/pages/privacy/privacy.component.css | 4 + .../app/pages/privacy/privacy.component.html | 408 ++++++++++++++++++ .../pages/privacy/privacy.component.spec.ts | 25 ++ .../app/pages/privacy/privacy.component.ts | 15 + 13 files changed, 597 insertions(+), 5 deletions(-) create mode 100644 Frontend/src/app/pages/imprint/imprint.component.css create mode 100644 Frontend/src/app/pages/imprint/imprint.component.html create mode 100644 Frontend/src/app/pages/imprint/imprint.component.spec.ts create mode 100644 Frontend/src/app/pages/imprint/imprint.component.ts create mode 100644 Frontend/src/app/pages/privacy/privacy.component.css create mode 100644 Frontend/src/app/pages/privacy/privacy.component.html create mode 100644 Frontend/src/app/pages/privacy/privacy.component.spec.ts create mode 100644 Frontend/src/app/pages/privacy/privacy.component.ts diff --git a/Frontend/src/app/app.module.ts b/Frontend/src/app/app.module.ts index eef8e23..a324b8d 100644 --- a/Frontend/src/app/app.module.ts +++ b/Frontend/src/app/app.module.ts @@ -15,6 +15,8 @@ import {HeaderComponent} from './components/header/header.component'; import {NewestPricesListComponent} from './components/newest-prices-list/newest-prices-list.component'; import {FormsModule} from '@angular/forms'; import {PageNotFoundPageComponent} from './pages/page-not-found-page/page-not-found-page.component'; +import { ImprintComponent } from './pages/imprint/imprint.component'; +import { PrivacyComponent } from './pages/privacy/privacy.component'; @NgModule({ declarations: [ @@ -27,7 +29,9 @@ import {PageNotFoundPageComponent} from './pages/page-not-found-page/page-not-fo ProductSearchPageComponent, HeaderComponent, NewestPricesListComponent, - PageNotFoundPageComponent + PageNotFoundPageComponent, + ImprintComponent, + PrivacyComponent ], imports: [ BrowserModule, diff --git a/Frontend/src/app/app.routing.ts b/Frontend/src/app/app.routing.ts index efb2a36..c38d9ba 100644 --- a/Frontend/src/app/app.routing.ts +++ b/Frontend/src/app/app.routing.ts @@ -7,11 +7,15 @@ import {LandingpageComponent} from './pages/landingpage/landingpage.component'; import {ProductDetailPageComponent} from './pages/product-detail-page/product-detail-page.component'; import {ProductSearchPageComponent} from './pages/product-search-page/product-search-page.component'; import {PageNotFoundPageComponent} from './pages/page-not-found-page/page-not-found-page.component'; +import {ImprintComponent} from './pages/imprint/imprint.component'; +import {PrivacyComponent} from './pages/privacy/privacy.component'; const routes: Routes = [ {path: '', component: LandingpageComponent}, {path: 'search', component: ProductSearchPageComponent}, {path: 'product/:id', component: ProductDetailPageComponent}, + {path: 'impressum', component: ImprintComponent}, + {path: 'datenschutz', component: PrivacyComponent}, {path: '**', component: PageNotFoundPageComponent} ]; diff --git a/Frontend/src/app/components/footer/footer.component.css b/Frontend/src/app/components/footer/footer.component.css index c39569a..0d7949b 100644 --- a/Frontend/src/app/components/footer/footer.component.css +++ b/Frontend/src/app/components/footer/footer.component.css @@ -5,7 +5,6 @@ width: 100%; background-color: dimgrey; color: white; - text-align: center; } .icon-3d { @@ -13,5 +12,23 @@ color: #fff; } +#footer-icons { + text-align: center; +} + +#imprintSection { + position: fixed; + right: 1em; + bottom: 1em; + width: 100%; + text-align: right; + padding-right: 1em; +} + +#imprintSection a { + color: white; + text-decoration: none; +} + diff --git a/Frontend/src/app/components/footer/footer.component.html b/Frontend/src/app/components/footer/footer.component.html index e6d17d8..a57e963 100644 --- a/Frontend/src/app/components/footer/footer.component.html +++ b/Frontend/src/app/components/footer/footer.component.html @@ -3,12 +3,16 @@ diff --git a/Frontend/src/app/components/footer/footer.component.ts b/Frontend/src/app/components/footer/footer.component.ts index a10f2a4..502c475 100644 --- a/Frontend/src/app/components/footer/footer.component.ts +++ b/Frontend/src/app/components/footer/footer.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; @Component({ selector: 'app-footer', @@ -7,9 +8,16 @@ import { Component, OnInit } from '@angular/core'; }) export class FooterComponent implements OnInit { - constructor() { } + constructor( + private router: Router, + private route: ActivatedRoute + ) {} ngOnInit(): void { } + navigateImprint(): void { + this.router.navigate([('/impressum/')]); + } + } diff --git a/Frontend/src/app/pages/imprint/imprint.component.css b/Frontend/src/app/pages/imprint/imprint.component.css new file mode 100644 index 0000000..56d491f --- /dev/null +++ b/Frontend/src/app/pages/imprint/imprint.component.css @@ -0,0 +1,4 @@ +#imprint { + padding-left: 5em; + padding-right: 5em; +} diff --git a/Frontend/src/app/pages/imprint/imprint.component.html b/Frontend/src/app/pages/imprint/imprint.component.html new file mode 100644 index 0000000..840716f --- /dev/null +++ b/Frontend/src/app/pages/imprint/imprint.component.html @@ -0,0 +1,59 @@ + +
+

Impressum

+ +

Angaben gemäß § 5 TMG

+

+ Patrick Müller
+ Schachtstraße 8
+ 75031 Eppingen +

+ +

Kontakt

+

+ E-Mail: betterzon-contact@mueller-patrick.tech +

+ +

Haftung für Inhalte

+

+ Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene + Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als + Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen + oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. +

+

+ Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben + hiervon unberührt. + Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. + Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen. +

+ +

Haftung für Links

+

+ Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen + Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für + die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die + verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. + Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. +

+

+ Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer + Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend + entfernen. +

+ +

Urheberrecht

+

+ Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. + Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des + Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und + Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. +

+

+ Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. + Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung + aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir + derartige Inhalte umgehend entfernen. +

+
+ diff --git a/Frontend/src/app/pages/imprint/imprint.component.spec.ts b/Frontend/src/app/pages/imprint/imprint.component.spec.ts new file mode 100644 index 0000000..2739ab4 --- /dev/null +++ b/Frontend/src/app/pages/imprint/imprint.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ImprintComponent } from './imprint.component'; + +describe('ImprintComponent', () => { + let component: ImprintComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ImprintComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ImprintComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/src/app/pages/imprint/imprint.component.ts b/Frontend/src/app/pages/imprint/imprint.component.ts new file mode 100644 index 0000000..f3c5441 --- /dev/null +++ b/Frontend/src/app/pages/imprint/imprint.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-imprint', + templateUrl: './imprint.component.html', + styleUrls: ['./imprint.component.css'] +}) +export class ImprintComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/Frontend/src/app/pages/privacy/privacy.component.css b/Frontend/src/app/pages/privacy/privacy.component.css new file mode 100644 index 0000000..a1ea55c --- /dev/null +++ b/Frontend/src/app/pages/privacy/privacy.component.css @@ -0,0 +1,4 @@ +#privacy { + padding-left: 5em; + padding-right: 5em; +} diff --git a/Frontend/src/app/pages/privacy/privacy.component.html b/Frontend/src/app/pages/privacy/privacy.component.html new file mode 100644 index 0000000..29c167f --- /dev/null +++ b/Frontend/src/app/pages/privacy/privacy.component.html @@ -0,0 +1,408 @@ + +
+

Datenschutz­erklärung

+

1. Datenschutz auf einen Blick

+

Allgemeine Hinweise

+

+ Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren + personenbezogenen Daten passiert, wenn Sie diese Website besuchen. Personenbezogene Daten sind alle Daten, mit denen + Sie persönlich identifiziert werden können. Ausführliche Informationen zum Thema Datenschutz + entnehmen Sie unserer unter diesem Text aufgeführten Datenschutzerklärung. +

+ +

Datenerfassung auf dieser Website

+

Wer ist verantwortlich für die Datenerfassung auf dieser Website?

+

+ Die Datenverarbeitung auf dieser Website erfolgt durch den Websitebetreiber. Dessen Kontaktdaten können + Sie dem Abschnitt „Hinweis zur Verantwortlichen Stelle“ in dieser Datenschutzerklärung + entnehmen. +

+ +

Wie erfassen wir Ihre Daten?

+

+ Ihre Daten werden zum einen dadurch erhoben, dass Sie uns + diese mitteilen. Hierbei kann es sich z. B. um Daten handeln, die Sie in ein Kontaktformular eingeben. +

+

+ Andere Daten werden automatisch oder nach Ihrer Einwilligung beim Besuch der Website durch unsere IT-Systeme + erfasst. Das sind vor allem technische Daten (z. B. Internetbrowser, Betriebssystem oder Uhrzeit des + Seitenaufrufs). Die Erfassung dieser Daten erfolgt automatisch, sobald Sie diese Website betreten. +

+ +

Wofür nutzen wir Ihre Daten?

+

+ Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der Website zu + gewährleisten. Andere Daten können zur Analyse Ihres Nutzerverhaltens verwendet werden. +

+ +

Welche Rechte haben Sie bezüglich Ihrer Daten?

+

+ Sie haben jederzeit das Recht, unentgeltlich Auskunft über + Herkunft, Empfänger und Zweck Ihrer gespeicherten personenbezogenen Daten zu erhalten. Sie haben außerdem + ein Recht, die Berichtigung oder Löschung dieser Daten zu verlangen. Wenn Sie eine Einwilligung zur + Datenverarbeitung erteilt haben, können Sie diese Einwilligung jederzeit für die Zukunft widerrufen. Außerdem + haben Sie das Recht, unter bestimmten Umständen die Einschränkung der Verarbeitung Ihrer personenbezogenen + Daten zu verlangen. Des Weiteren steht Ihnen ein Beschwerderecht bei der zuständigen Aufsichtsbehörde + zu. +

+

+ Hierzu sowie zu weiteren Fragen zum Thema Datenschutz können Sie sich jederzeit an uns wenden. +

+ +

2. Hosting und Content Delivery Networks (CDN)

+

Externes Hosting

+

+ Diese Website wird bei einem externen Dienstleister gehostet (Hoster). Die + personenbezogenen Daten, die auf dieser Website erfasst werden, werden auf den Servern des Hosters gespeichert. + Hierbei kann es sich v. a. um IP-Adressen, Kontaktanfragen, Meta- und Kommunikationsdaten, Vertragsdaten, + Kontaktdaten, Namen, Websitezugriffe und sonstige Daten, die über eine Website generiert werden, handeln. +

+

+ Der Einsatz des Hosters erfolgt zum Zwecke der Vertragserfüllung gegenüber unseren potenziellen und + bestehenden Kunden (Art. 6 Abs. 1 lit. b DSGVO) und im Interesse einer sicheren, schnellen und effizienten + Bereitstellung unseres Online-Angebots durch einen professionellen Anbieter (Art. 6 Abs. 1 lit. f DSGVO). +

+

+ Unser Hoster wird Ihre Daten nur insoweit verarbeiten, wie dies zur Erfüllung seiner Leistungspflichten + erforderlich ist und unsere Weisungen in Bezug auf diese Daten befolgen. +

+

+ Wir setzen folgenden Hoster ein: +

+

+ netcup GmbH
+ Daimlerstraße 25
+ 76185 Karlsruhe +

+ +

Abschluss eines Vertrages über Auftragsverarbeitung

+

+ Um die datenschutzkonforme Verarbeitung zu gewährleisten, + haben wir einen Vertrag über Auftragsverarbeitung mit unserem Hoster geschlossen. +

+ +

3. Allgemeine Hinweise und Pflicht­informationen

+

Datenschutz

+

+ Die Betreiber dieser Seiten nehmen den Schutz Ihrer persönlichen Daten sehr ernst. Wir + behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie + dieser Datenschutzerklärung. +

+

+ Wenn Sie diese Website benutzen, werden verschiedene personenbezogene Daten + erhoben. Personenbezogene Daten sind Daten, mit denen Sie persönlich identifiziert werden können. Die + vorliegende Datenschutzerklärung erläutert, welche Daten wir erheben und wofür wir sie nutzen. Sie + erläutert auch, wie und zu welchem Zweck das geschieht. +

+

+ Wir weisen darauf hin, dass die Datenübertragung + im Internet (z. B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser + Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich. +

+ +

Hinweis zur verantwortlichen Stelle

+

+ Die verantwortliche Stelle für die Datenverarbeitung auf dieser + Website ist: +

+

+ Patrick Müller
+ Schachtstraße 8
+ 75031 Eppingen +

+ +

+ E-Mail: betterzon-privacy@mueller-patrick.tech +

+

+ Verantwortliche Stelle ist die natürliche oder juristische Person, die allein oder gemeinsam mit anderen über + die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten (z. B. Namen, E-Mail-Adressen o. Ä.) + entscheidet. +

+ +

Speicherdauer

+

+ Soweit innerhalb dieser Datenschutzerklärung keine speziellere Speicherdauer genannt + wurde, verbleiben Ihre personenbezogenen Daten bei uns, bis der Zweck für die Datenverarbeitung entfällt. + Wenn Sie ein berechtigtes Löschersuchen geltend machen oder eine Einwilligung zur Datenverarbeitung widerrufen, + werden Ihre Daten gelöscht, sofern wir keine anderen rechtlich zulässigen Gründe für die + Speicherung Ihrer personenbezogenen Daten haben (z.B. steuer- oder handelsrechtliche Aufbewahrungsfristen); im + letztgenannten Fall erfolgt die Löschung nach Fortfall dieser Gründe. +

+ +

Hinweis zur Datenweitergabe in die USA und sonstige Drittstaaten

+

+ Auf unserer Website sind unter anderem + Tools von Unternehmen mit Sitz in den USA oder sonstigen datenschutzrechtlich nicht sicheren Drittstaaten + eingebunden. Wenn diese Tools aktiv sind, können Ihre personenbezogene Daten in diese Drittstaaten übertragen + und dort verarbeitet werden. Wir weisen darauf hin, dass in diesen Ländern kein mit der EU vergleichbares + Datenschutzniveau garantiert werden kann. Beispielsweise sind US-Unternehmen dazu verpflichtet, personenbezogene + Daten an Sicherheitsbehörden herauszugeben, ohne dass Sie als Betroffener hiergegen gerichtlich vorgehen könnten. + Es kann daher nicht ausgeschlossen werden, dass US-Behörden (z.B. Geheimdienste) Ihre auf US-Servern + befindlichen Daten zu Überwachungszwecken verarbeiten, auswerten und dauerhaft speichern. Wir haben auf diese + Verarbeitungstätigkeiten keinen Einfluss. +

+ +

Widerruf Ihrer Einwilligung zur Datenverarbeitung

+

+ Viele Datenverarbeitungsvorgänge sind nur mit Ihrer ausdrücklichen Einwilligung möglich. Sie können + eine bereits erteilte Einwilligung jederzeit widerrufen. Die Rechtmäßigkeit der bis zum Widerruf + erfolgten Datenverarbeitung bleibt vom Widerruf unberührt. +

+ +

Widerspruchsrecht gegen die Datenerhebung in besonderen Fällen sowie gegen Direktwerbung (Art. 21 DSGVO)

+

+ WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F DSGVO ERFOLGT, HABEN SIE JEDERZEIT DAS + RECHT, AUS GRÜNDEN, DIE SICH AUS IHRER BESONDEREN SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER + PERSONENBEZOGENEN DATEN WIDERSPRUCH EINZULEGEN; DIES GILT AUCH FÜR EIN AUF DIESE BESTIMMUNGEN GESTÜTZTES + PROFILING. DIE JEWEILIGE RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE DIESER DATENSCHUTZERKLÄRUNG. + WENN SIE WIDERSPRUCH EINLEGEN, WERDEN WIR IHRE BETROFFENEN PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES SEI + DENN, WIR KÖNNEN ZWINGENDE SCHUTZWÜRDIGE GRÜNDE FÜR DIE VERARBEITUNG NACHWEISEN, DIE IHRE + INTERESSEN, RECHTE UND FREIHEITEN ÜBERWIEGEN ODER DIE VERARBEITUNG DIENT DER GELTENDMACHUNG, AUSÜBUNG ODER + VERTEIDIGUNG VON RECHTSANSPRÜCHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO). +

+

+ WERDEN IHRE PERSONENBEZOGENEN + DATEN VERARBEITET, UM DIREKTWERBUNG ZU BETREIBEN, SO HABEN SIE DAS RECHT, JEDERZEIT WIDERSPRUCH GEGEN DIE + VERARBEITUNG SIE BETREFFENDER PERSONENBEZOGENER DATEN ZUM ZWECKE DERARTIGER WERBUNG EINZULEGEN; DIES GILT AUCH FÜR + DAS PROFILING, SOWEIT ES MIT SOLCHER DIREKTWERBUNG IN VERBINDUNG STEHT. WENN SIE WIDERSPRECHEN, WERDEN IHRE + PERSONENBEZOGENEN DATEN ANSCHLIESSEND NICHT MEHR ZUM ZWECKE DER DIREKTWERBUNG VERWENDET (WIDERSPRUCH NACH ART. 21 + ABS. 2 DSGVO). +

+ +

Beschwerde­recht bei der zuständigen Aufsichts­behörde

+

+ Im Falle von Verstößen + gegen die DSGVO steht den Betroffenen ein Beschwerderecht bei einer Aufsichtsbehörde, insbesondere in dem + Mitgliedstaat ihres gewöhnlichen Aufenthalts, ihres Arbeitsplatzes oder des Orts des mutmaßlichen Verstoßes + zu. Das Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher oder gerichtlicher + Rechtsbehelfe. +

+ +

Recht auf Daten­übertrag­barkeit

+

+ Sie haben das Recht, Daten, die wir auf Grundlage Ihrer + Einwilligung oder in Erfüllung eines Vertrags automatisiert verarbeiten, an sich oder an einen Dritten in einem + gängigen, maschinenlesbaren Format aushändigen zu lassen. Sofern Sie die direkte Übertragung der + Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur, soweit es technisch machbar ist. +

+ +

SSL- bzw. TLS-Verschlüsselung

+

+ Diese Seite nutzt aus Sicherheitsgründen und zum Schutz der Übertragung + vertraulicher Inhalte, wie zum Beispiel Bestellungen oder Anfragen, die Sie an uns als Seitenbetreiber senden, eine + SSL- bzw. TLS-Verschlüsselung. Eine verschlüsselte Verbindung erkennen Sie daran, dass die Adresszeile des + Browsers von „http://“ auf „https://“ wechselt und an dem Schloss-Symbol in Ihrer + Browserzeile. +

+

+ Wenn die SSL- bzw. TLS-Verschlüsselung aktiviert ist, können die Daten, die Sie an + uns übermitteln, nicht von Dritten mitgelesen werden. +

+ +

Auskunft, Löschung und Berichtigung

+

+ Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen + jederzeit das Recht auf unentgeltliche Auskunft über Ihre gespeicherten personenbezogenen Daten, deren Herkunft + und Empfänger und den Zweck der Datenverarbeitung und ggf. ein Recht auf Berichtigung oder Löschung dieser + Daten. Hierzu sowie zu weiteren Fragen zum Thema personenbezogene Daten können Sie sich jederzeit an uns + wenden. +

+

Recht auf Einschränkung der Verarbeitung

+

+ Sie haben das Recht, die Einschränkung der Verarbeitung + Ihrer personenbezogenen Daten zu verlangen. Hierzu können Sie sich jederzeit an uns wenden. Das Recht auf + Einschränkung der Verarbeitung besteht in folgenden Fällen: +

+
    +
  • + Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen Daten bestreiten, benötigen wir in + der Regel Zeit, um dies zu überprüfen. Für die Dauer der Prüfung haben Sie das Recht, die + Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. +
  • +
  • + Wenn die Verarbeitung Ihrer personenbezogenen Daten unrechtmäßig geschah/geschieht, können Sie + statt der Löschung die Einschränkung der Datenverarbeitung verlangen. +
  • +
  • + Wenn wir Ihre personenbezogenen Daten nicht mehr benötigen, Sie sie jedoch zur Ausübung, Verteidigung + oder Geltendmachung von Rechtsansprüchen benötigen, haben Sie das Recht, statt der Löschung die + Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. +
  • +
  • + Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben, muss eine Abwägung zwischen Ihren und + unseren Interessen vorgenommen werden. Solange noch nicht feststeht, wessen Interessen überwiegen, haben + Sie das Recht, die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. +
  • +
+

+ Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten eingeschränkt haben, dürfen diese Daten + – von ihrer Speicherung abgesehen – nur mit Ihrer Einwilligung oder zur Geltendmachung, Ausübung + oder Verteidigung von Rechtsansprüchen oder zum Schutz der Rechte einer anderen natürlichen oder + juristischen Person oder aus Gründen eines wichtigen öffentlichen Interesses der Europäischen Union + oder eines Mitgliedstaats verarbeitet werden. +

+ +

4. Datenerfassung auf dieser Website

+

Cookies

+

+ Unsere Internetseiten verwenden so genannte „Cookies“. Cookies sind kleine Textdateien + und richten auf Ihrem Endgerät keinen Schaden an. Sie werden entweder vorübergehend für die Dauer + einer Sitzung (Session-Cookies) oder dauerhaft (permanente Cookies) auf Ihrem Endgerät gespeichert. + Session-Cookies werden nach Ende Ihres Besuchs automatisch gelöscht. Permanente Cookies bleiben auf Ihrem + Endgerät gespeichert, bis Sie diese selbst löschen oder eine automatische Löschung durch Ihren + Webbrowser erfolgt. +

+

+ Teilweise können auch Cookies von Drittunternehmen auf Ihrem Endgerät + gespeichert werden, wenn Sie unsere Seite betreten (Third-Party-Cookies). Diese ermöglichen uns oder Ihnen die + Nutzung bestimmter Dienstleistungen des Drittunternehmens (z.B. Cookies zur Abwicklung von + Zahlungsdienstleistungen). +

+

+ Cookies haben verschiedene Funktionen. Zahlreiche Cookies sind technisch + notwendig, da bestimmte Websitefunktionen ohne diese nicht funktionieren würden (z.B. die Warenkorbfunktion + oder die Anzeige von Videos). Andere Cookies dienen dazu, das Nutzerverhalten auszuwerten oder Werbung + anzuzeigen. +

+

+ Cookies, die zur Durchführung des elektronischen Kommunikationsvorgangs (notwendige Cookies) + oder zur Bereitstellung bestimmter, von Ihnen erwünschter Funktionen (funktionale Cookies, z. B. für die + Warenkorbfunktion) oder zur Optimierung der Website (z.B. Cookies zur Messung des Webpublikums) erforderlich sind, + werden auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO gespeichert, sofern keine andere Rechtsgrundlage angegeben wird. + Der Websitebetreiber hat ein berechtigtes Interesse an der Speicherung von Cookies zur technisch fehlerfreien und + optimierten Bereitstellung seiner Dienste. Sofern eine Einwilligung zur Speicherung von Cookies abgefragt wurde, + erfolgt die Speicherung der betreffenden Cookies ausschließlich auf Grundlage dieser Einwilligung (Art. 6 Abs. + 1 lit. a DSGVO); die Einwilligung ist jederzeit widerrufbar. +

+

+ Sie können Ihren Browser so einstellen, + dass Sie über das Setzen von Cookies informiert werden und Cookies nur im Einzelfall erlauben, die Annahme von + Cookies für bestimmte Fälle oder generell ausschließen sowie das automatische Löschen der + Cookies beim Schließen des Browsers aktivieren. Bei der Deaktivierung von Cookies kann die Funktionalität + dieser Website eingeschränkt sein. +

+

+ Soweit Cookies von Drittunternehmen oder zu Analysezwecken eingesetzt + werden, werden wir Sie hierüber im Rahmen dieser Datenschutzerklärung gesondert informieren und ggf. eine + Einwilligung abfragen. +

+ +

Server-Log-Dateien

+

+ Der Provider der Seiten erhebt und speichert automatisch Informationen in so genannten + Server-Log-Dateien, die Ihr Browser automatisch an uns übermittelt. Dies sind: +

+
    +
  • Browsertyp und Browserversion
  • +
  • verwendetes Betriebssystem
  • +
  • Referrer URL
  • +
  • Hostname des zugreifenden Rechners
  • +
  • Uhrzeit der Serveranfrage
  • +
  • IP-Adresse
  • +
+

+ Eine Zusammenführung dieser Daten mit anderen Datenquellen wird nicht vorgenommen. +

+

+ Die Erfassung + dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Der Websitebetreiber hat ein berechtigtes + Interesse an der technisch fehlerfreien Darstellung und der Optimierung seiner Website – hierzu müssen + die Server-Log-Files erfasst werden. +

+ +

Kontaktformular

+

+ Wenn Sie uns per Kontaktformular Anfragen zukommen lassen, werden Ihre Angaben aus dem + Anfrageformular inklusive der von Ihnen dort angegebenen Kontaktdaten zwecks Bearbeitung der Anfrage und für + den Fall von Anschlussfragen bei uns gespeichert. Diese Daten geben wir nicht ohne Ihre Einwilligung weiter. +

+

+ Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO, sofern Ihre Anfrage mit der Erfüllung + eines Vertrags zusammenhängt oder zur Durchführung vorvertraglicher Maßnahmen erforderlich ist. In + allen übrigen Fällen beruht die Verarbeitung auf unserem berechtigten Interesse an der effektiven + Bearbeitung der an uns gerichteten Anfragen (Art. 6 Abs. 1 lit. f DSGVO) oder auf Ihrer Einwilligung (Art. 6 Abs. 1 + lit. a DSGVO) sofern diese abgefragt wurde. +

+

+ Die von Ihnen im Kontaktformular eingegebenen Daten verbleiben + bei uns, bis Sie uns zur Löschung auffordern, Ihre Einwilligung zur Speicherung widerrufen oder der Zweck für + die Datenspeicherung entfällt (z. B. nach abgeschlossener Bearbeitung Ihrer Anfrage). Zwingende + gesetzliche Bestimmungen – insbesondere Aufbewahrungsfristen – bleiben unberührt. +

+ +

Anfrage per E-Mail, Telefon oder Telefax

+

+ Wenn Sie uns per E-Mail, Telefon oder Telefax kontaktieren, wird + Ihre Anfrage inklusive aller daraus hervorgehenden personenbezogenen Daten (Name, Anfrage) zum Zwecke der + Bearbeitung Ihres Anliegens bei uns gespeichert und verarbeitet. Diese Daten geben wir nicht ohne Ihre Einwilligung + weiter. +

+

+ Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO, sofern Ihre + Anfrage mit der Erfüllung eines Vertrags zusammenhängt oder zur Durchführung vorvertraglicher Maßnahmen + erforderlich ist. In allen übrigen Fällen beruht die Verarbeitung auf unserem berechtigten Interesse an + der effektiven Bearbeitung der an uns gerichteten Anfragen (Art. 6 Abs. 1 lit. f DSGVO) oder auf Ihrer Einwilligung + (Art. 6 Abs. 1 lit. a DSGVO) sofern diese abgefragt wurde. +

+

+ Die von Ihnen an uns per Kontaktanfragen übersandten + Daten verbleiben bei uns, bis Sie uns zur Löschung auffordern, Ihre Einwilligung zur Speicherung widerrufen + oder der Zweck für die Datenspeicherung entfällt (z. B. nach abgeschlossener Bearbeitung Ihres + Anliegens). Zwingende gesetzliche Bestimmungen – insbesondere gesetzliche Aufbewahrungsfristen – bleiben + unberührt. +

+ +

5. Plugins und Tools

+

Google Web Fonts

+

+ Diese Seite nutzt zur einheitlichen Darstellung von Schriftarten so genannte Web Fonts, die + von Google bereitgestellt werden. Beim Aufruf einer Seite lädt Ihr Browser die benötigten Web Fonts in + ihren Browsercache, um Texte und Schriftarten korrekt anzuzeigen. +

+

+ Zu diesem Zweck muss der von Ihnen + verwendete Browser Verbindung zu den Servern von Google aufnehmen. Hierdurch erlangt Google Kenntnis darüber, + dass über Ihre IP-Adresse diese Website aufgerufen wurde. Die Nutzung von Google WebFonts erfolgt auf Grundlage + von Art. 6 Abs. 1 lit. f DSGVO. Der Websitebetreiber hat ein berechtigtes Interesse an der einheitlichen Darstellung + des Schriftbildes auf seiner Website. Sofern eine entsprechende Einwilligung abgefragt wurde (z. B. eine + Einwilligung zur Speicherung von Cookies), erfolgt die Verarbeitung ausschließlich auf Grundlage von Art. 6 + Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit widerrufbar. +

+

+ Wenn Ihr Browser Web Fonts nicht unterstützt, + wird eine Standardschrift von Ihrem Computer genutzt. +

+

+ Weitere Informationen zu Google Web Fonts finden Sie + unter https://developers.google.com/fonts/faq + und in der Datenschutzerklärung von Google: https://policies.google.com/privacy?hl=de. +

+ +

Font Awesome

+

+ Diese Seite nutzt zur einheitlichen Darstellung von Schriftarten und Symbolen Font Awesome. + Anbieter ist die Fonticons, Inc., 6 Porter Road Apartment 3R, Cambridge, Massachusetts, USA. +

+

+ Beim Aufruf + einer Seite lädt Ihr Browser die benötigten Fonts in ihren Browsercache, um Texte, Schriftarten und + Symbole korrekt anzuzeigen. Zu diesem Zweck muss der von Ihnen verwendete Browser Verbindung zu den Servern von Font + Awesome aufnehmen. Hierdurch erlangt Font Awesome Kenntnis darüber, dass über Ihre IP-Adresse diese + Website aufgerufen wurde. Die Nutzung von Font Awesome erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Wir + haben ein berechtigtes Interesse an der einheitlichen Darstellung des Schriftbildes auf unserer Website. Sofern eine + entsprechende Einwilligung abgefragt wurde (z. B. eine Einwilligung zur Speicherung von Cookies), erfolgt die + Verarbeitung ausschließlich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit + widerrufbar. +

+

+ Wenn Ihr Browser Font Awesome nicht unterstützt, wird eine Standardschrift von Ihrem + Computer genutzt. +

+

+ Weitere Informationen zu Font Awesome finden Sie und in der Datenschutzerklärung + von Font Awesome unter: https://fontawesome.com/privacy. +

+
+ diff --git a/Frontend/src/app/pages/privacy/privacy.component.spec.ts b/Frontend/src/app/pages/privacy/privacy.component.spec.ts new file mode 100644 index 0000000..ea1b059 --- /dev/null +++ b/Frontend/src/app/pages/privacy/privacy.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PrivacyComponent } from './privacy.component'; + +describe('PrivacyComponent', () => { + let component: PrivacyComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ PrivacyComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PrivacyComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Frontend/src/app/pages/privacy/privacy.component.ts b/Frontend/src/app/pages/privacy/privacy.component.ts new file mode 100644 index 0000000..9e4ed50 --- /dev/null +++ b/Frontend/src/app/pages/privacy/privacy.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-privacy', + templateUrl: './privacy.component.html', + styleUrls: ['./privacy.component.css'] +}) +export class PrivacyComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} From 30f613c18ae67ef7a3283884a12f7cf03d1b23a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20M=C3=BCller?= Date: Mon, 5 Apr 2021 13:40:55 +0200 Subject: [PATCH 5/6] BETTERZON-53: Styling clickable stuff on hover --- Frontend/src/app/components/header/header.component.css | 8 ++++++++ .../product-details/product-details.component.css | 5 +++++ .../components/product-list/product-list.component.css | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/Frontend/src/app/components/header/header.component.css b/Frontend/src/app/components/header/header.component.css index e3147c8..126040f 100644 --- a/Frontend/src/app/components/header/header.component.css +++ b/Frontend/src/app/components/header/header.component.css @@ -15,6 +15,10 @@ margin-left: 50%; } +.logo:hover { + cursor: pointer; +} + .searchBox { position: relative; margin: auto; @@ -36,6 +40,10 @@ margin-left: 10%; } +.profileIcon:hover { + cursor: pointer; +} + .icon-3d { padding: 10px; color: #fff; diff --git a/Frontend/src/app/components/product-details/product-details.component.css b/Frontend/src/app/components/product-details/product-details.component.css index 42dfa5b..cf2533f 100644 --- a/Frontend/src/app/components/product-details/product-details.component.css +++ b/Frontend/src/app/components/product-details/product-details.component.css @@ -81,3 +81,8 @@ margin-top: .5em; text-align: center; } + +.priceAlarm:hover { + background-color: lightgray; + cursor: pointer; +} diff --git a/Frontend/src/app/components/product-list/product-list.component.css b/Frontend/src/app/components/product-list/product-list.component.css index d80c1f5..d5eb76c 100644 --- a/Frontend/src/app/components/product-list/product-list.component.css +++ b/Frontend/src/app/components/product-list/product-list.component.css @@ -53,3 +53,8 @@ .productDescription { grid-area: description; } + +.productItem:hover { + background-color: lightgray; + cursor: pointer; +} From 1b1cdb59f6d9cb2a342bb647e03efdd60c7ee8de Mon Sep 17 00:00:00 2001 From: Patrick <50352812+Mueller-Patrick@users.noreply.github.com> Date: Mon, 5 Apr 2021 16:34:11 +0200 Subject: [PATCH 6/6] BETTERZON-48: Adding API functionality to get best available deals (#20) --- Backend/src/models/prices/price.interface.ts | 3 + Backend/src/models/prices/prices.router.ts | 23 ++++- Backend/src/models/prices/prices.service.ts | 94 ++++++++++++++++++++ 3 files changed, 118 insertions(+), 2 deletions(-) diff --git a/Backend/src/models/prices/price.interface.ts b/Backend/src/models/prices/price.interface.ts index 49030e8..956c9d5 100644 --- a/Backend/src/models/prices/price.interface.ts +++ b/Backend/src/models/prices/price.interface.ts @@ -4,4 +4,7 @@ export interface Price { vendor_id: number; price_in_cents: number; timestamp: Date; + // Only for deals + amazonDifference?: number; + amazonDifferencePercent?: number; } diff --git a/Backend/src/models/prices/prices.router.ts b/Backend/src/models/prices/prices.router.ts index 9672efa..889f817 100644 --- a/Backend/src/models/prices/prices.router.ts +++ b/Backend/src/models/prices/prices.router.ts @@ -19,7 +19,7 @@ export const pricesRouter = express.Router(); * Controller Definitions */ -// GET items/ +// GET prices/ pricesRouter.get('/', async (req: Request, res: Response) => { try { @@ -44,7 +44,7 @@ pricesRouter.get('/', async (req: Request, res: Response) => { } }); -// GET items/:id +// GET prices/:id pricesRouter.get('/:id', async (req: Request, res: Response) => { const id: number = parseInt(req.params.id, 10); @@ -63,6 +63,25 @@ pricesRouter.get('/:id', async (req: Request, res: Response) => { } }); +// GET prices/bestDeals + +pricesRouter.get('/bestDeals/:amount', async (req: Request, res: Response) => { + const amount: number = parseInt(req.params.amount, 10); + + if (!amount) { + res.status(400).send('Missing parameters.'); + return; + } + + try { + const prices: Prices = await PriceService.getBestDeals(amount); + + res.status(200).send(prices); + } catch (e) { + res.status(404).send(e.message); + } +}); + // POST items/ // pricesRouter.post('/', async (req: Request, res: Response) => { diff --git a/Backend/src/models/prices/prices.service.ts b/Backend/src/models/prices/prices.service.ts index b0a8038..b639db8 100644 --- a/Backend/src/models/prices/prices.service.ts +++ b/Backend/src/models/prices/prices.service.ts @@ -186,6 +186,100 @@ export const findByVendor = async (product: string, vendor: string, type: string return priceRows; }; +export const getBestDeals = async (amount: number): Promise => { + let conn; + let priceRows = []; + try { + conn = await pool.getConnection(); + + let allPrices: Record = {}; + + // Get newest prices for every product at every vendor + + const rows = await conn.query( + 'WITH summary AS (\n' + + ' SELECT p.product_id,\n' + + ' p.vendor_id,\n' + + ' p.price_in_cents,\n' + + ' p.timestamp,\n' + + ' 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' + + 'SELECT s.*\n' + + 'FROM summary s\n' + + 'WHERE s.rk = 1'); + + // Write returned values to allPrices map with product id as key and a list of prices as value + for (let row in rows) { + if (row !== 'meta') { + if (!allPrices[parseInt(rows[row].product_id)]) { + allPrices[parseInt(rows[row].product_id)] = []; + } + + allPrices[parseInt(rows[row].product_id)].push(rows[row]); + } + } + + // Iterate over all prices to find the products with the biggest difference between amazon and other vendor + let deals = []; + for (let productId in Object.keys(allPrices)) { + if (allPrices[productId]) { + let pricesForProd = allPrices[productId]; + + // Get amazon price and lowest price from other vendor + let amazonPrice = {} as Price; + let lowestPrice = {} as Price; + pricesForProd.forEach(function(price, priceIndex) { + if (price.vendor_id === 1) { + amazonPrice = price; + } else { + if (!lowestPrice.price_in_cents || lowestPrice.price_in_cents > price.price_in_cents) { + lowestPrice = price; + } + } + }); + + // Create deal object and add it to list + let deal = { + 'product_id': lowestPrice.product_id, + 'vendor_id': lowestPrice.vendor_id, + 'price_in_cents': lowestPrice.price_in_cents, + 'timestamp' :lowestPrice.timestamp, + 'amazonDifference': (amazonPrice.price_in_cents - lowestPrice.price_in_cents), + 'amazonDifferencePercent': ((1 - (lowestPrice.price_in_cents / amazonPrice.price_in_cents)) * 100), + }; + + // Push only deals were the amazon price is actually higher + if(deal.amazonDifferencePercent > 0) { + deals.push(deal); + } + } + } + + // Sort to have the best deals on the top + deals.sort((a, b) => a.amazonDifferencePercent < b.amazonDifferencePercent ? 1 : -1); + + // Return only as many records as requested or the maximum amount of found deals, whatever is less + let maxAmt = Math.min(amount, deals.length); + + for (let dealIndex = 0; dealIndex < maxAmt; dealIndex++){ + //console.log(deals[dealIndex]); + priceRows.push(deals[dealIndex] as Price); + } + + } catch (err) { + console.log(err); + throw err; + } finally { + if (conn) { + conn.end(); + } + } + + return priceRows; +}; + // export const create = async (newItem: Product): Promise => { // let conn; // try {