fix(leaderboards): show correct rank in friends weekly leaderboard (@fehmer) (#7104)

This commit is contained in:
Christian Fehmer 2025-11-12 15:33:32 +01:00 committed by GitHub
parent 60fffb15f8
commit 8ee7e94d46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 52 additions and 22 deletions

View file

@ -1265,10 +1265,13 @@ describe("Loaderboard Controller", () => {
describe("get xp weekly leaderboard rank", () => {
const getXpWeeklyLeaderboardMock = vi.spyOn(WeeklyXpLeaderboard, "get");
const getRankMock = vi.fn();
const getFriendsUidsMock = vi.spyOn(ConnectionsDal, "getFriendsUids");
beforeEach(async () => {
getXpWeeklyLeaderboardMock.mockClear();
getRankMock.mockClear();
[getXpWeeklyLeaderboardMock, getRankMock, getFriendsUidsMock].forEach(
(it) => it.mockClear()
);
await weeklyLeaderboardEnabled(true);
vi.useFakeTimers();
vi.setSystemTime(1722606812000);
@ -1313,25 +1316,13 @@ describe("Loaderboard Controller", () => {
expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith(lbConf, -1);
expect(getRankMock).toHaveBeenCalledWith(uid, lbConf);
expect(getRankMock).toHaveBeenCalledWith(uid, lbConf, undefined);
});
it("should get for last week", async () => {
//GIVEN
const lbConf = (await configuration).leaderboards.weeklyXp;
const resultData: XpLeaderboardEntry = {
totalXp: 100,
rank: 1,
timeTypedSeconds: 100,
uid: "user1",
name: "user1",
discordId: "discordId",
discordAvatar: "discordAvatar",
lastActivityTimestamp: 1000,
};
getRankMock.mockResolvedValue(resultData);
getRankMock.mockResolvedValue({});
//WHEN
const { body } = await mockApp
@ -1343,7 +1334,7 @@ describe("Loaderboard Controller", () => {
//THEN
expect(body).toEqual({
message: "Weekly xp leaderboard rank retrieved",
data: resultData,
data: {},
});
expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith(
@ -1351,7 +1342,33 @@ describe("Loaderboard Controller", () => {
1721606400000
);
expect(getRankMock).toHaveBeenCalledWith(uid, lbConf);
expect(getRankMock).toHaveBeenCalledWith(uid, lbConf, undefined);
});
it("should get for friendsOnly", async () => {
//GIVEN
const lbConf = (await configuration).leaderboards.weeklyXp;
await enableConnectionsFeature(true);
getRankMock.mockResolvedValue({});
const friends = ["friendOne", "friendTwo"];
getFriendsUidsMock.mockResolvedValue(friends);
//WHEN
const { body } = await mockApp
.get("/leaderboards/xp/weekly/rank")
.query({ friendsOnly: true })
.set("Authorization", `Bearer ${uid}`)
.expect(200);
//THEN
expect(body).toEqual({
message: "Weekly xp leaderboard rank retrieved",
data: {},
});
expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith(lbConf, -1);
expect(getRankMock).toHaveBeenCalledWith(uid, lbConf, friends);
});
it("fails if daily leaderboards are disabled", async () => {

View file

@ -248,7 +248,15 @@ export async function getWeeklyXpLeaderboard(
export async function getWeeklyXpLeaderboardRank(
req: MonkeyRequest<GetWeeklyXpLeaderboardRankQuery>
): Promise<GetWeeklyXpLeaderboardRankResponse> {
const { friendsOnly } = req.query;
const { uid } = req.ctx.decodedToken;
const connectionsConfig = req.ctx.configuration.connections;
const friendUids = await getFriendsUids(
uid,
friendsOnly === true,
connectionsConfig
);
const weeklyXpLeaderboard = getWeeklyXpLeaderboardWithError(
req.ctx.configuration.leaderboards.weeklyXp,
@ -256,7 +264,8 @@ export async function getWeeklyXpLeaderboardRank(
);
const rankEntry = await weeklyXpLeaderboard.getRank(
uid,
req.ctx.configuration.leaderboards.weeklyXp
req.ctx.configuration.leaderboards.weeklyXp,
friendUids
);
return new MonkeyResponse("Weekly xp leaderboard rank retrieved", rankEntry);

View file

@ -766,9 +766,13 @@ function fillUser(): void {
}
const userData = state.userData;
const percentile = (userData.rank / state.count) * 100;
const rank = state.friendsOnly
? (userData.friendsRank as number)
: userData.rank;
const percentile = (rank / state.count) * 100;
let percentileString = `Top ${percentile.toFixed(2)}%`;
if (userData.rank === 1) {
if (rank === 1) {
percentileString = "GOAT";
}
@ -805,7 +809,7 @@ function fillUser(): void {
};
const html = `
<div class="rank">${formatRank(userData.rank)}</div>
<div class="rank">${formatRank(rank)}</div>
<div class="userInfo">
<div class="top">You (${percentileString})</div>
<div class="bottom">${diffText}</div>