fix(repository): Move backend code into subdirectory

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2022-10-02 20:10:32 +02:00 committed by David Mehren
parent 86584e705f
commit bf30cbcf48
272 changed files with 87 additions and 67 deletions

View file

@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { ConsoleLoggerService } from './console-logger.service';
describe('sanitize', () => {
it('removes non-printable ASCII character', () => {
for (let i = 0; i++; i < 32) {
const hexString = i.toString(16);
expect(ConsoleLoggerService.sanitize(`a${hexString}b`)).toEqual('ab');
}
});
it('replaces non-zero-width space with space', () => {
const nonZeroWidthSpaces = [
'\u0020', // space
'\u00A0', // non-breaking space
'\u2000', // en quad
'\u2001', // en quad
'\u2002', // en space
'\u2003', // en space
'\u2004', // three-per-em space
'\u2005', // four-per-em space
'\u2006', // six-per-em space
'\u2007', // figure space
'\u2008', // punctuation space
'\u2009', // thin space
'\u200a', // hair space
'\u202F', // narrow no-break space
'\u205F', // medium mathematical space
'\u3000', // ideographic space
];
nonZeroWidthSpaces.forEach((space) => {
expect(ConsoleLoggerService.sanitize(`c${space}d`)).toEqual('c d');
});
});
});

View file

@ -0,0 +1,181 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import {
Inject,
Injectable,
LoggerService,
Optional,
Scope,
} from '@nestjs/common';
import { isObject } from '@nestjs/common/utils/shared.utils';
import appConfiguration, { AppConfig } from '../config/app.config';
import { Loglevel } from '../config/loglevel.enum';
import { needToLog } from '../config/utils';
import clc = require('cli-color');
import DateTimeFormatOptions = Intl.DateTimeFormatOptions;
@Injectable({ scope: Scope.TRANSIENT })
export class ConsoleLoggerService implements LoggerService {
private classContext: string | undefined;
private lastTimestamp: number;
private skipColor = false;
constructor(
@Inject(appConfiguration.KEY)
private appConfig: AppConfig,
@Optional() context?: string,
) {
this.classContext = context;
}
setContext(context: string): void {
this.classContext = context;
}
setSkipColor(skipColor: boolean): void {
this.skipColor = skipColor;
}
error(message: unknown, trace = '', functionContext?: string): void {
this.printMessage(
message,
clc.red,
this.makeContextString(functionContext),
false,
);
ConsoleLoggerService.printStackTrace(trace);
}
log(message: unknown, functionContext?: string): void {
if (needToLog(this.appConfig.loglevel, Loglevel.INFO)) {
this.printMessage(
message,
clc.green,
this.makeContextString(functionContext),
false,
);
}
}
warn(message: unknown, functionContext?: string): void {
if (needToLog(this.appConfig.loglevel, Loglevel.WARN)) {
this.printMessage(
message,
clc.yellow,
this.makeContextString(functionContext),
false,
);
}
}
debug(message: unknown, functionContext?: string): void {
if (needToLog(this.appConfig.loglevel, Loglevel.DEBUG)) {
this.printMessage(
message,
clc.magentaBright,
this.makeContextString(functionContext),
false,
);
}
}
verbose(message: unknown, functionContext?: string): void {
if (needToLog(this.appConfig.loglevel, Loglevel.TRACE)) {
this.printMessage(
message,
clc.cyanBright,
this.makeContextString(functionContext),
false,
);
}
}
private makeContextString(functionContext?: string): string {
let context = this.classContext;
if (!context) {
context = 'HedgeDoc';
}
if (functionContext) {
context += '.' + functionContext + '()';
}
return context;
}
static sanitize(input: string): string {
return (
input
// remove ASCII control characters
.replace(/\p{C}/gu, '')
// replace all non-zeros width spaces with one space
.replace(/\p{Zs}/gu, ' ')
);
}
private printMessage(
message: unknown,
color: (message: string) => string,
context = '',
isTimeDiffEnabled?: boolean,
): void {
let output;
// if skipColor is set, we do not use colors and skip sanitizing
if (this.skipColor) {
if (isObject(message)) {
output = `${color('Object:')}\n${JSON.stringify(message, null, 2)}\n`;
} else {
output = message as string;
}
} else {
if (isObject(message)) {
output = `${color('Object:')}\n${ConsoleLoggerService.sanitize(
JSON.stringify(message, null, 2),
)}\n`;
} else {
output = color(ConsoleLoggerService.sanitize(message as string));
}
}
const localeStringOptions: DateTimeFormatOptions = {
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
day: '2-digit',
month: '2-digit',
};
//TODO make timestamp optional
const timestamp = new Date(Date.now()).toLocaleString(
undefined,
localeStringOptions,
);
const contextMessage = context ? clc.blue(`[${context}] `) : '';
const timestampDiff = this.updateAndGetTimestampDiff(isTimeDiffEnabled);
process.stdout.write(
`${timestamp} ${contextMessage}${output}${timestampDiff}\n`,
);
}
private updateAndGetTimestampDiff(isTimeDiffEnabled?: boolean): string {
const includeTimestamp = this.lastTimestamp && isTimeDiffEnabled;
const result = includeTimestamp
? clc.yellow(` +${Date.now() - this.lastTimestamp}ms`)
: '';
this.lastTimestamp = Date.now();
return result;
}
private static printStackTrace(trace: string): void {
if (!trace) {
return;
}
process.stdout.write(`${trace}\n`);
}
}

