Merge remote-tracking branch 'origin/master'

This commit is contained in:
Marco Zeisler 2021-05-03 17:37:53 +02:00
commit 22a3493905
10 changed files with 67 additions and 55 deletions

2
backend/.gitignore vendored
View File

@ -1,7 +1,7 @@
venv venv
*.pyc *.pyc
staticfiles staticfiles
media media/feed-icons
.env .env
*.sqlite3 *.sqlite3
*.sqlite *.sqlite

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -9,7 +9,7 @@ class User(models.Model):
class Feed(models.Model): class Feed(models.Model):
url = models.TextField(blank=False, null=False, validators=[URLValidator(['http', 'https'])]) url = models.TextField(blank=False, null=False, validators=[URLValidator(['http', 'https'])])
active = models.BooleanField() active = models.BooleanField()
icon = models.FileField(upload_to='feed-icons', blank=True, null=True, icon = models.FileField(upload_to='feed-icons', blank=True, null=False, default='default-icon.svg',
validators=[FileExtensionValidator(['png', 'svg'])]) validators=[FileExtensionValidator(['png', 'svg'])])
keywords = models.TextField(blank=False, null=False) keywords = models.TextField(blank=False, null=False)
match_all_keywords = models.BooleanField(blank=True, default=False) match_all_keywords = models.BooleanField(blank=True, default=False)

View File

@ -3,6 +3,6 @@
<p>{{data.body}}</p> <p>{{data.body}}</p>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions mat-dialog-actions align="end"> <mat-dialog-actions mat-dialog-actions align="end">
<button mat-raised-button color="primary" [mat-dialog-close]="true">{{data.confirm}}</button>
<button *ngIf="data.hideAbort === false" mat-raised-button mat-dialog-close color="warn">{{data.abort}}</button> <button *ngIf="data.hideAbort === false" mat-raised-button mat-dialog-close color="warn">{{data.abort}}</button>
<button mat-raised-button color="primary" [mat-dialog-close]="true">{{data.confirm}}</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -35,7 +35,7 @@ export class EditierenComponent implements OnInit {
private http: HttpClient, private http: HttpClient,
private _snackbar: MatSnackBar, private _snackbar: MatSnackBar,
private _logger: NGXLogger, private _logger: NGXLogger,
private _dialog: MatDialog) { ) {
this.route.paramMap.subscribe(paramMap => { this.route.paramMap.subscribe(paramMap => {
this.id = paramMap.get('id'); this.id = paramMap.get('id');
if (this.id) { if (this.id) {
@ -105,25 +105,4 @@ export class EditierenComponent implements OnInit {
); );
} }
} }
public saveDialog(feedData) {
const dialogRef = this._dialog.open(DialogComponent, {
data: {
title: 'Neuen Feed erstellen',
body: 'Neuen Feed erstellen?',
abort: 'Abbrechen',
confirm: 'OK',
hideAbort: false
}
});
dialogRef.afterClosed().subscribe(
data => {
if (data === true) {
// Confirm button was clicked
this.saveFeed(feedData);
}
}
);
}
} }

View File

@ -15,13 +15,13 @@
</button> </button>
</div> </div>
<div class="col-1 padding-0 margin-auto"> <div class="col-1 padding-0 margin-auto">
<button mat-icon-button (click)="deleteFeed(feed.id)"> <button mat-icon-button (click)="deleteDialog(feed.id)">
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<div class="input-row margin-auto einstellungen_buttons_wrapper"> <div class="input-row margin-auto einstellungen_buttons_wrapper" *ngIf="this.feeds.length < 3">
<button routerLink="/einstellungen/editieren" mat-raised-button> <button routerLink="/einstellungen/editieren" mat-raised-button>
<mat-icon>add</mat-icon> RSS-Feed hinzufügen <mat-icon>add</mat-icon> RSS-Feed hinzufügen
</button> </button>

View File

