Further modified wireframes and removed old components

This commit is contained in:
Martin 2021-04-29 22:30:29 +02:00
parent df192617a2
commit 7dd3232139
18 changed files with 174 additions and 175 deletions

View File

@ -5,6 +5,7 @@ import {LoginComponent} from './component/login/login.component';
import {TweetsComponent} from './component/tweets/tweets.component'; import {TweetsComponent} from './component/tweets/tweets.component';
import {EinstellungenComponent} from './component/einstellungen/einstellungen.component'; import {EinstellungenComponent} from './component/einstellungen/einstellungen.component';
import {UnAuthGuardService} from './services/un-auth-guard.service'; import {UnAuthGuardService} from './services/un-auth-guard.service';
import {EditierenComponent} from './component/einstellungen/editieren/editieren.component';
const routes: Routes = [ const routes: Routes = [
{ {
@ -27,6 +28,16 @@ const routes: Routes = [
component: EinstellungenComponent, component: EinstellungenComponent,
canActivate: [AuthGuardService] canActivate: [AuthGuardService]
}, },
{
path: 'einstellungen/editieren',
component: EditierenComponent,
canActivate: [AuthGuardService]
},
{
path: 'einstellungen/editieren/:id',
component: EditierenComponent,
canActivate: [AuthGuardService]
},
]; ];
@NgModule({ @NgModule({

View File

@ -7,7 +7,6 @@ import {RestService} from './services/rest.service';
import {HttpClientModule} from '@angular/common/http'; import {HttpClientModule} from '@angular/common/http';
import {LoggerModule, NgxLoggerLevel} from 'ngx-logger'; import {LoggerModule, NgxLoggerLevel} from 'ngx-logger';
import {environment} from '../environments/environment'; import {environment} from '../environments/environment';
import {TestSubCompComponent} from './component/testsubcomp/test-sub-comp.component';
import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatFormFieldModule} from '@angular/material/form-field'; import {MatFormFieldModule} from '@angular/material/form-field';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@ -16,7 +15,6 @@ import {MatInputModule} from '@angular/material/input';
import {MatSlideToggleModule} from '@angular/material/slide-toggle'; import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {MatSliderModule} from '@angular/material/slider'; import {MatSliderModule} from '@angular/material/slider';
import {LoginComponent} from './component/login/login.component'; import {LoginComponent} from './component/login/login.component';
import {HomeComponent} from './component/home/home.component';
import { AuthGuardService } from './services/auth-guard.service'; import { AuthGuardService } from './services/auth-guard.service';
import { AuthService } from './services/auth.service'; import { AuthService } from './services/auth.service';
import {JwtHelper} from 'angular2-jwt'; import {JwtHelper} from 'angular2-jwt';
@ -28,10 +26,11 @@ import { EinstellungenComponent } from './component/einstellungen/einstellungen.
import { NavigationComponent } from './component/navigation/navigation.component'; import { NavigationComponent } from './component/navigation/navigation.component';
import {MatSnackBarModule} from '@angular/material/snack-bar'; import {MatSnackBarModule} from '@angular/material/snack-bar';
import {MatCheckboxModule} from '@angular/material/checkbox'; import {MatCheckboxModule} from '@angular/material/checkbox';
import { EditierenComponent } from './component/einstellungen/editieren/editieren.component';
@NgModule({ @NgModule({
declarations: [LandingComponent, TestSubCompComponent, LoginComponent, declarations: [LandingComponent, LoginComponent, NavigationComponent,
HomeComponent, TweetsComponent, EinstellungenComponent, NavigationComponent], TweetsComponent, EinstellungenComponent, EditierenComponent],
imports: [ imports: [
ReactiveFormsModule, ReactiveFormsModule,
BrowserModule, BrowserModule,

View File

@ -0,0 +1,27 @@
.input {
width: 100%;
}
.input-row {
display: block;
padding: 10px 0;
}
.einstellungen_buttons_wrapper {
width: fit-content;
display: grid;
grid-auto-flow: column;
grid-column-gap: 10px;
}
.feed-icon {
width: 75%;
max-width: 5em;
}
.feed-list-row {
padding: 10px 0;
margin-left: auto;
margin-right: auto;
max-width: 800px;
}

View File

@ -0,0 +1,35 @@
<app-navigation [activeLink]="'settings'"></app-navigation>
<div class="content">
<div class="text-center">
<p class="font-weight-bold">RSS-Feed erstellen</p>
<div class="input-row">
<mat-form-field appearance="standard" class="input">
<mat-label>Vollständige URL des RSS-Feeds:</mat-label>
<input matInput placeholder="https://rss.orf.at/news.xml">
</mat-form-field>
</div>
<div class="input-row text-left">
<mat-form-field appearance="standard" class="input">
<mat-label>Folgende Stichwörter im Feed suchen:</mat-label>
<input matInput placeholder="Spiel, Spaß, Schokolade">
</mat-form-field>
<mat-checkbox>Alle Stichworte müssen enthalten sein</mat-checkbox>
</div>
<div class="input-row text-left">
<span>Optionales Icon:</span>
<br>
<img (click)="iconChooser()" class="feed-icon" src="{{icon}}" alt="Feed-Icon">
<input hidden type="file"
(change)="fileChangeEvent($event)"
id="feed-icon-picker" name="icon"
accept="image/png, image/svg+xml">
</div>
<div class="input-row text-left">
<mat-slide-toggle color="primary">Slide me!</mat-slide-toggle>
</div>
<div class="input-row margin-auto einstellungen_buttons_wrapper">
<button routerLink="/einstellungen" mat-raised-button>Abbrechen</button>
<button mat-raised-button><mat-icon>save</mat-icon> Speichern</button>
</div>
</div>
</div>

View File

@ -0,0 +1,54 @@
import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-editieren',
templateUrl: './editieren.component.html',
styleUrls: ['./editieren.component.css']
})
export class EditierenComponent implements OnInit {
icon;
id;
constructor(private route: ActivatedRoute) {
this.icon = 'assets/logo.svg';
this.route.paramMap.subscribe( paramMap => {
this.id = paramMap.get('id');
if (this.id) {
this.loadFeed(this.id);
}
});
}
ngOnInit(): void {
}
loadFeed(id) {
// TODO: direkt vor laden alle inputs deaktivieren (od hiden) und erst nach fertigem laden wieder entsperren
// TODO: load feed from backend and fill
console.log('TODO: Load feed settings with id ' + id);
}
// TODO: bei Input-Words die Leerzeichen vor- und nach dem letzten Zeichen entfernen: " Formel 1 " wird zu "Formel 1"
iconChooser() {
document.getElementById('feed-icon-picker').click();
}
fileChangeEvent(event) {
if (event && event.target) {
const files = event.target.files;
if (files && files[0]) {
const reader = new FileReader();
reader.onload = () => {
if (reader.result) {
this.icon = reader.result;
}
};
reader.readAsDataURL(files[0]);
}
}
}
}

View File

@ -1,33 +1,5 @@
<app-navigation [activeLink]="'settings'"></app-navigation> <app-navigation [activeLink]="'settings'"></app-navigation>
<div class="content"> <div class="content">
<div class="text-center">
<p class="font-weight-bold">RSS-Feed erstellen</p>
<div class="input-row">
<mat-form-field appearance="standard" class="input">
<mat-label>Vollständige URL des RSS-Feeds:</mat-label>
<input matInput placeholder="https://rss.orf.at/news.xml">
</mat-form-field>
</div>
<div class="input-row text-left">
<mat-form-field appearance="standard" class="input">
<mat-label>Folgende Stichwörter im Feed suchen:</mat-label>
<input matInput placeholder="Spiel, Spaß, Schokolade">
</mat-form-field>
<mat-checkbox>Alle Stichworte müssen enthalten sein</mat-checkbox>
</div>
<div class="input-row text-left">
<span>Optionales Icon:</span>
<br>
HIER ICON-PICKER EINFÜGEN!
</div>
<div class="input-row text-left">
<mat-slide-toggle color="primary">Slide me!</mat-slide-toggle>
</div>
<div class="input-row margin-auto einstellungen_buttons_wrapper">
<button mat-raised-button>Abbrechen</button>
<button mat-raised-button><mat-icon>save</mat-icon> Speichern</button>
</div>
</div>
<div class="text-center"> <div class="text-center">
<div class="container" *ngFor="let number of [1, 2, 3]"> <div class="container" *ngFor="let number of [1, 2, 3]">
<div class="row feed-list-row"> <div class="row feed-list-row">
@ -38,7 +10,7 @@
<span class="overflow-break">https://rss.orf.at/news.xml</span> <span class="overflow-break">https://rss.orf.at/news.xml</span>
</div> </div>
<div class="col-1 padding-0 margin-auto"> <div class="col-1 padding-0 margin-auto">
<button mat-icon-button> <button mat-icon-button routerLink="/einstellungen/editieren/{{number}}">
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
</div> </div>
@ -50,7 +22,9 @@
</div> </div>
</div> </div>
<div class="input-row margin-auto einstellungen_buttons_wrapper"> <div class="input-row margin-auto einstellungen_buttons_wrapper">
<button mat-raised-button><mat-icon>add</mat-icon> RSS-Feed hinzufügen</button> <button routerLink="/einstellungen/editieren" mat-raised-button>
<mat-icon>add</mat-icon> RSS-Feed hinzufügen
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -7,11 +7,12 @@ import { Component, OnInit } from '@angular/core';
}) })
export class EinstellungenComponent implements OnInit { export class EinstellungenComponent implements OnInit {
constructor() { } icon;
constructor() {
this.icon = 'assets/logo.svg';
}
ngOnInit(): void { ngOnInit(): void {
} }
// TODO: bei Input-Words die Leerzeichen vor- und nach dem letzten Zeichen entfernen: " Formel 1 " wird zu "Formel 1"
} }

View File

@ -1,19 +0,0 @@
<p>home works!</p>
<a href="http://localhost:4200/">
<button (click)="logout()">Logout</button>
</a>
<a href="http://localhost:4200/">bye</a>
<br>
<button (click)="paramsFromUrl()">Get Params from URL</button>
<br>
<button (click)="gotoBackend()">Call Backend</button>
<br>
<label>
Token:
<input type="text" [(ngModel)]="id_token">
</label>
<br>
<label>
State:
<input type="text" [(ngModel)]="state">
</label>

View File

@ -1,65 +0,0 @@
import {Component, OnInit} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Router} from '@angular/router';
import {environment} from '../../../environments/environment';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
openid_endpoint = environment.openid_endpoint;
id_token = 'x';
state = 'y';
parsedToken;
constructor(private http: HttpClient, private router: Router) {
// TODO: DELETE COMPONENT
}
ngOnInit(): void {
this.paramsFromUrl();
}
logout() {
const headerDict = {
'Accept': '*/*',
'Access-Control-Allow-Origin': '*'
};
this.http.get(this.openid_endpoint + '/logout?' +
'id_token_hint=' + this.id_token + '&\n' +
'post_logout_redirect_uri=http://localhost:4200&\n' +
'state=' + this.state,
{
headers: new HttpHeaders(headerDict),
responseType: 'text'
}).subscribe(() => this.router.navigate(['login']));
}
gotoBackend() {
const headerDict = {
'Authorization': 'Bearer ' + this.id_token
};
this.http.get('http://localhost:8000/api/login',
{
headers: new HttpHeaders(headerDict)
})
.subscribe(data => console.log(data));
}
paramsFromUrl() {
const url = window.location.href;
const params: string = url.split('#')[1];
this.state = params.split('&')[0].split('session_state=')[1];
this.id_token = params.split('&')[1].split('id_token=')[1];
try {
this.parsedToken = JSON.parse(atob(this.id_token.split('.')[1]));
} catch (e) {
console.log(e);
}
}
}

View File

@ -1,9 +1,9 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http'; import {HttpClient} from '@angular/common/http';
import {ActivatedRoute, Router} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {AuthService} from '../../services/auth.service'; import {AuthService} from '../../services/auth.service';
import {environment} from '../../../environments/environment'; import {environment} from '../../../environments/environment';
import {MatSnackBar} from '@angular/material/snack-bar'; import {SnackbarService} from '../../services/snackbar.service';
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
@ -21,7 +21,7 @@ export class LoginComponent implements OnInit {
private router: Router, private router: Router,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private authService: AuthService, private authService: AuthService,
private snackBar: MatSnackBar) { private snackbar: SnackbarService) {
} }
ngOnInit(): void { ngOnInit(): void {
@ -31,16 +31,18 @@ export class LoginComponent implements OnInit {
element => { element => {
const split = element.split('='); const split = element.split('=');
if (split[0] === 'error') { if (split[0] === 'error') {
this.snackBar.open(split[1], 'Schließen', { this.snackbar.show(split[1], 'Schließen', 5000);
duration: 5000,
});
return; return;
} }
if (split[0] === 'id_token') { if (split[0] === 'id_token') {
this.id_token = split[1]; this.id_token = split[1];
this.parsedToken = JSON.parse(atob(this.id_token.split('.')[1])); this.parsedToken = JSON.parse(atob(this.id_token.split('.')[1]));
const nonce = sessionStorage.getItem('nonce');
if (nonce && nonce === this.parsedToken.nonce) {
this.authService.setToken(this.id_token); this.authService.setToken(this.id_token);
this.gotoBackend(); } else {
this.snackbar.show('Fehler bei der Anmeldung', 'Schließen', 5000);
}
} else if (split[0] === 'state') { } else if (split[0] === 'state') {
this.state = split[1]; this.state = split[1];
} }
@ -54,13 +56,15 @@ export class LoginComponent implements OnInit {
} }
login() { login() {
const nonce = this.randomString(20);
sessionStorage.setItem('nonce', nonce);
const url = this.openid_endpoint + '/auth?' + const url = this.openid_endpoint + '/auth?' +
'client_id=waecm' + 'client_id=waecm' +
'&response_type=id_token' + '&response_type=id_token' +
'&prompt=consent' + '&prompt=consent' +
'&redirect_uri=' + environment.location + '&redirect_uri=' + environment.location +
'&scope=openid%20profile' + '&scope=openid%20profile' +
'&nonce=' + this.randomString(20); '&nonce=' + nonce;
window.location.replace(url); window.location.replace(url);
} }
@ -72,17 +76,4 @@ export class LoginComponent implements OnInit {
} }
return text; return text;
} }
gotoBackend() {
// TODO: Remove
const headerDict = {
'Authorization': 'Bearer ' + this.id_token,
};
return this.http.get('http://localhost:8000/api/login',
{
headers: new HttpHeaders(headerDict),
observe: 'response',
})
.subscribe(data => alert('Returned with code: ' + data['status']));
}
} }

