Don't ping owners on rank-only standings changes in Discord
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 3m24s
🚀 Deploy / ʦ🔍 Typecheck & Lint (pull_request) Successful in 1m23s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
🚀 Deploy / 🧪 Test (push) Successful in 3m17s
🚀 Deploy / ʦ🔍 Typecheck & Lint (push) Successful in 1m28s
🚀 Deploy / 🐳 Build (push) Successful in 1m11s
🚀 Deploy / 🚀 Deploy (push) Successful in 11s
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 3m24s
🚀 Deploy / ʦ🔍 Typecheck & Lint (pull_request) Successful in 1m23s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
🚀 Deploy / 🧪 Test (push) Successful in 3m17s
🚀 Deploy / ʦ🔍 Typecheck & Lint (push) Successful in 1m28s
🚀 Deploy / 🐳 Build (push) Successful in 1m11s
🚀 Deploy / 🚀 Deploy (push) Successful in 11s
The first score of a season displaces every other team's rank (e.g. everyone becomes T2), which fired a mass @-ping of the whole league even though only one owner actually scored. The Standings Changes section pinged every team whose rank *or* points changed. Now the section pings an owner only when that team's points genuinely changed this event; rank-only shufflers are still displayed with their rank delta, but by name and without a mention. Mirrors the existing "display but don't ping" behaviour in the Scored Matches section and preserves pings for pure season-standings sports (F1, IndyCar), where a real scorer's points always change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
91227b2cb3
commit
3f6af2665e
2 changed files with 48 additions and 5 deletions
|
|
@ -277,6 +277,43 @@ describe("sendStandingsUpdateNotification", () => {
|
||||||
expect(desc).not.toContain("Gamma");
|
expect(desc).not.toContain("Gamma");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("pings scorers but not rank-only shufflers", async () => {
|
||||||
|
await sendStandingsUpdateNotification({
|
||||||
|
webhookUrl: WEBHOOK_URL,
|
||||||
|
seasonName: "My League 2025",
|
||||||
|
standings: [
|
||||||
|
// Alpha scored — points changed, moved up.
|
||||||
|
{ teamId: "a", teamName: "Alpha", totalPoints: 150, rank: 1, discordUserId: "111" },
|
||||||
|
// Beta was displaced down without scoring — rank changed only.
|
||||||
|
{ teamId: "b", teamName: "Beta", totalPoints: 125, rank: 2, username: "beta_owner", discordUserId: "222" },
|
||||||
|
],
|
||||||
|
previousStandings: new Map([
|
||||||
|
["a", 125],
|
||||||
|
["b", 125],
|
||||||
|
]),
|
||||||
|
previousRanks: new Map([
|
||||||
|
["a", 2],
|
||||||
|
["b", 1],
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
|
||||||
|
const desc = getDescription();
|
||||||
|
// Beta is still displayed with its rank movement…
|
||||||
|
expect(desc).toContain("Beta");
|
||||||
|
expect(desc).toContain("↓1");
|
||||||
|
// …but by name, not as an @-mention.
|
||||||
|
expect(desc).not.toContain("<@222>");
|
||||||
|
// Alpha scored, so it keeps its mention.
|
||||||
|
expect(desc).toContain("<@111>");
|
||||||
|
|
||||||
|
const payload = getPayload();
|
||||||
|
// Only the scorer is pinged.
|
||||||
|
expect(payload.content).toContain("111");
|
||||||
|
expect(payload.content).not.toContain("222");
|
||||||
|
expect(payload.allowed_mentions.users).toContain("111");
|
||||||
|
expect(payload.allowed_mentions.users).not.toContain("222");
|
||||||
|
});
|
||||||
|
|
||||||
it("omits rank delta when no previousRanks provided", async () => {
|
it("omits rank delta when no previousRanks provided", async () => {
|
||||||
await sendStandingsUpdateNotification({
|
await sendStandingsUpdateNotification({
|
||||||
webhookUrl: WEBHOOK_URL,
|
webhookUrl: WEBHOOK_URL,
|
||||||
|
|
|
||||||
|
|
@ -175,13 +175,19 @@ export async function sendStandingsUpdateNotification({
|
||||||
const isTied = buildTiedRankChecker(standings.map((s) => s.rank));
|
const isTied = buildTiedRankChecker(standings.map((s) => s.rank));
|
||||||
const rankLabel = (rank: number) => (isTied(rank) ? `T${rank}` : `${rank}`);
|
const rankLabel = (rank: number) => (isTied(rank) ? `T${rank}` : `${rank}`);
|
||||||
|
|
||||||
|
// A team's points genuinely changed this event (vs. merely being displaced in
|
||||||
|
// rank because someone else scored). Only real scorers are pinged; rank-only
|
||||||
|
// shufflers are still displayed, but by name and without an @-mention.
|
||||||
|
const pointsChanged = (s: StandingEntry) => {
|
||||||
|
const prevPoints = previousStandings.get(s.teamId);
|
||||||
|
return prevPoints !== undefined && prevPoints !== s.totalPoints;
|
||||||
|
};
|
||||||
|
|
||||||
// Standings changes section — show teams whose points or rank changed.
|
// Standings changes section — show teams whose points or rank changed.
|
||||||
const changedTeams = standings.filter((s) => {
|
const changedTeams = standings.filter((s) => {
|
||||||
const prevPoints = previousStandings.get(s.teamId);
|
|
||||||
const pointsChanged = prevPoints !== undefined && prevPoints !== s.totalPoints;
|
|
||||||
const prevRank = previousRanks?.get(s.teamId);
|
const prevRank = previousRanks?.get(s.teamId);
|
||||||
const rankChanged = prevRank !== undefined && prevRank !== s.rank;
|
const rankChanged = prevRank !== undefined && prevRank !== s.rank;
|
||||||
return pointsChanged || rankChanged;
|
return pointsChanged(s) || rankChanged;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (changedTeams.length > 0) {
|
if (changedTeams.length > 0) {
|
||||||
|
|
@ -206,7 +212,7 @@ export async function sendStandingsUpdateNotification({
|
||||||
}
|
}
|
||||||
|
|
||||||
const escapedName = escapeMarkdown(s.teamName);
|
const escapedName = escapeMarkdown(s.teamName);
|
||||||
const managerLabel = s.discordUserId
|
const managerLabel = s.discordUserId && pointsChanged(s)
|
||||||
? `<@${s.discordUserId}>`
|
? `<@${s.discordUserId}>`
|
||||||
: s.username
|
: s.username
|
||||||
? escapeMarkdown(s.username)
|
? escapeMarkdown(s.username)
|
||||||
|
|
@ -225,7 +231,7 @@ export async function sendStandingsUpdateNotification({
|
||||||
// Collect Discord user IDs of all opted-in managers appearing in this notification.
|
// Collect Discord user IDs of all opted-in managers appearing in this notification.
|
||||||
const pingUserIds = new Set<string>();
|
const pingUserIds = new Set<string>();
|
||||||
for (const s of changedTeams) {
|
for (const s of changedTeams) {
|
||||||
if (s.discordUserId) pingUserIds.add(s.discordUserId);
|
if (s.discordUserId && pointsChanged(s)) pingUserIds.add(s.discordUserId);
|
||||||
}
|
}
|
||||||
for (const m of relevantMatches ?? []) {
|
for (const m of relevantMatches ?? []) {
|
||||||
if (m.winnerDiscordUserId) pingUserIds.add(m.winnerDiscordUserId);
|
if (m.winnerDiscordUserId) pingUserIds.add(m.winnerDiscordUserId);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue