Merge remote-tracking branch 'origin/develop' into BETTERZON-31

# Conflicts:
#	Frontend/src/app/app.module.ts
This commit is contained in:
Patrick Müller 2021-04-06 20:19:40 +02:00
commit 64074b48e8
25 changed files with 752 additions and 13 deletions

1
.gitignore vendored
View File

@ -26,6 +26,7 @@ speed-measure-plugin*.json
!Frontend.iml
!Backend.iml
!CucumberTests.iml
!Crawler.iml
# Include IntelliJ modules
!/.idea/modules.xml

View File

@ -4,6 +4,7 @@
<modules>
<module fileurl="file://$PROJECT_DIR$/Backend/Backend.iml" filepath="$PROJECT_DIR$/Backend/Backend.iml" />
<module fileurl="file://$PROJECT_DIR$/Betterzon.iml" filepath="$PROJECT_DIR$/Betterzon.iml" />
<module fileurl="file://$PROJECT_DIR$/Crawler/Crawler.iml" filepath="$PROJECT_DIR$/Crawler/Crawler.iml" />
<module fileurl="file://$PROJECT_DIR$/CucumberTests/CucumberTests.iml" filepath="$PROJECT_DIR$/CucumberTests/CucumberTests.iml" />
<module fileurl="file://$PROJECT_DIR$/Frontend/Frontend.iml" filepath="$PROJECT_DIR$/Frontend/Frontend.iml" />
</modules>

View File

@ -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;

View File

@ -4,4 +4,7 @@ export interface Price {
vendor_id: number;
price_in_cents: number;
timestamp: Date;
// Only for deals
amazonDifference?: number;
amazonDifferencePercent?: number;
}

View File

@ -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) => {

View File

@ -186,6 +186,100 @@ export const findByVendor = async (product: string, vendor: string, type: string
return priceRows;
};
export const getBestDeals = async (amount: number): Promise<Prices> => {
let conn;
let priceRows = [];
try {
conn = await pool.getConnection();
let allPrices: Record<number, Price[]> = {};
// 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<void> => {
// let conn;
// try {

View File

@ -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/

8
Crawler/Crawler.iml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

1
Crawler/requirements.txt Normal file
View File

@ -0,0 +1 @@
pymysql

View File

@ -17,6 +17,8 @@ import {FormsModule} from '@angular/forms';
import {PageNotFoundPageComponent} from './pages/page-not-found-page/page-not-found-page.component';
import {MatMenuModule} from '@angular/material/menu';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ImprintComponent } from './pages/imprint/imprint.component';
import { PrivacyComponent } from './pages/privacy/privacy.component';
@NgModule({
declarations: [
@ -29,7 +31,9 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
ProductSearchPageComponent,
HeaderComponent,
NewestPricesListComponent,
PageNotFoundPageComponent
PageNotFoundPageComponent,
ImprintComponent,
PrivacyComponent
],
imports: [
BrowserModule,

View File

@ -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}
];

View File

@ -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;
}

View File

@ -3,7 +3,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<footer class="footer">
<div class='wrap'>
<div class='wrap' id="footer-icons">
<div class="icons">
<a href="https://github.com/Mueller-Patrick/Betterzon" class="fa fa-github fa-4x icon-3d"></a>
<a href="https://twitter.com/elonmusk" class="fa fa-twitter fa-4x icon-3d"></a>
@ -11,4 +11,8 @@
</div>
<div class = "blocks" id="copyright">© COPYRIGHT 2020</div>
</div>
<div id="imprintSection">
<a href="/impressum" >Imprint</a><br>
<a href="/datenschutz">Privacy Policy</a>
</div>
</footer>

View File

@ -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/')]);
}
}

View File

@ -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;

View File

@ -81,3 +81,8 @@
margin-top: .5em;
text-align: center;
}
.priceAlarm:hover {
background-color: lightgray;
cursor: pointer;
}

View File

@ -53,3 +53,8 @@
.productDescription {
grid-area: description;
}
.productItem:hover {
background-color: lightgray;
cursor: pointer;
}

View File

@ -0,0 +1,4 @@
#imprint {
padding-left: 5em;
padding-right: 5em;
}

View File

