From 53a01ad97779ff47be4c309f5dc2547ecc61d08e Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 30 Dec 2020 16:31:18 +0100 Subject: [PATCH] Added stats response ref #56 --- src/controllers/StatsController.ts | 25 ++++----- src/models/responses/ResponseStats.ts | 74 +++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 16 deletions(-) create mode 100644 src/models/responses/ResponseStats.ts diff --git a/src/controllers/StatsController.ts b/src/controllers/StatsController.ts index b6c75a3..75e676b 100644 --- a/src/controllers/StatsController.ts +++ b/src/controllers/StatsController.ts @@ -8,6 +8,7 @@ import { RunnerOrganisation } from '../models/entities/RunnerOrganisation'; import { RunnerTeam } from '../models/entities/RunnerTeam'; import { Scan } from '../models/entities/Scan'; import { User } from '../models/entities/User'; +import { ResponseStats } from '../models/responses/ResponseStats'; import { ResponseStatsRunner } from '../models/responses/ResponseStatsRunner'; import { ResponseStatsTeam } from '../models/responses/ResponseStatsTeam'; @@ -15,25 +16,17 @@ import { ResponseStatsTeam } from '../models/responses/ResponseStatsTeam'; export class StatsController { @Get() + @ResponseSchema(ResponseStats) @OpenAPI({ description: "A very basic stats endpoint providing basic counters for a dashboard or simmilar" }) async get() { let connection = getConnection(); - let runners = await connection.getRepository(Runner).find({ relations: ["scans"] }); + let runners = await connection.getRepository(Runner).find({ relations: ['scans', 'scans.track'] }); let teams = await connection.getRepository(RunnerTeam).find(); let orgs = await connection.getRepository(RunnerOrganisation).find(); let users = await connection.getRepository(User).find(); let scans = await connection.getRepository(Scan).find(); - let donations = await connection.getRepository(Donation).find({ relations: ["runner", "runner.scans"] }); - return { - "total_runners": runners.length, - "total_teams": teams.length, - "total_orgs": orgs.length, - "total_users": users.length, - "total_scans": scans.filter(scan => { scan.valid === true }).length, - "total_distance": runners.reduce((sum, current) => sum + current.distance, 0), - "total_donation_amount": donations.reduce((sum, current) => sum + current.amount, 0), - "average_distance": runners.reduce((sum, current) => sum + current.distance, 0) / runners.length, - }; + let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] }); + return new ResponseStats(runners, teams, orgs, users, scans, donations) } @Get("/runners/distance") @@ -41,7 +34,7 @@ export class StatsController { @ResponseSchema(ResponseStatsRunner, { isArray: true }) @OpenAPI({ description: "Returns the top ten runners by distance.", security: [{ "StatsApiToken": [] }] }) async getTopRunnersByDistance() { - let runners = await getConnection().getRepository(Runner).find({ relations: ['scans', 'group', 'distanceDonations'] }); + let runners = await getConnection().getRepository(Runner).find({ relations: ['scans', 'group', 'distanceDonations', 'scans.track'] }); let topRunners = runners.sort((runner1, runner2) => runner1.distance - runner2.distance).slice(0, 9); let responseRunners: ResponseStatsRunner[] = new Array(); topRunners.forEach(runner => { @@ -55,7 +48,7 @@ export class StatsController { @ResponseSchema(ResponseStatsRunner, { isArray: true }) @OpenAPI({ description: "Returns the top ten runners by donations.", security: [{ "StatsApiToken": [] }] }) async getTopRunnersByDonations() { - let runners = await getConnection().getRepository(Runner).find({ relations: ['scans', 'group', 'distanceDonations'] }); + let runners = await getConnection().getRepository(Runner).find({ relations: ['scans', 'group', 'distanceDonations', 'scans.track'] }); let topRunners = runners.sort((runner1, runner2) => runner1.distanceDonationAmount - runner2.distanceDonationAmount).slice(0, 9); let responseRunners: ResponseStatsRunner[] = new Array(); topRunners.forEach(runner => { @@ -69,7 +62,7 @@ export class StatsController { @ResponseSchema(ResponseStatsTeam, { isArray: true }) @OpenAPI({ description: "Returns the top ten teams by distance.", security: [{ "StatsApiToken": [] }] }) async getTopTeamsByDistance() { - let teams = await getConnection().getRepository(RunnerTeam).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations'] }); + let teams = await getConnection().getRepository(RunnerTeam).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track'] }); let topTeams = teams.sort((team1, team2) => team1.distance - team2.distance).slice(0, 9); let responseTeams: ResponseStatsTeam[] = new Array(); topTeams.forEach(team => { @@ -83,7 +76,7 @@ export class StatsController { @ResponseSchema(ResponseStatsTeam, { isArray: true }) @OpenAPI({ description: "Returns the top ten teams by donations.", security: [{ "StatsApiToken": [] }] }) async getTopTeamsByDonations() { - let teams = await getConnection().getRepository(RunnerTeam).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations'] }); + let teams = await getConnection().getRepository(RunnerTeam).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track'] }); let topTeams = teams.sort((team1, team2) => team1.distanceDonationAmount - team2.distanceDonationAmount).slice(0, 9); let responseTeams: ResponseStatsTeam[] = new Array(); topTeams.forEach(team => { diff --git a/src/models/responses/ResponseStats.ts b/src/models/responses/ResponseStats.ts new file mode 100644 index 0000000..d236bd0 --- /dev/null +++ b/src/models/responses/ResponseStats.ts @@ -0,0 +1,74 @@ +import { + IsInt +} from "class-validator"; +import { Donation } from '../entities/Donation'; +import { Runner } from '../entities/Runner'; +import { RunnerOrganisation } from '../entities/RunnerOrganisation'; +import { RunnerTeam } from '../entities/RunnerTeam'; +import { Scan } from '../entities/Scan'; +import { User } from '../entities/User'; + +/** + * Defines the stats response. + * The stats response calculates some basic stats for a dashboard or public display. +*/ +export class ResponseStats { + /** + * The amount of runners registered in the system. + */ + @IsInt() + total_runners: number; + + /** + * The amount of teams registered in the system. + */ + @IsInt() + total_teams: number; + + /** + * The amount of organisations registered in the system. + */ + @IsInt() + total_orgs: number; + + /** + * The amount of users registered in the system. + */ + @IsInt() + total_users: number; + + /** + * The amount of valid scans registered in the system. + */ + @IsInt() + total_scans: number; + + /** + * The total distance that all runners ran. + */ + @IsInt() + total_distance: number; + + /** + * The total donation amount. + */ + @IsInt() + total_donation: number; + + /** + * The average distance per runner. + */ + @IsInt() + average_distance: number; + + public constructor(runners: Runner[], teams: RunnerTeam[], orgs: RunnerOrganisation[], users: User[], scans: Scan[], donations: Donation[]) { + this.total_runners = runners.length; + this.total_teams = teams.length; + this.total_orgs = orgs.length; + this.total_users = users.length; + this.total_scans = scans.filter(scan => { scan.valid === true }).length; + this.total_distance = runners.reduce((sum, current) => sum + current.distance, 0); + this.total_donation = donations.reduce((sum, current) => sum + current.amount, 0); + this.average_distance = this.total_distance / this.total_runners; + } +}