Fix: Validate songId as number and add user notification for leaderboard submission

This commit is contained in:
2026-01-17 19:29:36 +08:00
parent 9bd2b21d44
commit 0706f99427
2 changed files with 78 additions and 5 deletions

View File

@@ -77,9 +77,16 @@ class Leaderboard {
}
async fetchLeaderboard() {
// Validate songId is a valid number
if (!this.songId || isNaN(parseInt(this.songId))) {
console.error("Invalid song ID for leaderboard:", this.songId)
this.leaderboardData = []
return
}
try {
var response = await loader.ajax(
`${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${this.songId}&difficulty=${this.difficulty}`
`${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${parseInt(this.songId)}&difficulty=${this.difficulty}`
)
var data = JSON.parse(response)
if (data.status === "ok") {
@@ -94,6 +101,7 @@ class Leaderboard {
}
}
changeDifficulty(direction) {
var difficulties = ["easy", "normal", "hard", "oni", "ura"]
var currentIndex = difficulties.indexOf(this.difficulty)

View File

@@ -958,27 +958,92 @@ class Scoresheet {
}
submitToLeaderboard(songId, difficulty, scoreObj) {
// Only submit if user is logged in and song has valid ID
if (!account.loggedIn || !songId) {
// Only submit if user is logged in and song has valid numeric ID
if (!account.loggedIn || !songId || isNaN(parseInt(songId))) {
return
}
var self = this
loader.getCsrfToken().then(token => {
var request = new XMLHttpRequest()
request.open("POST", "api/leaderboard/submit")
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
request.setRequestHeader("X-CSRFToken", token)
request.onload = function () {
if (request.status === 200) {
try {
var response = JSON.parse(request.responseText)
if (response.status === "ok") {
self.showLeaderboardNotification(response.message)
}
} catch (e) {
console.error("Failed to parse leaderboard response:", e)
}
}
}
request.send(JSON.stringify({
song_id: songId,
song_id: parseInt(songId),
difficulty: difficulty,
score: scoreObj
}))
}).catch(() => {
// Silently fail - leaderboard submission is optional
console.log("Leaderboard submission failed")
})
}
showLeaderboardNotification(message) {
var notification = document.createElement("div")
notification.className = "leaderboard-notification"
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 15px 25px;
background: linear-gradient(135deg, #4a90e2, #7b68ee);
color: white;
border-radius: 10px;
font-size: 16px;
font-family: ${strings.font || "sans-serif"};
z-index: 10000;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
opacity: 0;
transform: translateX(100px);
transition: all 0.3s ease-out;
`
var text = ""
switch (message) {
case "score_submitted": text = "🏆 成绩已提交到排行榜!"; break
case "score_updated": text = "🎉 排行榜成绩已更新!"; break
case "score_not_higher": text = "📊 已有更高成绩"; break
case "score_too_low": text = "未进入排行榜前50"; break
default: text = "排行榜已更新"
}
notification.innerText = text
document.body.appendChild(notification)
// Trigger animation
setTimeout(() => {
notification.style.opacity = "1"
notification.style.transform = "translateX(0)"
}, 10)
// Remove after 3 seconds
setTimeout(() => {
notification.style.opacity = "0"
notification.style.transform = "translateX(100px)"
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification)
}
}, 300)
}, 3000)
}
clean() {
this.keyboard.clean()
this.gamepad.clean()