@ -0,0 +1,59 @@
<app-header [showSearch]="true"></app-header>
<div id="imprint">
<h1>Impressum</h1>
<h2>Angaben gem&auml;&szlig; &sect; 5 TMG</h2>
<p>
Patrick Müller<br/>
Schachtstraße 8<br/>
75031 Eppingen
</p>
<h2>Kontakt</h2>
<p>
E-Mail: betterzon-contact@mueller-patrick.tech
</p>
<h3>Haftung f&uuml;r Inhalte</h3>
<p>
Als Diensteanbieter sind wir gem&auml;&szlig; &sect; 7 Abs.1 TMG f&uuml;r eigene
Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach &sect;&sect; 8 bis 10 TMG sind wir als
Diensteanbieter jedoch nicht verpflichtet, &uuml;bermittelte oder gespeicherte fremde Informationen zu &uuml;berwachen
oder nach Umst&auml;nden zu forschen, die auf eine rechtswidrige T&auml;tigkeit hinweisen.
</p>
<p>
Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben
hiervon unber&uuml;hrt.
Eine diesbez&uuml;gliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung m&ouml;glich.
Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.
</p>
<h3>Haftung f&uuml;r Links</h3>
<p>
Unser Angebot enth&auml;lt Links zu externen Websites Dritter, auf deren Inhalte wir keinen
Einfluss haben. Deshalb k&ouml;nnen wir f&uuml;r diese fremden Inhalte auch keine Gew&auml;hr &uuml;bernehmen. F&uuml;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&ouml;gliche Rechtsverst&ouml;&szlig;e &uuml;berpr&uuml;ft.
Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar.
</p>
<p>
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.
</p>
<h3>Urheberrecht</h3>
<p>
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht.
Die Vervielf&auml;ltigung, Bearbeitung, Verbreitung und jede Art der Verwertung au&szlig;erhalb der Grenzen des
Urheberrechtes bed&uuml;rfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und
Kopien dieser Seite sind nur f&uuml;r den privaten, nicht kommerziellen Gebrauch gestattet.
</p>
<p>
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.
</p>
</div>
<app-footer></app-footer>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ImprintComponent } from './imprint.component';
describe('ImprintComponent', () => {
let component: ImprintComponent;
let fixture: ComponentFixture<ImprintComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ImprintComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ImprintComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -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 {
}
}

View File

@ -0,0 +1,4 @@
#privacy {
padding-left: 5em;
padding-right: 5em;
}

View File