View file

@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Module } from '@nestjs/common';
import { ConsoleLoggerService } from './console-logger.service';
import { TypeormLoggerService } from './typeorm-logger.service';
@Module({
providers: [ConsoleLoggerService, TypeormLoggerService],
exports: [ConsoleLoggerService, TypeormLoggerService],
})
export class LoggerModule {}

View file

@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*
* The code in this class is based on:
* https://github.com/typeorm/typeorm/blob/master/src/logger/AdvancedConsoleLogger.ts
*/
import { Injectable } from '@nestjs/common';
import { Logger, QueryRunner } from 'typeorm';
import { PlatformTools } from 'typeorm/platform/PlatformTools';
import { ConsoleLoggerService } from './console-logger.service';
@Injectable()
export class TypeormLoggerService implements Logger {
constructor(private readonly logger: ConsoleLoggerService) {
this.logger.setContext('TypeORM');
this.logger.setSkipColor(true);
}
log(level: 'log' | 'info' | 'warn', message: unknown, _?: QueryRunner): void {
switch (level) {
case 'log':
case 'info':
this.logger.log(message);
break;
case 'warn':
this.logger.warn(message);
}
}
logMigration(message: string, _?: QueryRunner): void {
// eslint-disable-next-line local-rules/correct-logger-context
this.logger.log(message, 'migration');
}
logQuery(query: string, parameters?: unknown[], _?: QueryRunner): void {
const sql =
query +
(parameters && parameters.length
? ' -- PARAMETERS: ' + this.stringifyParams(parameters)
: '');
// eslint-disable-next-line local-rules/correct-logger-context
this.logger.debug(PlatformTools.highlightSql(sql), 'query');
}
logQueryError(
error: string | Error,
query: string,
parameters?: unknown[],
_?: QueryRunner,
): void {
const sql =
query +
(parameters && parameters.length
? ` -- PARAMETERS: ${this.stringifyParams(parameters)}`
: '');
this.logger.debug(PlatformTools.highlightSql(sql));
// eslint-disable-next-line local-rules/correct-logger-context
this.logger.debug(error.toString(), 'queryError');
}
logQuerySlow(
time: number,
query: string,
parameters?: unknown[],
_?: QueryRunner,
): void {
const sql =
query +
(parameters && parameters.length
? ` -- PARAMETERS: ${this.stringifyParams(parameters)}`
: '');
/* eslint-disable local-rules/correct-logger-context */
this.logger.warn(PlatformTools.highlightSql(sql), 'querySlow');
this.logger.warn(`execution time: ${time}`, 'querySlow');
/* eslint-enable local-rules/correct-logger-context */
}
logSchemaBuild(message: string, _?: QueryRunner): void {
// eslint-disable-next-line local-rules/correct-logger-context
this.logger.debug(message, 'schemaBuild');
}
/**
* Converts parameters to a string.
* Sometimes parameters can have circular objects and therefore we are handle this case too.
*/
protected stringifyParams(parameters: unknown[]): string {
try {
return JSON.stringify(parameters);
} catch (error) {
// most probably circular objects in parameters
return parameters.toString();
}
}
}