@ -1,11 +1,13 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {HttpClient} from '@angular/common/http'; import {HttpClient} from '@angular/common/http';
import {Observable, throwError} from 'rxjs'; import {throwError} from 'rxjs';
import {MatSnackBar} from '@angular/material/snack-bar'; import {MatSnackBar} from '@angular/material/snack-bar';
import {NGXLogger} from 'ngx-logger'; import {NGXLogger} from 'ngx-logger';
import {IFeed} from '../../interfaces/feed.interface'; import {IFeed} from '../../interfaces/feed.interface';
import {FeedService} from '../../services/feed.service'; import {FeedService} from '../../services/feed.service';
import {ActivatedRoute, NavigationEnd, Router} from '@angular/router'; import {ActivatedRoute} from '@angular/router';
import {DialogComponent} from '../dialog/dialog.component';
import {MatDialog} from '@angular/material/dialog';
@Component({ @Component({
selector: 'app-einstellungen', selector: 'app-einstellungen',
@ -16,29 +18,16 @@ export class EinstellungenComponent implements OnInit {
icon; icon;
feeds: Observable<IFeed[]>; feeds: IFeed[] = [];
mySubscription;
constructor(private http: HttpClient, constructor(private http: HttpClient,
private _snackbar: MatSnackBar, private _snackbar: MatSnackBar,
private _logger: NGXLogger, private _logger: NGXLogger,
private _feedService: FeedService, private _feedService: FeedService,
private _route: ActivatedRoute, private _route: ActivatedRoute,
private _router: Router) { private _dialog: MatDialog) {
this.icon = 'assets/logo.svg'; this.icon = 'assets/logo.svg';
this._router.routeReuseStrategy.shouldReuseRoute = () => false; this._feedService.getFeeds().toPromise().then(data => this.feeds = data).catch(err => this._logger.error(err));
this.mySubscription = this._router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
// Trick the Router into believing it's last link wasn't previously loaded
this._router.navigated = false;
}
});
this._feedService.getFeeds().subscribe(
(data: any) => {
this.feeds = data;
}
);
} }
ngOnInit(): void { ngOnInit(): void {
@ -48,12 +37,33 @@ export class EinstellungenComponent implements OnInit {
this.http.delete('http://127.0.0.1:8000/feeds/' + id + '/').subscribe( this.http.delete('http://127.0.0.1:8000/feeds/' + id + '/').subscribe(
() => { () => {
this._snackbar.open('Feed erfolgreich gelöscht!', 'Schließen', {duration: 3000}); this._snackbar.open('Feed erfolgreich gelöscht!', 'Schließen', {duration: 3000});
this.feeds = this.feeds.filter(feed => feed.id !== id);
}, },
err => { err => {
this._logger.error(err); this._logger.error(err);
return throwError(err); return throwError(err);
} }
); );
this._router.navigate([this._router.url]); }
public deleteDialog(id: number) {
const dialogRef = this._dialog.open(DialogComponent, {
data: {
title: 'Feed löschen',
body: 'Feed wirklich löschen?',
abort: 'Abbrechen',
confirm: 'OK',
hideAbort: false
}
});
dialogRef.afterClosed().subscribe(
data => {
if (data === true) {
// Confirm button was clicked
this.deleteFeed(id);
}
}
);
} }
} }

View File

@ -1,16 +1,16 @@
<app-navigation [activeLink]="'tweets'"></app-navigation> <app-navigation [activeLink]="'tweets'"></app-navigation>
<div class="content"> <div class="content">
<div class="text-center"> <div class="text-center" *ngIf="feeds.length === 0">
<span>Kein RSS_Feed vorhanden</span> <span>Kein RSS-Feed vorhanden</span>
<br> <br>
<span><a routerLink="/einstellungen/editieren">RSS-Feed erstellen</a></span> <a routerLink="/einstellungen/editieren">RSS-Feed erstellen</a>
</div> </div>
<div class="text-center"> <div class="text-center" *ngIf="feeds.length !== 0">
<span>Kein Tweets vorhanden</span> <span>Keine Tweets vorhanden</span>
<br> <br>
<span>Schau später noch einmal vorbei!</span> <span>Schau später noch einmal vorbei!</span>
</div> </div>
<div> <div *ngIf="feeds.length !== 0">
<div> <div>
<div class="container" *ngFor="let number of [1, 2, 3]"> <div class="container" *ngFor="let number of [1, 2, 3]">
<div class="row"> <div class="row">

View File

@ -1,6 +1,9 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {AuthService} from '../../services/auth.service'; import {AuthService} from '../../services/auth.service';
import {HttpClient, HttpHeaders} from '@angular/common/http'; import {HttpClient, HttpHeaders} from '@angular/common/http';
import {FeedService} from '../../services/feed.service';
import {IFeed} from '../../interfaces/feed.interface';
import {Observable} from 'rxjs';
class Tweet { class Tweet {
@ -14,9 +17,16 @@ class Tweet {
export class TweetsComponent implements OnInit { export class TweetsComponent implements OnInit {
tweets: Tweet[] = []; tweets: Tweet[] = [];
feeds: Observable<IFeed>[] = [];
constructor(private http: HttpClient, constructor(private http: HttpClient,
private authService: AuthService) { private authService: AuthService,
private _feedService: FeedService) {
this._feedService.getFeeds().subscribe(
(data: any) => {
this.feeds = data;
}
);
} }
ngOnInit(): void { ngOnInit(): void {

View File

@ -1,6 +1,19 @@
import {AbstractControl} from '@angular/forms'; import {AbstractControl} from '@angular/forms';
export function keywordsValidator(control: AbstractControl): { [key: string]: any } | null { export function keywordsValidator(control: AbstractControl): { [key: string]: any } | null {
const valid = /^((\w){3,},?){1,2}(\w{3,})?$/.test(control.value); if (control.value == undefined) {
return valid ? null : {'invalidKeywords': {value: control.value}}; return null;
}
let split: string[];
split = control.value.split(',');
if (split.length > 3) {
return {'invalidKeywords': {value: control.value}};
}
for (let i = 0; i < split.length; i++) {
const word = split[i].trim();
if (word.length < 3) {
return {'invalidKeywords': {value: control.value}};
}
}
return null;
} }