Skip to content

Commit 996fe41

Browse files
adds stats to the main page (#35)
adds stats to the main page
1 parent 4d73bba commit 996fe41

File tree

16 files changed

+555
-332
lines changed

16 files changed

+555
-332
lines changed

src/DTO/PublicStatsDto.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Name, Nullable, Property } from "@tsed/schema";
2+
3+
class RecordFormat {
4+
@Property()
5+
@Name("Practised")
6+
public practised: number;
7+
8+
@Property()
9+
@Name("Blind")
10+
public blind: number;
11+
}
12+
13+
class BooleanResponse {
14+
@Property()
15+
@Name("No")
16+
public no: number;
17+
18+
@Property()
19+
@Name("Yes")
20+
public yes: number;
21+
}
22+
23+
export class PublicStatsDto {
24+
@Property()
25+
@Nullable(RecordFormat)
26+
public recordFormat: RecordFormat | null = null;
27+
28+
@Property()
29+
@Nullable(BooleanResponse)
30+
public isAuthor: BooleanResponse | null = null;
31+
32+
@Property()
33+
@Nullable(BooleanResponse)
34+
public distributable: BooleanResponse | null = null;
35+
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { IndexDto } from "./IndexDto.js";
2-
import { SubmissionRoundModel } from "../model/db/SubmissionRound.model";
3-
import { SubmissionModel } from "../model/db/Submission.model.js";
4-
import { WadValidationService } from "../services/WadValidationService.js";
2+
import { SubmissionRoundModel } from "../../model/db/SubmissionRound.model.js";
3+
import { SubmissionModel } from "../../model/db/Submission.model.js";
4+
import { WadValidationService } from "../../services/WadValidationService.js";
55

66
export class AdminDto extends IndexDto {
77
public constructor(
@@ -30,6 +30,6 @@ export class AdminDto extends IndexDto {
3030
if (!this.currentActiveRound) {
3131
return [];
3232
}
33-
return this.currentActiveRound.submissions.filter(submission => submission.isSubmissionValidAndVerified());
33+
return this.currentActiveRound.validAndVerifiedSubmissions;
3434
}
3535
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { SubmissionRoundModel } from "../model/db/SubmissionRound.model.js";
2-
import DOOM_ENGINE from "../model/constants/DoomEngine.js";
3-
import GZDOOM_ACTIONS from "../model/constants/GZDoomActions.js";
4-
import { ObjectUtils } from "../utils/Utils.js";
5-
import { WadValidationService } from "../services/WadValidationService.js";
1+
import { SubmissionRoundModel } from "../../model/db/SubmissionRound.model.js";
2+
import DOOM_ENGINE from "../../model/constants/DoomEngine.js";
3+
import GZDOOM_ACTIONS from "../../model/constants/GZDoomActions.js";
4+
import { ObjectUtils } from "../../utils/Utils.js";
5+
import { WadValidationService } from "../../services/WadValidationService.js";
66

77
export class IndexDto {
88
private readonly months = [

src/DTO/ejs/StatsDto.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { SubmissionRoundModel } from "../../model/db/SubmissionRound.model.js";
2+
import { AutoInjectable, Inject } from "@tsed/di";
3+
import { SubmissionRoundService } from "../../services/SubmissionRoundService.js";
4+
5+
@AutoInjectable()
6+
export class StatsDto {
7+
public readonly mostSubmittedWad: string;
8+
public readonly mostSubmittedWadPercentage: number;
9+
10+
public constructor(
11+
private activeRound: SubmissionRoundModel | null = null,
12+
private previousRounds: SubmissionRoundModel[],
13+
@Inject() private submissionRoundService?: SubmissionRoundService,
14+
) {}
15+
16+
private async getMostSubmittedWadPercentageRounded(): Promise<number | null> {
17+
if (!this.activeRound) {
18+
return null;
19+
}
20+
const validSubmissions = this.activeRound.validAndVerifiedSubmissions;
21+
const totalSubmissions = validSubmissions.length;
22+
const mostSubmittedWad = await this.getMostSubmittedWad();
23+
24+
if (totalSubmissions > 0 && mostSubmittedWad) {
25+
const mostSubmittedWadCount = validSubmissions.filter(
26+
submission => submission.wadName === mostSubmittedWad,
27+
).length;
28+
return Math.round((mostSubmittedWadCount / totalSubmissions) * 100 * 100) / 100;
29+
}
30+
return 0;
31+
}
32+
33+
private getMostSubmittedWad(): Promise<string | null> {
34+
return this.submissionRoundService!.getMostSubmittedWadName();
35+
}
36+
37+
private get hasActiveRound(): boolean {
38+
return this.activeRound !== null;
39+
}
40+
41+
public async merge(obj: Record<string, unknown>): Promise<void> {
42+
if (this.hasActiveRound) {
43+
const mostSubmittedWad = (await this.getMostSubmittedWad())!;
44+
const mostSubmittedWadPercentage = (await this.getMostSubmittedWadPercentageRounded())!;
45+
46+
obj["stats"] = {
47+
mostSubmittedWad,
48+
mostSubmittedWadPercentage,
49+
};
50+
}
51+
}
52+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Controller, Inject } from "@tsed/di";
2+
import { BaseRestController } from "../BaseRestController.js";
3+
import { StatsService } from "../../../services/StatsService.js";
4+
import { Get, Returns } from "@tsed/schema";
5+
import { StatusCodes } from "http-status-codes";
6+
import { BadRequest } from "@tsed/exceptions";
7+
import { PathParams } from "@tsed/platform-params";
8+
import { PublicStatsDto } from "../../../DTO/PublicStatsDto.js";
9+
10+
@Controller("/stats")
11+
export class StatsController extends BaseRestController {
12+
public constructor(@Inject() private readonly statsService: StatsService) {
13+
super();
14+
}
15+
16+
@Get("/:roundId")
17+
@Returns(StatusCodes.OK, PublicStatsDto)
18+
@Returns(StatusCodes.BAD_REQUEST, BadRequest)
19+
public getStats(@PathParams("roundId") roundId: number): Promise<PublicStatsDto> {
20+
return this.statsService.getStats(roundId);
21+
}
22+
}

src/controllers/rest/impl/SubmissionController.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,6 @@ export class SubmissionController extends BaseRestController {
143143
return wad.content;
144144
}
145145

146-
@Get("/:roundId/validAndVerifiedSubmissions")
147-
@Authorize("login")
148-
@(Returns(StatusCodes.OK, Array).Of(SubmissionModel))
149-
@Returns(StatusCodes.BAD_REQUEST, BadRequest)
150-
public getValidAndVerifiedSubmissions(@PathParams("roundId") roundId: number): Promise<SubmissionModel[]> {
151-
return this.submissionService.getAllEntries(roundId, true);
152-
}
153-
154146
private async getWad(
155147
roundId: number,
156148
entryId: number,

src/controllers/rest/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
export * from "./BaseRestController.js";
55
export * from "./impl/security/PassportCtrl.js";
6+
export * from "./impl/StatsController.js";
67
export * from "./impl/SubmissionController.js";
78
export * from "./impl/SubmissionRoundController.js";
89
export * from "./impl/SubmissionRoundResultController.js";

src/controllers/secureViews/AdminHome.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import { SubmissionRoundResultService } from "../../services/SubmissionRoundResu
55
import { Authorize } from "@tsed/passport";
66
import { Req } from "@tsed/common";
77
import { CustomUserInfoModel } from "../../model/auth/CustomUserInfoModel.js";
8-
import { AdminDto } from "../../DTO/AdminDto.js";
8+
import { AdminDto } from "../../DTO/ejs/AdminDto.js";
99
import { WadValidationService } from "../../services/WadValidationService.js";
10+
import { StatsDto } from "../../DTO/ejs/StatsDto.js";
1011

1112
@Controller("/")
1213
export class AdminHome {
@@ -27,11 +28,14 @@ export class AdminHome {
2728
const currentActiveRound = await this.submissionRoundService.getCurrentActiveSubmissionRound(false);
2829
const previousRounds = await this.submissionRoundResultService.getAllSubmissionRoundResults();
2930
const user = req.user as CustomUserInfoModel;
30-
const mostSubmittedWad = await this.submissionRoundService.getMostSubmittedWadName();
31-
return {
31+
const stats = new StatsDto(currentActiveRound, previousRounds);
32+
const resp: Record<string, unknown> = {
3233
indexModel: new AdminDto(currentActiveRound, previousRounds, this.wadValidationService),
3334
user,
34-
mostSubmittedWad,
3535
};
36+
37+
await stats.merge(resp);
38+
39+
return resp;
3640
}
3741
}

src/controllers/views/HomeView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { SubmissionConfirmationService } from "../../services/SubmissionConfirma
55
import { QueryParams, Req, Res } from "@tsed/common";
66
import { NotFound } from "@tsed/exceptions";
77
import { SubmissionRoundResultService } from "../../services/SubmissionRoundResultService.js";
8-
import { IndexDto } from "../../DTO/IndexDto.js";
8+
import { IndexDto } from "../../DTO/ejs/IndexDto.js";
99
import type { UUID } from "crypto";
1010
import { WadValidationService } from "../../services/WadValidationService.js";
1111
import { CaptchaManager } from "../../manager/CaptchaManager.js";

src/model/db/SubmissionRound.model.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,8 @@ export class SubmissionRoundModel extends AbstractModel {
5050
private sanitiseString(): void {
5151
this.name = xss(this.name);
5252
}
53+
54+
public get validAndVerifiedSubmissions(): SubmissionModel[] {
55+
return this.submissions.filter(submission => submission.isSubmissionValidAndVerified());
56+
}
5357
}

0 commit comments

Comments
 (0)