1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2025-01-26 05:27:35 +02:00

Improving notification and CSRF error logging

This commit is contained in:
Patrik J. Braun 2020-12-27 18:57:02 +01:00
parent 3b82b71203
commit b37d4ec8c8
8 changed files with 87 additions and 21 deletions

View File

@ -105,7 +105,7 @@ export class RenderingMWs {
const message = new Message<any>(err, null);
return res.json(message);
}
NotificationManager.error('Unknown server error', err);
NotificationManager.error('Unknown server error', err, req);
return next(err);
}

View File

@ -1,4 +1,5 @@
import {NotificationDTO, NotificationType} from '../../common/entities/NotificationDTO';
import {Request} from 'express';
export class NotificationManager {
public static notifications: NotificationDTO[] = [];
@ -11,19 +12,35 @@ export class NotificationManager {
];
public static error(message: string, details?: any) {
NotificationManager.notifications.push({
public static error(message: string, details?: any, req?: Request) {
const noti: NotificationDTO = {
type: NotificationType.error,
message: message,
details: details
});
};
if (req) {
noti.request = {
method: req.method,
url: req.url,
statusCode: req.statusCode
};
}
NotificationManager.notifications.push(noti);
}
public static warning(message: string, details?: any) {
NotificationManager.notifications.push({
public static warning(message: string, details?: any, req?: Request) {
const noti: NotificationDTO = {
type: NotificationType.warning,
message: message,
details: details
});
};
if (req) {
noti.request = {
method: req.method,
url: req.url,
statusCode: req.statusCode
};
}
NotificationManager.notifications.push(noti);
}
}

View File

@ -24,11 +24,18 @@ export class ErrorRouter {
res.status(401);
return next(new ErrorDTO(ErrorCodes.NOT_AUTHENTICATED, 'Invalid token'));
}
if (err.name === 'ForbiddenError' && err.code === 'EBADCSRFTOKEN') {
// jwt authentication error
res.status(401);
return next(new ErrorDTO(ErrorCodes.NOT_AUTHENTICATED, 'Invalid CSRF token', err, req));
}
console.log(err);
// Flush out the stack to the console
Logger.error('Unexpected error:');
console.error(err);
return next(new ErrorDTO(ErrorCodes.SERVER_ERROR, 'Unknown server side error', err));
return next(new ErrorDTO(ErrorCodes.SERVER_ERROR, 'Unknown server side error', err, req));
},
RenderingMWs.renderError
);

View File

