import { Get, JsonController, QueryParam, UseBefore } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnection } from 'typeorm'; import StatsAuth from '../middlewares/StatsAuth'; import { Donation } from '../models/entities/Donation'; import { Donor } from '../models/entities/Donor'; import { Runner } from '../models/entities/Runner'; import { RunnerOrganization } from '../models/entities/RunnerOrganization'; import { RunnerTeam } from '../models/entities/RunnerTeam'; import { Scan } from '../models/entities/Scan'; import { TrackScan } from '../models/entities/TrackScan'; import { User } from '../models/entities/User'; import { ResponseStats } from '../models/responses/ResponseStats'; import { ResponseStatsOrgnisation } from '../models/responses/ResponseStatsOrganization'; import { ResponseStatsRunner } from '../models/responses/ResponseStatsRunner'; import { ResponseStatsTeam } from '../models/responses/ResponseStatsTeam'; @JsonController('/stats') export class StatsController { @Get() @ResponseSchema(ResponseStats) @OpenAPI({ description: "A very basic stats endpoint providing basic counters for a dashboard or simmilar" }) async get() { const connection = getConnection(); const runners = await connection.getRepository(Runner).count(); const teams = await connection.getRepository(RunnerTeam).count(); const orgs = await connection.getRepository(RunnerOrganization).count(); const users = await connection.getRepository(User).count(); const scans = await connection.getRepository(Scan).count({ where: { valid: true } }); const distance_query = await connection.getRepository(Scan).createQueryBuilder('scan') .leftJoinAndSelect("scan.track", "track").where("scan.valid = TRUE") .select("SUM(track.distance)", "sum_track").addSelect("SUM(_distance)", "sum_distance") .getRawOne(); let distace = parseInt(distance_query.sum_track) if (distance_query.sum_distance) { distace += parseInt(distance_query.sum_distance) } let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] }); const donors = await connection.getRepository(Donor).count(); return new ResponseStats(runners, teams, orgs, users, scans, donations, distace, donors) } @Get("/runners/distance") @UseBefore(StatsAuth) @ResponseSchema(ResponseStatsRunner, { isArray: true }) @OpenAPI({ description: "Returns the top ten runners by distance.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) async getTopRunnersByDistance() { let runners = await getConnection().getRepository(Runner).find({ relations: ['scans', 'group', 'distanceDonations', 'scans.track'] }); if (!runners || runners.length == 0) { return []; } let topRunners = runners.sort((runner1, runner2) => runner2.distance - runner1.distance).slice(0, 10); let responseRunners: ResponseStatsRunner[] = new Array(); topRunners.forEach(runner => { responseRunners.push(new ResponseStatsRunner(runner)); }); return responseRunners; } @Get("/runners/donations") @UseBefore(StatsAuth) @ResponseSchema(ResponseStatsRunner, { isArray: true }) @OpenAPI({ description: "Returns the top ten runners by donations.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) async getTopRunnersByDonations() { let runners = await getConnection().getRepository(Runner).find({ relations: ['group', 'distanceDonations', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] }); if (!runners || runners.length == 0) { return []; } let topRunners = runners.sort((runner1, runner2) => runner2.distanceDonationAmount - runner1.distanceDonationAmount).slice(0, 10); let responseRunners: ResponseStatsRunner[] = new Array(); topRunners.forEach(runner => { responseRunners.push(new ResponseStatsRunner(runner)); }); return responseRunners; } @Get("/runners/laptime") @UseBefore(StatsAuth) @ResponseSchema(ResponseStatsRunner, { isArray: true }) @OpenAPI({ description: "Returns the top ten runners by fastest laptime on your selected track (track by id).", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) async getTopRunnersByLaptime(@QueryParam("track") track: number) { let scans = await getConnection().getRepository(TrackScan).find({ relations: ['track', 'runner', 'runner.group', 'runner.scans', 'runner.scans.track', 'runner.distanceDonations'] }); if (!scans || scans.length == 0) { return []; } scans = scans.filter((s) => { return s.track.id == track && s.valid == true && s.lapTime != 0 }).sort((scan1, scan2) => scan1.lapTime - scan2.lapTime); let topScans = new Array(); let knownRunners = new Array(); for (let i = 0; i < scans.length && topScans.length < 10; i++) { const element = scans[i]; if (!knownRunners.includes(element.runner.id)) { topScans.push(element); knownRunners.push(element.runner.id); } } let responseRunners: ResponseStatsRunner[] = new Array(); topScans.forEach(scan => { responseRunners.push(new ResponseStatsRunner(scan.runner, scan.lapTime)); }); return responseRunners; } @Get("/scans") @UseBefore(StatsAuth) @ResponseSchema(ResponseStatsRunner, { isArray: true }) @OpenAPI({ description: "Returns the top ten fastest track times (with their runner and the runner's group).", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) async getTopRunnersByTrackTime() { throw new Error("Not implemented yet.") } @Get("/teams/distance") @UseBefore(StatsAuth) @ResponseSchema(ResponseStatsTeam, { isArray: true }) @OpenAPI({ description: "Returns the top ten teams by distance.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) async getTopTeamsByDistance() { let teams = await getConnection().getRepository(RunnerTeam).find({ relations: ['parentGroup', 'runners', 'runners.scans', 'runners.scans.track'] }); if (!teams || teams.length == 0) { return []; } let topTeams = teams.sort((team1, team2) => team2.distance - team1.distance).slice(0, 10); let responseTeams: ResponseStatsTeam[] = new Array(); topTeams.forEach(team => { responseTeams.push(new ResponseStatsTeam(team)); }); return responseTeams; } @Get("/teams/donations") @UseBefore(StatsAuth) @ResponseSchema(ResponseStatsTeam, { isArray: true }) @OpenAPI({ description: "Returns the top ten teams by donations.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) async getTopTeamsByDonations() { let teams = await getConnection().getRepository(RunnerTeam).find({ relations: ['parentGroup', 'runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track'] }); if (!teams || teams.length == 0) { return []; } let topTeams = teams.sort((team1, team2) => team2.distanceDonationAmount - team1.distanceDonationAmount).slice(0, 10); let responseTeams: ResponseStatsTeam[] = new Array(); topTeams.forEach(team => { responseTeams.push(new ResponseStatsTeam(team)); }); return responseTeams; } @Get("/organizations/distance") @UseBefore(StatsAuth) @ResponseSchema(ResponseStatsOrgnisation, { isArray: true }) @OpenAPI({ description: "Returns the top ten organizations by distance.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) async getTopOrgsByDistance() { let orgs = await getConnection().getRepository(RunnerOrganization).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.scans', 'teams.runners.distanceDonations', 'teams.runners.scans.track'] }); if (!orgs || orgs.length == 0) { return []; } let topOrgs = orgs.sort((org1, org2) => org2.distance - org1.distance).slice(0, 10); let responseOrgs: ResponseStatsOrgnisation[] = new Array(); topOrgs.forEach(org => { responseOrgs.push(new ResponseStatsOrgnisation(org)); }); return responseOrgs; } @Get("/organizations/donations") @UseBefore(StatsAuth) @ResponseSchema(ResponseStatsOrgnisation, { isArray: true }) @OpenAPI({ description: "Returns the top ten organizations by donations.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) async getTopOrgsByDonations() { let orgs = await getConnection().getRepository(RunnerOrganization).find({ relations: ['runners', 'runners.distanceDonations', 'runners.distanceDonations.runner', 'runners.distanceDonations.runner.scans', 'runners.distanceDonations.runner.scans.track', 'teams', 'teams.runners', 'teams.runners.distanceDonations', 'teams.runners.distanceDonations.runner', 'teams.runners.distanceDonations.runner.scans', 'teams.runners.distanceDonations.runner.scans.track'] }); if (!orgs || orgs.length == 0) { return []; } let topOrgs = orgs.sort((org1, org2) => org2.distanceDonationAmount - org1.distanceDonationAmount).slice(0, 10); let responseOrgs: ResponseStatsOrgnisation[] = new Array(); topOrgs.forEach(org => { responseOrgs.push(new ResponseStatsOrgnisation(org)); }); return responseOrgs; } }