View File

@ -1,3 +0,0 @@
<p>{{message}}
<button mat-raised-button (click)="buttonClickedEvent.emit()">Click me</button>
</p>

View File

@ -1,24 +0,0 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
@Component({
selector: 'app-test-sub-comp',
templateUrl: './test-sub-comp.component.html',
styleUrls: ['./test-sub-comp.component.css'],
})
export class TestSubCompComponent implements OnInit {
@Input()
message: string;
@Input()
anotherInput: string;
@Output()
buttonClickedEvent: EventEmitter<void> = new EventEmitter<void>();
constructor() {
}
ngOnInit(): void {
// this.message;
}
}

View File

@ -3,7 +3,7 @@
<div class="text-center"> <div class="text-center">
<span>Kein RSS_Feed vorhanden</span> <span>Kein RSS_Feed vorhanden</span>
<br> <br>
<span><a routerLink="/einstellungen">RSS-Feed erstellen</a></span> <span><a routerLink="/einstellungen/editieren">RSS-Feed erstellen</a></span>
</div> </div>
<div class="text-center"> <div class="text-center">
<span>Kein Tweets vorhanden</span> <span>Kein Tweets vorhanden</span>

View File

@ -20,6 +20,7 @@ export class AuthService {
public deleteToken(): void { public deleteToken(): void {
sessionStorage.removeItem(this.tokenKey); sessionStorage.removeItem(this.tokenKey);
sessionStorage.removeItem('nonce');
} }
public getToken(): string { public getToken(): string {

View File

@ -3,6 +3,7 @@ import {Injectable} from '@angular/core';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {tap} from 'rxjs/operators'; import {tap} from 'rxjs/operators';
import {NGXLogger} from 'ngx-logger'; import {NGXLogger} from 'ngx-logger';
import {AuthService} from './auth.service';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -12,7 +13,7 @@ import {NGXLogger} from 'ngx-logger';
*/ */
export class InterceptorService implements HttpInterceptor { export class InterceptorService implements HttpInterceptor {
constructor(private logger: NGXLogger) { constructor(private logger: NGXLogger, private authService: AuthService) {
} }
/** /**
@ -21,8 +22,8 @@ export class InterceptorService implements HttpInterceptor {
* @param next http response handler * @param next http response handler
*/ */
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// TODO get the real token
const token = 'A_TOKEN'; const token = this.authService.getToken();
// the original request is immutable, so we need to clone it // the original request is immutable, so we need to clone it
req = req.clone({ req = req.clone({

View File

@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import {MatSnackBar} from '@angular/material/snack-bar';
@Injectable({
providedIn: 'root'
})
export class SnackbarService {
constructor(private snackBar: MatSnackBar) { }
show(message, button, duration: number = 5000) {
this.snackBar.open(message, button, {
duration: duration,
});
}
}