@ -1,3 +1,5 @@
import {Request} from 'express';
export enum ErrorCodes {
NOT_AUTHENTICATED = 1,
ALREADY_AUTHENTICATED = 2,
@ -25,9 +27,16 @@ export enum ErrorCodes {
export class ErrorDTO {
public detailsStr: string;
public request: {
method: string, url: string
} = {method: '', url: ''};
constructor(public code: ErrorCodes, public message?: string, public details?: any) {
constructor(public code: ErrorCodes, public message?: string, public details?: any, req?: Request) {
this.detailsStr = (this.details ? this.details.toString() : '') || ErrorCodes[code];
this.request = {
method: req.method,
url: req.url
};
}
toString(): string {

View File

@ -6,4 +6,9 @@ export interface NotificationDTO {
type: NotificationType;
message: string;
details?: any;
request?: {
method: string,
url: string,
statusCode: number
};
}

View File

@ -6,6 +6,10 @@ import {NotificationDTO, NotificationType} from '../../../common/entities/Notifi
import {UserDTO, UserRoles} from '../../../common/entities/UserDTO';
import {I18n} from '@ngx-translate/i18n-polyfill';
export interface CountedNotificationDTO extends NotificationDTO {
count: number;
}
@Injectable()
export class NotificationService {
@ -13,7 +17,8 @@ export class NotificationService {
positionClass: 'toast-top-center',
animate: 'flyLeft'
};
notifications: NotificationDTO[] = [];
countedNotifications: CountedNotificationDTO[] = [];
numberOfNotifications = 0;
lastUser: UserDTO = null;
constructor(private _toastr: ToastrService,
@ -36,11 +41,30 @@ export class NotificationService {
return this._toastr;
}
groupNotifications(notifications: NotificationDTO[]) {
const groups: { [key: string]: { notification: NotificationDTO, count: number } } = {};
notifications.forEach(n => {
let key = n.message;
if (n.details) {
key += JSON.stringify(n.details);
}
groups[key] = groups[key] || {notification: n, count: 0};
groups[key].count++;
});
this.numberOfNotifications = notifications.length;
this.countedNotifications = [];
for (const key of Object.keys(groups)) {
(groups[key].notification as CountedNotificationDTO).count = groups[key].count;
this.countedNotifications.push(groups[key].notification as CountedNotificationDTO);
}
}
async getServerNotifications() {
try {
this.notifications = (await this._networkService.getJson<NotificationDTO[]>('/notifications')) || [];
this.notifications.forEach((noti) => {
let msg = noti.message;
this.groupNotifications((await this._networkService.getJson<NotificationDTO[]>('/notifications')) || []);
this.countedNotifications.forEach((noti) => {
let msg = '(' + noti.count + ') ' + noti.message;
if (noti.details) {
msg += ' Details: ' + JSON.stringify(noti.details);
}

View File

@ -12,17 +12,21 @@
<app-frame>
<div body class="container-fluid">
<div class="card mb-4" *ngIf="notificationService.notifications.length>0">
<div class="card mb-4" *ngIf="notificationService.countedNotifications.length>0">
<h5 class="card-header" i18n>
Server notifications
</h5>
<div class="card-body">
<ng-container *ngFor="let notification of notificationService.notifications">
<ng-container *ngFor="let notification of notificationService.countedNotifications">
<div class="alert alert-{{getCss(notification.type)}}" role="alert">
{{notification.message}}
({{notification.count}}) {{notification.message}}
<br *ngIf="notification.details"/>
{{notification.details | json}}
<ng-container *ngIf="notification.request">
<br/>
Request: "{{notification.request.method}}", url: "{{notification.request.url}}", status code: "{{notification.request.statusCode}}"
</ng-container>
</div>
</ng-container>
</div>
@ -40,7 +44,7 @@
class="version"
href="https://github.com/bpatrik/pigallery2/releases">
<span
i18n>App version:</span>&nbsp;<span>{{'v'+((settingsService.settings | async).Server.Environment.appVersion || '----')}}</span>
i18n>App version:</span>&nbsp;<span>{{'v' + ((settingsService.settings | async).Server.Environment.appVersion || '----')}}</span>
</a>
</div>
<div class="form-group">

View File

@ -38,8 +38,8 @@
type="button" class="btn btn-dark dropdown-toggle"
aria-controls="dropdown-alignment">
<span class="oi oi-menu"></span>
<span *ngIf="isAdmin() && notificationService.notifications.length>0"
class="navbar-badge badge badge-warning">{{notificationService.notifications.length}}</span>
<span *ngIf="isAdmin() && notificationService.numberOfNotifications>0"
class="navbar-badge badge badge-warning">{{notificationService.numberOfNotifications}}</span>
</button>
<ul id="dropdown-alignment" *dropdownMenu
class="dropdown-menu dropdown-menu-right"
@ -54,8 +54,8 @@
<li role="menuitem" *ngIf="isAdmin()">
<a class="dropdown-item" [routerLink]="['/admin']">
<span class="oi oi-wrench"></span>
<span *ngIf="notificationService.notifications.length>0"
class="badge">{{notificationService.notifications.length}}</span>
<span *ngIf="notificationService.numberOfNotifications>0"
class="badge">{{notificationService.numberOfNotifications}}</span>
<ng-container i18n>Settings</ng-container>
</a>
</li>