This commit is contained in:
Miodec 2022-06-09 21:09:15 +02:00
commit f495fb3f36
10 changed files with 102 additions and 22 deletions

View file

@ -1,4 +1,5 @@
import _ from "lodash";
import { getCurrentDayTimestamp, MILLISECONDS_IN_DAY } from "../../utils/misc";
import { MonkeyResponse } from "../../utils/monkey-response";
import * as LeaderboardsDAL from "../../dal/leaderboards";
import MonkeyError from "../../utils/error";
@ -72,13 +73,21 @@ export async function getRankFromLeaderboard(
function getDailyLeaderboardWithError(
req: MonkeyTypes.Request
): DailyLeaderboards.DailyLeaderboard {
const { language, mode, mode2 } = req.query;
const { language, mode, mode2, daysBefore } = req.query;
const normalizedDayBefore = parseInt(daysBefore as string, 10);
const currentDayTimestamp = getCurrentDayTimestamp();
const dayBeforeTimestamp =
currentDayTimestamp - normalizedDayBefore * MILLISECONDS_IN_DAY;
const customTimestamp = _.isNil(daysBefore) ? -1 : dayBeforeTimestamp;
const dailyLeaderboard = DailyLeaderboards.getDailyLeaderboard(
language as string,
mode as string,
mode2 as string,
req.ctx.configuration.dailyLeaderboards
req.ctx.configuration.dailyLeaderboards,
customTimestamp
);
if (!dailyLeaderboard) {
throw new MonkeyError(404, "There is no daily leaderboard for this mode");

View file

@ -22,6 +22,11 @@ const LEADERBOARD_VALIDATION_SCHEMA_WITH_LIMIT = {
limit: joi.number().min(0).max(50),
};
const DAILY_LEADERBOARD_VALIDATION_SCHEMA = {
...LEADERBOARD_VALIDATION_SCHEMA_WITH_LIMIT,
daysBefore: joi.number().min(1).max(1),
};
const router = Router();
const requireDailyLeaderboardsEnabled = validateConfiguration({
@ -58,7 +63,7 @@ router.get(
RateLimit.leaderboardsGet,
authenticateRequest({ isPublic: true }),
validateRequest({
query: LEADERBOARD_VALIDATION_SCHEMA_WITH_LIMIT,
query: DAILY_LEADERBOARD_VALIDATION_SCHEMA,
}),
asyncHandler(LeaderboardController.getDailyLeaderboard)
);
@ -69,7 +74,7 @@ router.get(
RateLimit.leaderboardsGet,
authenticateRequest(),
validateRequest({
query: BASE_LEADERBOARD_VALIDATION_SCHEMA,
query: DAILY_LEADERBOARD_VALIDATION_SCHEMA,
}),
asyncHandler(LeaderboardController.getDailyLeaderboardRank)
);

View file

@ -41,10 +41,10 @@ async function bootServer(port: number): Promise<Server> {
Logger.info("Initializing task queues...");
initJobQueue(RedisClient.getConnection());
Logger.success("Task queues initialized");
initializeDailyLeaderboardsCache(liveConfiguration.dailyLeaderboards);
}
initializeDailyLeaderboardsCache(liveConfiguration.dailyLeaderboards);
Logger.info("Starting cron jobs...");
jobs.forEach((job) => job.start());
Logger.success("Cron jobs started");

View file

@ -173,7 +173,8 @@ export function getDailyLeaderboard(
language: string,
mode: string,
mode2: string,
dailyLeaderboardsConfig: MonkeyTypes.Configuration["dailyLeaderboards"]
dailyLeaderboardsConfig: MonkeyTypes.Configuration["dailyLeaderboards"],
customTimestamp = -1
): DailyLeaderboard | null {
const { validModeRules, enabled } = dailyLeaderboardsConfig;
@ -188,10 +189,15 @@ export function getDailyLeaderboard(
return null;
}
const key = `${language}:${mode}:${mode2}`;
const key = `${language}:${mode}:${mode2}:${customTimestamp}`;
if (!DAILY_LEADERBOARDS.has(key)) {
const dailyLeaderboard = new DailyLeaderboard(language, mode, mode2);
const dailyLeaderboard = new DailyLeaderboard(
language,
mode,
mode2,
customTimestamp
);
DAILY_LEADERBOARDS.set(key, dailyLeaderboard);
}

View file

@ -81,9 +81,11 @@ export function padNumbers(
);
}
export const MILLISECONDS_IN_DAY = 86400000;
export function getCurrentDayTimestamp(): number {
const currentTime = Date.now();
return currentTime - (currentTime % 86400000);
return currentTime - (currentTime % MILLISECONDS_IN_DAY);
}
export function matchesAPattern(text: string, pattern: string): boolean {
@ -91,8 +93,6 @@ export function matchesAPattern(text: string, pattern: string): boolean {
return regex.test(text);
}
export const MILLISECONDS_IN_DAY = 86400000;
export function kogascore(wpm: number, acc: number, timestamp: number): number {
const normalizedWpm = Math.floor(wpm * 100);
const normalizedAcc = Math.floor(acc * 100);

View file

@ -20,10 +20,10 @@
min-width: 100%;
display: grid;
align-items: center;
justify-content: space-between;
grid-template-columns: max-content auto 20rem;
grid-template-areas:
"title buttons"
"subtitle buttons";
"title yesterday buttons"
"subtitle subtitle buttons";
.buttons {
grid-area: buttons;
@ -38,6 +38,11 @@
grid-area: title;
}
.showYesterdayButton {
grid-area: "yesterday";
margin-left: 1rem;
}
.subTitle {
color: var(--sub-color);
grid-area: subtitle;
@ -102,7 +107,7 @@
.leftTableWrapper,
.rightTableWrapper {
height: calc(100vh - 12rem);
height: calc(100vh - 14rem);
@extend .ffscroll;
overflow-y: scroll;
overflow-x: auto;
@ -208,9 +213,9 @@
.buttons {
.buttonGroup {
display: grid;
grid-auto-flow: column;
grid-auto-flow: row;
gap: 0.5rem;
grid-auto-columns: 1fr;
gap: 1rem;
grid-area: buttons;
}
}

View file

@ -7,6 +7,7 @@
font-size: 1rem;
}
.leaderboardsTop {
grid-template-columns: max-content;
.buttonGroup {
grid-auto-flow: row;
gap: 0.5rem;
@ -211,6 +212,17 @@
.leaderboardsTop {
flex-direction: column;
align-items: baseline;
grid-template-areas:
"title title"
"subtitle subtitle"
"yesterday yesterday"
"buttons buttons";
.buttonGroup {
grid-auto-flow: column;
}
.showYesterdayButton {
margin-left: 0;
}
}
.tables {
grid-template-columns: unset;
@ -225,7 +237,7 @@
}
.tables .rightTableWrapper,
.tables .leftTableWrapper {
height: calc(50vh - 8rem);
height: calc(50vh - 10rem);
}
}
}
@ -551,7 +563,7 @@
width: 85vw;
.tables .rightTableWrapper,
.tables .leftTableWrapper {
height: calc(50vh - 7rem);
height: calc(50vh - 10rem);
}
.tables {
grid-template-columns: unset;

View file

@ -5,6 +5,7 @@ interface LeaderboardQuery {
mode: MonkeyTypes.Mode;
mode2: string | number;
isDaily?: boolean;
daysBefore?: number;
}
interface LeadeboardQueryWithPagination extends LeaderboardQuery {
@ -18,7 +19,16 @@ export default class Leaderboards {
}
async get(query: LeadeboardQueryWithPagination): Ape.EndpointData {
const { language, mode, mode2, isDaily, skip = 0, limit = 50 } = query;
const {
language,
mode,
mode2,
isDaily,
skip = 0,
limit = 50,
daysBefore,
} = query;
const includeDaysBefore = isDaily && daysBefore;
const searchQuery = {
language,
@ -26,6 +36,7 @@ export default class Leaderboards {
mode2,
skip: Math.max(skip, 0),
limit: Math.max(Math.min(limit, 50), 0),
...(includeDaysBefore && { daysBefore }),
};
const endpointPath = `${BASE_PATH}/${isDaily ? "daily" : ""}`;
@ -34,12 +45,14 @@ export default class Leaderboards {
}
async getRank(query: LeaderboardQuery): Ape.EndpointData {
const { language, mode, mode2, isDaily } = query;
const { language, mode, mode2, isDaily, daysBefore } = query;
const includeDaysBefore = isDaily && daysBefore;
const searchQuery = {
language,
mode,
mode2,
...(includeDaysBefore && { daysBefore }),
};
const endpointPath = `${BASE_PATH}${isDaily ? "/daily" : ""}/rank`;

View file

@ -339,6 +339,7 @@ export function hide(): void {
clearFoot(60);
reset();
stopTimer();
$("leaderboardsWrapper .showYesterdayButton").removeClass("active");
$("#leaderboardsWrapper").addClass("hidden");
}
);
@ -352,18 +353,35 @@ function updateTitle(): void {
el.text(`${timeRangeString} English Leaderboards`);
}
function updateYesterdayButton(): void {
$("#leaderboardsWrapper .showYesterdayButton").addClass("hidden");
if (currentTimeRange === "daily") {
$("#leaderboardsWrapper .showYesterdayButton").removeClass("hidden");
}
}
async function update(): Promise<void> {
showLoader(15);
showLoader(60);
const timeModes = ["15", "60"];
let daysBefore = 0;
if (
currentTimeRange === "daily" &&
$("#leaderboardsWrapper .showYesterdayButton").hasClass("active")
) {
daysBefore = 1;
}
const leaderboardRequests = timeModes.map((mode2) => {
return Ape.leaderboards.get({
language: "english",
mode: "time",
mode2,
isDaily: currentTimeRange === "daily",
daysBefore,
});
});
@ -375,6 +393,7 @@ async function update(): Promise<void> {
mode: "time",
mode2,
isDaily: currentTimeRange === "daily",
daysBefore,
});
})
);
@ -415,6 +434,7 @@ async function update(): Promise<void> {
$("#leaderboardsWrapper .rightTableWrapper").removeClass("invisible");
updateTitle();
updateYesterdayButton();
$("#leaderboardsWrapper .buttons .button").removeClass("active");
$(
`#leaderboardsWrapper .buttonGroup.timeRange .button.` + currentTimeRange
@ -674,6 +694,12 @@ $(
"#leaderboardsWrapper #leaderboards .leaderboardsTop .buttonGroup.timeRange .daily"
).on("click", () => {
currentTimeRange = "daily";
$("#leaderboardsWrapper .showYesterdayButton").removeClass("active");
update();
});
$("#leaderboardsWrapper .showYesterdayButton").on("click", () => {
$("#leaderboardsWrapper .showYesterdayButton").toggleClass("active");
update();
});

View file

@ -676,6 +676,10 @@
<div class="leaderboardsTop">
<div class="mainTitle">All-Time English Leaderboards</div>
<div class="subTitle">Next update in: --:--</div>
<div class="text-button showYesterdayButton hidden">
<i class="fas fa-calendar-day"></i>
Show Yesterday
</div>
<div class="buttons">
<div class="buttonGroup timeRange">
<div class="button allTime">all-time</div>