Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
22a3493905
2
backend/.gitignore
vendored
2
backend/.gitignore
vendored
@ -1,7 +1,7 @@
|
|||||||
venv
|
venv
|
||||||
*.pyc
|
*.pyc
|
||||||
staticfiles
|
staticfiles
|
||||||
media
|
media/feed-icons
|
||||||
.env
|
.env
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
*.sqlite
|
*.sqlite
|
||||||
|
|||||||
BIN
backend/app_be/media/default-icon.svg
Normal file
BIN
backend/app_be/media/default-icon.svg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@ -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)
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user