Reformat code
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
export interface Predicate<T, O> {
|
||||
process(input: T): O;
|
||||
}
|
||||
process(input: T): O;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
export class Sort {
|
||||
public static descending = (a: number, b: number) => {
|
||||
if (a < b) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a > b) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
public static descending = (a: number, b: number) => {
|
||||
if (a < b) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (a > b) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
export class TimeUtil {
|
||||
|
||||
public static humanize = (seconds: number) => {
|
||||
const d = Math.floor(seconds / (3600 * 24));
|
||||
const h = Math.floor(seconds % (3600 * 24) / 3600);
|
||||
const m = Math.floor(seconds % 3600 / 60);
|
||||
const s = Math.floor(seconds % 60);
|
||||
|
||||
return `${d}d ${h}h ${m}m ${s}s`;
|
||||
}
|
||||
}
|
||||
public static humanize = (seconds: number) => {
|
||||
const d = Math.floor(seconds / (3600 * 24));
|
||||
const h = Math.floor((seconds % (3600 * 24)) / 3600);
|
||||
const m = Math.floor((seconds % 3600) / 60);
|
||||
const s = Math.floor(seconds % 60);
|
||||
|
||||
return `${d}d ${h}h ${m}m ${s}s`;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { Controller, Get, HostParam, HttpException, HttpStatus, Param, Req } from '@nestjs/common';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
HostParam,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Req,
|
||||
} from '@nestjs/common';
|
||||
import { AppService } from './app.service';
|
||||
import { DatabaseService } from './database/database.service';
|
||||
import logger from './logger/Logger';
|
||||
import { TableEntry } from "./models/TableEntry";
|
||||
import { SinusBotService } from "./services/sinusbot.service";
|
||||
import { TableEntry } from './models/TableEntry';
|
||||
import { SinusBotService } from './services/sinusbot.service';
|
||||
import { UserStatsResponse } from './models/aliases';
|
||||
|
||||
@Controller()
|
||||
@@ -11,7 +19,7 @@ export class AppController {
|
||||
constructor(
|
||||
private readonly appService: AppService,
|
||||
private readonly sinusBotService: SinusBotService,
|
||||
private readonly databaseService: DatabaseService
|
||||
private readonly databaseService: DatabaseService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@@ -26,13 +34,16 @@ export class AppController {
|
||||
|
||||
@Get('/stats/season/:id')
|
||||
async getStats(@Param('id') id: string): Promise<UserStatsResponse> {
|
||||
return this.databaseService.fetchStats(id)
|
||||
.then(value => { return value; })
|
||||
return this.databaseService
|
||||
.fetchStats(id)
|
||||
.then(value => {
|
||||
return value;
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error(`Error occured when fetching stats.`, err);
|
||||
throw new HttpException(
|
||||
'Error when fetching stats. Contact administrator or try again later!',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,13 @@ import { TimeTrackerPredicate } from './database/timetracking.predicate';
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [AppController],
|
||||
providers: [AppService, SinusBotService, DatabaseService, PrismaService, TimeTrackerPredicate],
|
||||
providers: [
|
||||
AppService,
|
||||
SinusBotService,
|
||||
DatabaseService,
|
||||
PrismaService,
|
||||
TimeTrackerPredicate,
|
||||
],
|
||||
})
|
||||
export class AppModule implements NestModule {
|
||||
configure(consumer: MiddlewareConsumer): any {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { TimeTrackerPredicate } from './timetracking.predicate';
|
||||
import { SeasonInfo, TimeTrackerStats, UserStatsResponse } from '../models/aliases';
|
||||
import {
|
||||
SeasonInfo,
|
||||
TimeTrackerStats,
|
||||
UserStatsResponse,
|
||||
} from '../models/aliases';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
@@ -16,8 +20,7 @@ export class DatabaseService {
|
||||
constructor(
|
||||
private readonly prismaClient: PrismaService,
|
||||
private readonly timetrackerPredicate: TimeTrackerPredicate,
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
public fetchSeasonInfos = async (seasonId: string): Promise<SeasonInfo> => {
|
||||
let seasons;
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
import { ranks, seasons, timetracker, user } from "@prisma/client";
|
||||
import { Predicate } from "src/api/predicate";
|
||||
import { Sort } from "src/api/sort";
|
||||
import { TimeUtil } from "src/api/timeutil";
|
||||
import { TableEntry } from "src/models/TableEntry";
|
||||
import { ranks, seasons, timetracker, user } from '@prisma/client';
|
||||
import { Predicate } from 'src/api/predicate';
|
||||
import { Sort } from 'src/api/sort';
|
||||
import { TimeUtil } from 'src/api/timeutil';
|
||||
import { TableEntry } from 'src/models/TableEntry';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
type UserStats = timetracker & { user: user, ranks: ranks; };
|
||||
type UserStats = timetracker & { user: user; ranks: ranks };
|
||||
|
||||
export class TimeTrackerPredicate implements Predicate<UserStats[], TableEntry[]> {
|
||||
|
||||
process(input: UserStats[]): TableEntry[] {
|
||||
return input.filter((userStats: UserStats) => userStats.time != null)
|
||||
.map((userStats: UserStats) => {
|
||||
return {
|
||||
name: userStats.user.name,
|
||||
rawTime: userStats.time,
|
||||
onlineTime: TimeUtil.humanize(userStats.time),
|
||||
rank: userStats.ranks.rank_name
|
||||
}
|
||||
})
|
||||
.sort((lhs, rhs) => Sort.descending(lhs.rawTime, rhs.rawTime));
|
||||
}
|
||||
}
|
||||
@Injectable()
|
||||
export class TimeTrackerPredicate
|
||||
implements Predicate<UserStats[], TableEntry[]> {
|
||||
process(input: UserStats[]): TableEntry[] {
|
||||
return input
|
||||
.filter((userStats: UserStats) => userStats.time != null)
|
||||
.map((userStats: UserStats) => {
|
||||
return {
|
||||
name: userStats.user.name,
|
||||
rawTime: userStats.time,
|
||||
onlineTime: TimeUtil.humanize(userStats.time),
|
||||
rank: userStats.ranks.rank_name,
|
||||
};
|
||||
})
|
||||
.sort((lhs, rhs) => Sort.descending(lhs.rawTime, rhs.rawTime));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export class LoggerMiddleware implements NestMiddleware {
|
||||
const contentLength = response.get('content-length');
|
||||
|
||||
logger.info(
|
||||
`${method} ${url} ${statusCode} ${contentLength} - ${userAgent} ${ip}`
|
||||
`${method} ${url} ${statusCode} ${contentLength} - ${userAgent} ${ip}`,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as winston from 'winston';
|
||||
|
||||
const transports = {
|
||||
console: new winston.transports.Console()
|
||||
console: new winston.transports.Console(),
|
||||
};
|
||||
|
||||
const logger = winston.createLogger({
|
||||
transports: [transports.console]
|
||||
})
|
||||
transports: [transports.console],
|
||||
});
|
||||
|
||||
export default logger;
|
||||
|
||||
@@ -4,7 +4,7 @@ interface RequestError extends Error {
|
||||
}
|
||||
|
||||
interface RequestErrorConstructor extends ErrorConstructor {
|
||||
new(message?: string): RequestError;
|
||||
new (message?: string): RequestError;
|
||||
(message?: string): RequestError;
|
||||
readonly prototype: RequestError;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export interface TableEntry {
|
||||
name: string;
|
||||
onlineTime: string;
|
||||
name: string;
|
||||
rank: string;
|
||||
onlineTime: string;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ranks, seasons, timetracker, user } from '@prisma/client';
|
||||
import { TableEntry } from './TableEntry';
|
||||
|
||||
export type TimeTrackerStats = timetracker & { user: user; ranks: ranks; }
|
||||
export type SeasonInfo = seasons & { maxSeasonId: number }
|
||||
export type UserStatsResponse = SeasonInfo & TableEntry[]
|
||||
export type TimeTrackerStats = timetracker & { user: user; ranks: ranks };
|
||||
export type SeasonInfo = seasons & { maxSeasonId: number };
|
||||
export type UserStatsResponse = SeasonInfo & TableEntry[];
|
||||
|
||||
@@ -11,4 +11,4 @@ export class PrismaService extends PrismaClient
|
||||
async onModuleDestroy() {
|
||||
await this.$disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { TableEntry } from "../models/TableEntry";
|
||||
import { TunakillUser } from "../models/TunakillUser";
|
||||
import {HttpException, HttpStatus, Injectable} from "@nestjs/common";
|
||||
import {TunakillLogin} from "../models/TunakillLogin";
|
||||
import { TableEntry } from '../models/TableEntry';
|
||||
import { TunakillUser } from '../models/TunakillUser';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { TunakillLogin } from '../models/TunakillLogin';
|
||||
import fetch from 'node-fetch';
|
||||
import logger from "../logger/Logger";
|
||||
import logger from '../logger/Logger';
|
||||
|
||||
@Injectable()
|
||||
export class SinusBotService {
|
||||
private host = process.env.HOST
|
||||
private host = process.env.HOST;
|
||||
private credentials = {
|
||||
username: process.env.SINUSBOT_USER,
|
||||
password: process.env.SINUSBOT_PASSWORD
|
||||
}
|
||||
password: process.env.SINUSBOT_PASSWORD,
|
||||
};
|
||||
|
||||
private botInfo = {
|
||||
id: undefined,
|
||||
instanceId: process.env.SINUSBOT_INSTANCEID
|
||||
}
|
||||
instanceId: process.env.SINUSBOT_INSTANCEID,
|
||||
};
|
||||
|
||||
private botIdURL = `${this.host}/api/v1/botId`;
|
||||
private tunaKillURL = `${this.host}/api/v1/bot/i/${this.botInfo.instanceId}/event/tunakill_rank_all_user`;
|
||||
@@ -34,23 +34,30 @@ export class SinusBotService {
|
||||
// if (this.bearer == null) {
|
||||
logger.info(`Hey! I'm trying to get my Bearer token!`);
|
||||
await this.login()
|
||||
.then(token => this.bearer = token)
|
||||
.then(token => (this.bearer = token))
|
||||
.then(() => {
|
||||
logger.debug(
|
||||
`Seems like I have my Bearer token!
|
||||
Looks like it's ${this.bearer == null ? 'undefined' : 'not undefined'}`
|
||||
Looks like it's ${
|
||||
this.bearer == null ? 'undefined' : 'not undefined'
|
||||
}`,
|
||||
);
|
||||
});
|
||||
// }
|
||||
|
||||
logger.info(`I try to fetch user data now! The URL is called ${this.tunaKillURL}`);
|
||||
logger.info(
|
||||
`I try to fetch user data now! The URL is called ${this.tunaKillURL}`,
|
||||
);
|
||||
return await fetch(this.tunaKillURL, this.requestConfig(null, this.bearer))
|
||||
.then(res => this.checkStatus(res))
|
||||
.then(res => res.json())
|
||||
.then(data => this.consumeTunakillResponse(data))
|
||||
.catch(error => {
|
||||
logger.error(`I couldn't fetch user data.`, error);
|
||||
throw this.createHttpException(HttpStatus.INTERNAL_SERVER_ERROR, error.message);
|
||||
throw this.createHttpException(
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
error.message,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,12 +68,15 @@ export class SinusBotService {
|
||||
if (this.botInfo.id == null) {
|
||||
logger.debug(`I have to fetch a bot ID before I can continue!`);
|
||||
await this.fetchDefaultBotId()
|
||||
.then(defaultBotId => this.botInfo.id = defaultBotId)
|
||||
.then(defaultBotId => (this.botInfo.id = defaultBotId))
|
||||
.catch(error => {
|
||||
logger.warn(`I couldn't retrieve SinusBot bot information. Login is likely to fail!`, error);
|
||||
logger.warn(
|
||||
`I couldn't retrieve SinusBot bot information. Login is likely to fail!`,
|
||||
error,
|
||||
);
|
||||
throw this.createHttpException(
|
||||
HttpStatus.NOT_FOUND,
|
||||
`Could not fetch enough bot information for further requests.`
|
||||
`Could not fetch enough bot information for further requests.`,
|
||||
);
|
||||
});
|
||||
logger.info(`The bot ID now is ${this.botInfo.id}`);
|
||||
@@ -75,20 +85,23 @@ export class SinusBotService {
|
||||
const body: TunakillLogin = {
|
||||
username: this.credentials.username,
|
||||
password: this.credentials.password,
|
||||
botId: this.botInfo.id
|
||||
}
|
||||
botId: this.botInfo.id,
|
||||
};
|
||||
|
||||
logger.info(`Logging in for Bearer token!`)
|
||||
logger.info(`Logging in for Bearer token!`);
|
||||
return await fetch(this.loginURL, this.requestConfig(JSON.stringify(body)))
|
||||
.then(res => this.checkStatus(res))
|
||||
.then(res => res.json())
|
||||
.then(data => data.token)
|
||||
.catch(error => {
|
||||
logger.error(`Oh oh! Something went wrong while fetching Bearer token.`, error);
|
||||
logger.error(
|
||||
`Oh oh! Something went wrong while fetching Bearer token.`,
|
||||
error,
|
||||
);
|
||||
throw this.createHttpException(
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
`Fetching Bearer token for Sinusbot failed.
|
||||
Please refresh page or try again later!`
|
||||
Please refresh page or try again later!`,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -110,39 +123,56 @@ export class SinusBotService {
|
||||
throw Error('Response from SinusBot does not have any data to parse.');
|
||||
}
|
||||
|
||||
return response
|
||||
// TODO: Remove hardcoded username filter for bots.
|
||||
.filter((user: TunakillUser) => user.name !== "Server Query Admin" && user.name !== "DJ Inshalla")
|
||||
return (
|
||||
response
|
||||
// TODO: Remove hardcoded username filter for bots.
|
||||
.filter(
|
||||
(user: TunakillUser) =>
|
||||
user.name !== 'Server Query Admin' && user.name !== 'DJ Inshalla',
|
||||
)
|
||||
|
||||
.filter((user: TunakillUser) => user.time != null)
|
||||
.map((user: TunakillUser) => {
|
||||
return {
|
||||
name: user.name,
|
||||
rawTime: user.time,
|
||||
onlineTime: this.humanizeTime(user.time)
|
||||
};
|
||||
})
|
||||
.sort((a: any, b: any) => this.sortByDescendingTime(a.rawTime, b.rawTime));
|
||||
.filter((user: TunakillUser) => user.time != null)
|
||||
.map((user: TunakillUser) => {
|
||||
return {
|
||||
name: user.name,
|
||||
rawTime: user.time,
|
||||
onlineTime: this.humanizeTime(user.time),
|
||||
};
|
||||
})
|
||||
.sort((a: any, b: any) =>
|
||||
this.sortByDescendingTime(a.rawTime, b.rawTime),
|
||||
)
|
||||
);
|
||||
}
|
||||
private requestConfig = (body?: string, bearerToken?: string, requestType: string = 'POST'): RequestInit => {
|
||||
private requestConfig = (
|
||||
body?: string,
|
||||
bearerToken?: string,
|
||||
requestType: string = 'POST',
|
||||
): RequestInit => {
|
||||
return {
|
||||
method: requestType,
|
||||
body: body,
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
Accept: '*/*',
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'HumeniusTSRankingBackend/0.0.2',
|
||||
'Authorization': `Bearer ${bearerToken}`
|
||||
}
|
||||
Authorization: `Bearer ${bearerToken}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
private createHttpException = (statusCode: HttpStatus, message?: string): HttpException => {
|
||||
return new HttpException({
|
||||
status: statusCode,
|
||||
error: message
|
||||
}, statusCode);
|
||||
}
|
||||
private createHttpException = (
|
||||
statusCode: HttpStatus,
|
||||
message?: string,
|
||||
): HttpException => {
|
||||
return new HttpException(
|
||||
{
|
||||
status: statusCode,
|
||||
error: message,
|
||||
},
|
||||
statusCode,
|
||||
);
|
||||
};
|
||||
|
||||
private checkStatus = response => {
|
||||
if (!response.ok) {
|
||||
@@ -151,7 +181,7 @@ export class SinusBotService {
|
||||
throw err;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
};
|
||||
|
||||
private sortByDescendingTime = (a: number, b: number) => {
|
||||
if (a < b) {
|
||||
@@ -163,16 +193,16 @@ export class SinusBotService {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
private humanizeTime = (seconds: number) => {
|
||||
const d = Math.floor(seconds / (3600 * 24));
|
||||
const h = Math.floor(seconds % (3600 * 24) / 3600);
|
||||
const m = Math.floor(seconds % 3600 / 60);
|
||||
const h = Math.floor((seconds % (3600 * 24)) / 3600);
|
||||
const m = Math.floor((seconds % 3600) / 60);
|
||||
const s = Math.floor(seconds % 60);
|
||||
|
||||
return `${d}d ${h}h ${m}m ${s}s`;
|
||||
}
|
||||
};
|
||||
|
||||
private static logResponse(res: any) {
|
||||
logger.debug(res);
|
||||
|
||||
Reference in New Issue
Block a user