@ -0,0 +1,408 @@
<app-header [showSearch]="true"></app-header>
<div id="privacy">
<h1>Datenschutz&shy;erkl&auml;rung</h1>
<h2>1. Datenschutz auf einen Blick</h2>
<h3>Allgemeine Hinweise</h3>
<p>
Die folgenden Hinweise geben einen einfachen &Uuml;berblick dar&uuml;ber, was mit Ihren
personenbezogenen Daten passiert, wenn Sie diese Website besuchen. Personenbezogene Daten sind alle Daten, mit denen
Sie pers&ouml;nlich identifiziert werden k&ouml;nnen. Ausf&uuml;hrliche Informationen zum Thema Datenschutz
entnehmen Sie unserer unter diesem Text aufgef&uuml;hrten Datenschutzerkl&auml;rung.
</p>
<h3>Datenerfassung auf dieser Website</h3>
<h4>Wer ist verantwortlich f&uuml;r die Datenerfassung auf dieser Website?</h4>
<p>
Die Datenverarbeitung auf dieser Website erfolgt durch den Websitebetreiber. Dessen Kontaktdaten k&ouml;nnen
Sie dem Abschnitt &bdquo;Hinweis zur Verantwortlichen Stelle&ldquo; in dieser Datenschutzerkl&auml;rung
entnehmen.
</p>
<h4>Wie erfassen wir Ihre Daten?</h4>
<p>
Ihre Daten werden zum einen dadurch erhoben, dass Sie uns
diese mitteilen. Hierbei kann es sich z.&nbsp;B. um Daten handeln, die Sie in ein Kontaktformular eingeben.
</p>
<p>
Andere Daten werden automatisch oder nach Ihrer Einwilligung beim Besuch der Website durch unsere IT-Systeme
erfasst. Das sind vor allem technische Daten (z.&nbsp;B. Internetbrowser, Betriebssystem oder Uhrzeit des
Seitenaufrufs). Die Erfassung dieser Daten erfolgt automatisch, sobald Sie diese Website betreten.
</p>
<h4>Wof&uuml;r nutzen wir Ihre Daten?</h4>
<p>
Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der Website zu
gew&auml;hrleisten. Andere Daten k&ouml;nnen zur Analyse Ihres Nutzerverhaltens verwendet werden.
</p>
<h4>Welche Rechte haben Sie bez&uuml;glich Ihrer Daten?</h4>
<p>
Sie haben jederzeit das Recht, unentgeltlich Auskunft &uuml;ber
Herkunft, Empf&auml;nger und Zweck Ihrer gespeicherten personenbezogenen Daten zu erhalten. Sie haben au&szlig;erdem
ein Recht, die Berichtigung oder L&ouml;schung dieser Daten zu verlangen. Wenn Sie eine Einwilligung zur
Datenverarbeitung erteilt haben, k&ouml;nnen Sie diese Einwilligung jederzeit f&uuml;r die Zukunft widerrufen. Au&szlig;erdem
haben Sie das Recht, unter bestimmten Umst&auml;nden die Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen
Daten zu verlangen. Des Weiteren steht Ihnen ein Beschwerderecht bei der zust&auml;ndigen Aufsichtsbeh&ouml;rde
zu.
</p>
<p>
Hierzu sowie zu weiteren Fragen zum Thema Datenschutz k&ouml;nnen Sie sich jederzeit an uns wenden.
</p>
<h2>2. Hosting und Content Delivery Networks (CDN)</h2>
<h3>Externes Hosting</h3>
<p>
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 &uuml;ber eine Website generiert werden, handeln.
</p>
<p>
Der Einsatz des Hosters erfolgt zum Zwecke der Vertragserf&uuml;llung gegen&uuml;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).
</p>
<p>
Unser Hoster wird Ihre Daten nur insoweit verarbeiten, wie dies zur Erf&uuml;llung seiner Leistungspflichten
erforderlich ist und unsere Weisungen in Bezug auf diese Daten befolgen.
</p>
<p>
Wir setzen folgenden Hoster ein:
</p>
<p>
netcup GmbH<br/>
Daimlerstra&szlig;e 25<br/>
76185 Karlsruhe
</p>
<h4>Abschluss eines Vertrages &uuml;ber Auftragsverarbeitung</h4>
<p>
Um die datenschutzkonforme Verarbeitung zu gew&auml;hrleisten,
haben wir einen Vertrag &uuml;ber Auftragsverarbeitung mit unserem Hoster geschlossen.
</p>
<h2>3. Allgemeine Hinweise und Pflicht&shy;informationen</h2>
<h3>Datenschutz</h3>
<p>
Die Betreiber dieser Seiten nehmen den Schutz Ihrer pers&ouml;nlichen Daten sehr ernst. Wir
behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie
dieser Datenschutzerkl&auml;rung.
</p>
<p>
Wenn Sie diese Website benutzen, werden verschiedene personenbezogene Daten
erhoben. Personenbezogene Daten sind Daten, mit denen Sie pers&ouml;nlich identifiziert werden k&ouml;nnen. Die
vorliegende Datenschutzerkl&auml;rung erl&auml;utert, welche Daten wir erheben und wof&uuml;r wir sie nutzen. Sie
erl&auml;utert auch, wie und zu welchem Zweck das geschieht.
</p>
<p>
Wir weisen darauf hin, dass die Daten&uuml;bertragung
im Internet (z.&nbsp;B. bei der Kommunikation per E-Mail) Sicherheitsl&uuml;cken aufweisen kann. Ein l&uuml;ckenloser
Schutz der Daten vor dem Zugriff durch Dritte ist nicht m&ouml;glich.
</p>
<h3>Hinweis zur verantwortlichen Stelle</h3>
<p>
Die verantwortliche Stelle f&uuml;r die Datenverarbeitung auf dieser
Website ist:
</p>
<p>
Patrick Müller<br/>
Schachtstraße 8<br/>
75031 Eppingen
</p>
<p>
E-Mail: betterzon-privacy@mueller-patrick.tech
</p>
<p>
Verantwortliche Stelle ist die nat&uuml;rliche oder juristische Person, die allein oder gemeinsam mit anderen &uuml;ber
die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten (z.&nbsp;B. Namen, E-Mail-Adressen o. &Auml;.)
entscheidet.
</p>
<h3>Speicherdauer</h3>
<p>
Soweit innerhalb dieser Datenschutzerkl&auml;rung keine speziellere Speicherdauer genannt
wurde, verbleiben Ihre personenbezogenen Daten bei uns, bis der Zweck f&uuml;r die Datenverarbeitung entf&auml;llt.
Wenn Sie ein berechtigtes L&ouml;schersuchen geltend machen oder eine Einwilligung zur Datenverarbeitung widerrufen,
werden Ihre Daten gel&ouml;scht, sofern wir keine anderen rechtlich zul&auml;ssigen Gr&uuml;nde f&uuml;r die
Speicherung Ihrer personenbezogenen Daten haben (z.B. steuer- oder handelsrechtliche Aufbewahrungsfristen); im
letztgenannten Fall erfolgt die L&ouml;schung nach Fortfall dieser Gr&uuml;nde.
</p>
<h3>Hinweis zur Datenweitergabe in die USA und sonstige Drittstaaten</h3>
<p>
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&ouml;nnen Ihre personenbezogene Daten in diese Drittstaaten &uuml;bertragen
und dort verarbeitet werden. Wir weisen darauf hin, dass in diesen L&auml;ndern kein mit der EU vergleichbares
Datenschutzniveau garantiert werden kann. Beispielsweise sind US-Unternehmen dazu verpflichtet, personenbezogene
Daten an Sicherheitsbeh&ouml;rden herauszugeben, ohne dass Sie als Betroffener hiergegen gerichtlich vorgehen k&ouml;nnten.
Es kann daher nicht ausgeschlossen werden, dass US-Beh&ouml;rden (z.B. Geheimdienste) Ihre auf US-Servern
befindlichen Daten zu &Uuml;berwachungszwecken verarbeiten, auswerten und dauerhaft speichern. Wir haben auf diese
Verarbeitungst&auml;tigkeiten keinen Einfluss.
</p>
<h3>Widerruf Ihrer Einwilligung zur Datenverarbeitung</h3>
<p>
Viele Datenverarbeitungsvorg&auml;nge sind nur mit Ihrer ausdr&uuml;cklichen Einwilligung m&ouml;glich. Sie k&ouml;nnen
eine bereits erteilte Einwilligung jederzeit widerrufen. Die Rechtm&auml;&szlig;igkeit der bis zum Widerruf
erfolgten Datenverarbeitung bleibt vom Widerruf unber&uuml;hrt.
</p>
<h3>Widerspruchsrecht gegen die Datenerhebung in besonderen F&auml;llen sowie gegen Direktwerbung (Art. 21 DSGVO)</h3>
<p>
WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F DSGVO ERFOLGT, HABEN SIE JEDERZEIT DAS
RECHT, AUS GR&Uuml;NDEN, DIE SICH AUS IHRER BESONDEREN SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER
PERSONENBEZOGENEN DATEN WIDERSPRUCH EINZULEGEN; DIES GILT AUCH F&Uuml;R EIN AUF DIESE BESTIMMUNGEN GEST&Uuml;TZTES
PROFILING. DIE JEWEILIGE RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE DIESER DATENSCHUTZERKL&Auml;RUNG.
WENN SIE WIDERSPRUCH EINLEGEN, WERDEN WIR IHRE BETROFFENEN PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES SEI
DENN, WIR K&Ouml;NNEN ZWINGENDE SCHUTZW&Uuml;RDIGE GR&Uuml;NDE F&Uuml;R DIE VERARBEITUNG NACHWEISEN, DIE IHRE
INTERESSEN, RECHTE UND FREIHEITEN &Uuml;BERWIEGEN ODER DIE VERARBEITUNG DIENT DER GELTENDMACHUNG, AUS&Uuml;BUNG ODER
VERTEIDIGUNG VON RECHTSANSPR&Uuml;CHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO).
</p>
<p>
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&Uuml;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).
</p>
<h3>Beschwerde&shy;recht bei der zust&auml;ndigen Aufsichts&shy;beh&ouml;rde</h3>
<p>
Im Falle von Verst&ouml;&szlig;en
gegen die DSGVO steht den Betroffenen ein Beschwerderecht bei einer Aufsichtsbeh&ouml;rde, insbesondere in dem
Mitgliedstaat ihres gew&ouml;hnlichen Aufenthalts, ihres Arbeitsplatzes oder des Orts des mutma&szlig;lichen Versto&szlig;es
zu. Das Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher oder gerichtlicher
Rechtsbehelfe.
</p>
<h3>Recht auf Daten&shy;&uuml;bertrag&shy;barkeit</h3>
<p>
Sie haben das Recht, Daten, die wir auf Grundlage Ihrer
Einwilligung oder in Erf&uuml;llung eines Vertrags automatisiert verarbeiten, an sich oder an einen Dritten in einem
g&auml;ngigen, maschinenlesbaren Format aush&auml;ndigen zu lassen. Sofern Sie die direkte &Uuml;bertragung der
Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur, soweit es technisch machbar ist.
</p>
<h3>SSL- bzw. TLS-Verschl&uuml;sselung</h3>
<p>
Diese Seite nutzt aus Sicherheitsgr&uuml;nden und zum Schutz der &Uuml;bertragung
vertraulicher Inhalte, wie zum Beispiel Bestellungen oder Anfragen, die Sie an uns als Seitenbetreiber senden, eine
SSL- bzw. TLS-Verschl&uuml;sselung. Eine verschl&uuml;sselte Verbindung erkennen Sie daran, dass die Adresszeile des
Browsers von &bdquo;http://&ldquo; auf &bdquo;https://&ldquo; wechselt und an dem Schloss-Symbol in Ihrer
Browserzeile.
</p>
<p>
Wenn die SSL- bzw. TLS-Verschl&uuml;sselung aktiviert ist, k&ouml;nnen die Daten, die Sie an
uns &uuml;bermitteln, nicht von Dritten mitgelesen werden.
</p>
<h3>Auskunft, L&ouml;schung und Berichtigung</h3>
<p>
Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen
jederzeit das Recht auf unentgeltliche Auskunft &uuml;ber Ihre gespeicherten personenbezogenen Daten, deren Herkunft
und Empf&auml;nger und den Zweck der Datenverarbeitung und ggf. ein Recht auf Berichtigung oder L&ouml;schung dieser
Daten. Hierzu sowie zu weiteren Fragen zum Thema personenbezogene Daten k&ouml;nnen Sie sich jederzeit an uns
wenden.
</p>
<h3>Recht auf Einschr&auml;nkung der Verarbeitung</h3>
<p>
Sie haben das Recht, die Einschr&auml;nkung der Verarbeitung
Ihrer personenbezogenen Daten zu verlangen. Hierzu k&ouml;nnen Sie sich jederzeit an uns wenden. Das Recht auf
Einschr&auml;nkung der Verarbeitung besteht in folgenden F&auml;llen:
</p>
<ul>
<li>
Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen Daten bestreiten, ben&ouml;tigen wir in
der Regel Zeit, um dies zu &uuml;berpr&uuml;fen. F&uuml;r die Dauer der Pr&uuml;fung haben Sie das Recht, die
Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li>
<li>
Wenn die Verarbeitung Ihrer personenbezogenen Daten unrechtm&auml;&szlig;ig geschah/geschieht, k&ouml;nnen Sie
statt der L&ouml;schung die Einschr&auml;nkung der Datenverarbeitung verlangen.
</li>
<li>
Wenn wir Ihre personenbezogenen Daten nicht mehr ben&ouml;tigen, Sie sie jedoch zur Aus&uuml;bung, Verteidigung
oder Geltendmachung von Rechtsanspr&uuml;chen ben&ouml;tigen, haben Sie das Recht, statt der L&ouml;schung die
Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li>
<li>
Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben, muss eine Abw&auml;gung zwischen Ihren und
unseren Interessen vorgenommen werden. Solange noch nicht feststeht, wessen Interessen &uuml;berwiegen, haben
Sie das Recht, die Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li>
</ul>
<p>
Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten eingeschr&auml;nkt haben, d&uuml;rfen diese Daten
&ndash; von ihrer Speicherung abgesehen &ndash; nur mit Ihrer Einwilligung oder zur Geltendmachung, Aus&uuml;bung
oder Verteidigung von Rechtsanspr&uuml;chen oder zum Schutz der Rechte einer anderen nat&uuml;rlichen oder
juristischen Person oder aus Gr&uuml;nden eines wichtigen &ouml;ffentlichen Interesses der Europ&auml;ischen Union
oder eines Mitgliedstaats verarbeitet werden.
</p>
<h2>4. Datenerfassung auf dieser Website</h2>
<h3>Cookies</h3>
<p>
Unsere Internetseiten verwenden so genannte &bdquo;Cookies&ldquo;. Cookies sind kleine Textdateien
und richten auf Ihrem Endger&auml;t keinen Schaden an. Sie werden entweder vor&uuml;bergehend f&uuml;r die Dauer
einer Sitzung (Session-Cookies) oder dauerhaft (permanente Cookies) auf Ihrem Endger&auml;t gespeichert.
Session-Cookies werden nach Ende Ihres Besuchs automatisch gel&ouml;scht. Permanente Cookies bleiben auf Ihrem
Endger&auml;t gespeichert, bis Sie diese selbst l&ouml;schen&nbsp;oder eine automatische L&ouml;schung durch Ihren
Webbrowser erfolgt.
</p>
<p>
Teilweise k&ouml;nnen auch Cookies von Drittunternehmen auf Ihrem Endger&auml;t
gespeichert werden, wenn Sie unsere Seite betreten (Third-Party-Cookies). Diese erm&ouml;glichen uns oder Ihnen die
Nutzung bestimmter Dienstleistungen des Drittunternehmens (z.B. Cookies zur Abwicklung von
Zahlungsdienstleistungen).
</p>
<p>
Cookies haben verschiedene Funktionen. Zahlreiche Cookies sind technisch
notwendig, da bestimmte Websitefunktionen ohne diese nicht funktionieren w&uuml;rden (z.B. die Warenkorbfunktion
oder die Anzeige von Videos). Andere Cookies dienen dazu, das Nutzerverhalten auszuwerten&nbsp;oder Werbung
anzuzeigen.
</p>
<p>
Cookies, die zur Durchf&uuml;hrung des elektronischen Kommunikationsvorgangs (notwendige Cookies)
oder zur Bereitstellung bestimmter, von Ihnen erw&uuml;nschter Funktionen (funktionale Cookies, z. B. f&uuml;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&szlig;lich auf Grundlage dieser Einwilligung (Art. 6 Abs.
1 lit. a DSGVO); die Einwilligung ist jederzeit widerrufbar.
</p>
<p>
Sie k&ouml;nnen Ihren Browser so einstellen,
dass Sie &uuml;ber das Setzen von Cookies informiert werden und Cookies nur im Einzelfall erlauben, die Annahme von
Cookies f&uuml;r bestimmte F&auml;lle oder generell ausschlie&szlig;en sowie das automatische L&ouml;schen der
Cookies beim Schlie&szlig;en des Browsers aktivieren. Bei der Deaktivierung von Cookies kann die Funktionalit&auml;t
dieser Website eingeschr&auml;nkt sein.
</p>
<p>
Soweit Cookies von Drittunternehmen oder zu Analysezwecken eingesetzt
werden, werden wir Sie hier&uuml;ber im Rahmen dieser Datenschutzerkl&auml;rung gesondert informieren und ggf. eine
Einwilligung abfragen.
</p>
<h3>Server-Log-Dateien</h3>
<p>
Der Provider der Seiten erhebt und speichert automatisch Informationen in so genannten
Server-Log-Dateien, die Ihr Browser automatisch an uns &uuml;bermittelt. Dies sind:
</p>
<ul>
<li>Browsertyp und Browserversion</li>
<li>verwendetes Betriebssystem</li>
<li>Referrer URL</li>
<li>Hostname des zugreifenden Rechners</li>
<li>Uhrzeit der Serveranfrage</li>
<li>IP-Adresse</li>
</ul>
<p>
Eine Zusammenf&uuml;hrung dieser Daten mit anderen Datenquellen wird nicht vorgenommen.
</p>
<p>
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 &ndash; hierzu m&uuml;ssen
die Server-Log-Files erfasst werden.
</p>
<h3>Kontaktformular</h3>
<p>
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&uuml;r
den Fall von Anschlussfragen bei uns gespeichert. Diese Daten geben wir nicht ohne Ihre Einwilligung weiter.
</p>
<p>
Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO, sofern Ihre Anfrage mit der Erf&uuml;llung
eines Vertrags zusammenh&auml;ngt oder zur Durchf&uuml;hrung vorvertraglicher Ma&szlig;nahmen erforderlich ist. In
allen &uuml;brigen F&auml;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.
</p>
<p>
Die von Ihnen im Kontaktformular eingegebenen Daten verbleiben
bei uns, bis Sie uns zur L&ouml;schung auffordern, Ihre Einwilligung zur Speicherung widerrufen oder der Zweck f&uuml;r
die Datenspeicherung entf&auml;llt (z.&nbsp;B. nach abgeschlossener Bearbeitung Ihrer Anfrage). Zwingende
gesetzliche Bestimmungen &ndash; insbesondere Aufbewahrungsfristen &ndash; bleiben unber&uuml;hrt.
</p>
<h3>Anfrage per E-Mail, Telefon oder Telefax</h3>
<p>
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.
</p>
<p>
Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO, sofern Ihre
Anfrage mit der Erf&uuml;llung eines Vertrags zusammenh&auml;ngt oder zur Durchf&uuml;hrung vorvertraglicher Ma&szlig;nahmen
erforderlich ist. In allen &uuml;brigen F&auml;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.
</p>
<p>
Die von Ihnen an uns per Kontaktanfragen &uuml;bersandten
Daten verbleiben bei uns, bis Sie uns zur L&ouml;schung auffordern, Ihre Einwilligung zur Speicherung widerrufen
oder der Zweck f&uuml;r die Datenspeicherung entf&auml;llt (z.&nbsp;B. nach abgeschlossener Bearbeitung Ihres
Anliegens). Zwingende gesetzliche Bestimmungen &ndash; insbesondere gesetzliche Aufbewahrungsfristen &ndash; bleiben
unber&uuml;hrt.
</p>
<h2>5. Plugins und Tools</h2>
<h3>Google Web Fonts</h3>
<p>
Diese Seite nutzt zur einheitlichen Darstellung von Schriftarten so genannte Web Fonts, die
von Google bereitgestellt werden. Beim Aufruf einer Seite l&auml;dt Ihr Browser die ben&ouml;tigten Web Fonts in
ihren Browsercache, um Texte und Schriftarten korrekt anzuzeigen.
</p>
<p>
Zu diesem Zweck muss der von Ihnen
verwendete Browser Verbindung zu den Servern von Google aufnehmen. Hierdurch erlangt Google Kenntnis dar&uuml;ber,
dass &uuml;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&szlig;lich auf Grundlage von Art. 6
Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit widerrufbar.
</p>
<p>
Wenn Ihr Browser Web Fonts nicht unterst&uuml;tzt,
wird eine Standardschrift von Ihrem Computer genutzt.
</p>
<p>
Weitere Informationen zu Google Web Fonts finden Sie
unter <a href="https://developers.google.com/fonts/faq" target="_blank" rel="noopener noreferrer">https://developers.google.com/fonts/faq</a>
und in der Datenschutzerkl&auml;rung von Google: <a href="https://policies.google.com/privacy?hl=de" target="_blank"
rel="noopener noreferrer">https://policies.google.com/privacy?hl=de</a>.
</p>
<h3>Font Awesome</h3>
<p>
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.
</p>
<p>
Beim Aufruf
einer Seite l&auml;dt Ihr Browser die ben&ouml;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&uuml;ber, dass &uuml;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&szlig;lich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit
widerrufbar.
</p>
<p>
Wenn Ihr Browser Font Awesome nicht unterst&uuml;tzt, wird eine Standardschrift von Ihrem
Computer genutzt.
</p>
<p>
Weitere Informationen zu Font Awesome finden Sie&nbsp;und in der Datenschutzerkl&auml;rung
von Font Awesome unter: <a href="https://fontawesome.com/privacy" target="_blank" rel="noopener noreferrer">https://fontawesome.com/privacy</a>.
</p>
</div>
<app-footer></app-footer>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PrivacyComponent } from './privacy.component';
describe('PrivacyComponent', () => {
let component: PrivacyComponent;
let fixture: ComponentFixture<PrivacyComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PrivacyComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PrivacyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -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 {
}
}