您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Script para mostrar las notas actuales de todos los usuarios en el scoreboard del CTFd. (TODO: Manejo de errores en las requests)
// ==UserScript== // @name Mostrar Notas // @namespace http://tampermonkey.net/ // @license MIT // @version 0.1.551 // @description Script para mostrar las notas actuales de todos los usuarios en el scoreboard del CTFd. (TODO: Manejo de errores en las requests) // @author Neftalí Toledo // @match https://ic.catedras.linti.unlp.edu.ar/scoreboard // @icon https://www.google.com/s2/favicons?sz=64&domain=edu.ar // @grant none // @run-at document-end // ==/UserScript== (async function() { 'use strict'; const ENDPOINT = "https://ic.catedras.linti.unlp.edu.ar/api/v1/users/USER_ID/solves"; const RETOS_ENDPOINT = "https://ic.catedras.linti.unlp.edu.ar/api/v1/challenges" // Define los valores de suma correspondientes a cada categoría para el promedio ponderado //const cantidad_dificultades = 3; (SIN USO) const valorEasy = 4; const valorMedium = 3; const valorHard = 3; const valoresTotales = await obtenerValoresTotales(); //Obtiene los totales para calcular el promedio // Categorias que no se van a tener en cuenta para el calculo de la nota const categoriasExcluidas = [ "Extras-(no-suman-nota)", "Practica-0_Scripting" ] //Promedio function calcularPromedioPonderado(cantidadEasy, cantidadMedium, cantidadHard, categoria) { // Calcula la suma ponderada const promedioEasy = calcularPromedio(cantidadEasy, valoresTotales[categoria]["Easy"] || 1); const promedioMedium = calcularPromedio(cantidadMedium, valoresTotales[categoria]["Medium"] || 1); const promedioHard = calcularPromedio(cantidadHard, valoresTotales[categoria]["Hard"] || 1); return (promedioEasy * valorEasy + promedioMedium * valorMedium + promedioHard * valorHard); } function calcularPromedio(retos_resueltos, total) { return (retos_resueltos / total); } // Filtros function filtrarDesafios(data, total = false) { const result = {}; data.forEach(item => { const categoryKey = total ? item.category : item.challenge.category; const [categoria, dificultad] = categoryKey.split(" - "); result[categoria] = result[categoria] || {}; result[categoria][dificultad] = (result[categoria][dificultad] || 0) + 1; }); return result; } // Exclusiones function excluirCategorias(categorias) { const categoriasExcluidasSet = new Set(categoriasExcluidas); // Se convierte en Set por eficiencia para muchas categorías excluidas return categorias.filter(categoria => !categoriasExcluidasSet.has(categoria)); } // Obtener la cantidad de retos resueltos por el usuario async function obtenerRetosResueltos(user) { const req = ENDPOINT.replace("USER_ID", user); const response = await fetch(req); const dataJSON = await response.json(); return dataJSON; } // Obtener nota para cada practica function obtenerNotas(data) { const retos_resueltos = filtrarDesafios(data); const categorias = excluirCategorias(Object.keys(retos_resueltos)); const notas = categorias .filter(categoria => Object.keys(retos_resueltos[categoria]).length > 0) .map(categoria => { const cantidadEasy = retos_resueltos[categoria]["Easy"] || 0; const cantidadMedium = retos_resueltos[categoria]["Medium"] || 0; const cantidadHard = retos_resueltos[categoria]["Hard"] || 0; const promedioPonderado = calcularPromedioPonderado(cantidadEasy, cantidadMedium, cantidadHard, categoria); return `${categoria}: ${parseFloat(promedioPonderado).toPrecision(3)}`; }) .reverse().join("<br>"); return notas; } // Obtener el total de retos por categoría async function obtenerValoresTotales(){ const response = await fetch(RETOS_ENDPOINT); const retosJSON = await response.json(); const retos_total = filtrarDesafios(retosJSON.data, true); return retos_total; } // Obtenemos la tabla de usuarios y sus filas const tablaUsuarios = document.querySelector(".table-striped"); const filas = tablaUsuarios.querySelectorAll("tr"); // Añadir columna de notas const columnaNotas = document.createElement("td"); columnaNotas.setAttribute("scope", "col"); columnaNotas.innerHTML = "<b>Notas</b>"; filas[0].appendChild(columnaNotas); // Obtener las notas de cada usuario const userPromises = []; for (let i = 1; i < filas.length; i++) { //A veces este link cambia a "https://ic.catedras.linti.unlp.edu.ar/teams/" en vez de "https://ic.catedras.linti.unlp.edu.ar/users/" // No se por qué pasa const userID = parseInt(filas[i].querySelector("td a").href.replace("https://ic.catedras.linti.unlp.edu.ar/users/", "")); userPromises.push(obtenerRetosResueltos(userID)); } // Esperar a que se resuelvan todas las promesas const userNotes = await Promise.all(userPromises); // Construir notas como una cadena HTML const notasHTML = userNotes.map(userNote => { const notas = obtenerNotas(userNote.data); return notas || "No resolvió ningún reto"; }); // Añadir notas a cada fila for (let i = 1; i < filas.length; i++) { const elementoNota = document.createElement("td"); elementoNota.innerHTML = notasHTML[i - 1]; filas[i].appendChild(elementoNota); } })();