From e2b6bdc319bdee5f1fe6827bfe2edd4795847a84 Mon Sep 17 00:00:00 2001 From: exyi Date: Mon, 30 Nov 2020 23:35:24 +0000 Subject: [PATCH] Use x-summary endpoint for points This endpoint includes points from the old tasks in series - resolves #44 --- frontend/src/Editor.svelte | 2 +- frontend/src/Odevzdavatko.svelte | 5 ++-- frontend/src/TasksLoader.svelte | 3 -- frontend/src/ksp-submit-api.ts | 27 +++++++++++++++++- frontend/src/ksp-task-grabber.ts | 46 ------------------------------- frontend/src/task-status-cache.ts | 11 +++++--- 6 files changed, 36 insertions(+), 58 deletions(-) diff --git a/frontend/src/Editor.svelte b/frontend/src/Editor.svelte index 4dd4793..112a4f8 100644 --- a/frontend/src/Editor.svelte +++ b/frontend/src/Editor.svelte @@ -191,7 +191,7 @@ return; } const y = prompt("Který ročník (číslo 26...X)"); - await refreshTaskStatuses([`${y}-Z1-1`]); + await refreshTaskStatuses(); const newTasks = Array.from($taskStatuses.values()).filter( (t) => t.id.startsWith(y + "-") && diff --git a/frontend/src/Odevzdavatko.svelte b/frontend/src/Odevzdavatko.svelte index cb1af5e..0d39990 100644 --- a/frontend/src/Odevzdavatko.svelte +++ b/frontend/src/Odevzdavatko.svelte @@ -1,7 +1,6 @@ {#if data == null && err == null} diff --git a/frontend/src/ksp-submit-api.ts b/frontend/src/ksp-submit-api.ts index d255703..5d718aa 100644 --- a/frontend/src/ksp-submit-api.ts +++ b/frontend/src/ksp-submit-api.ts @@ -1,4 +1,4 @@ -import { fetchHtml } from "./ksp-task-grabber"; +import { fetchHtml, isLoggedIn } from "./ksp-task-grabber"; let apitoken : string | null = null @@ -85,3 +85,28 @@ export async function submit(id: string, subtask: string, uploadedData: string | ] }) } +export type TaskStatus = { + id: string + name: string + submitted: boolean + solved: boolean + points: number + maxPoints: number +} + +export async function grabTaskSummary(): Promise> { + if (!isLoggedIn()) throw new Error() + + const results = await requestJson(`/api/tasks/x-summary`) as { tasks: TaskSubmitStatus[] } + + function mapId(id: string) { + if (id.startsWith("cviciste/")) + return id.substr("cviciste/".length) + else + return id + } + + return new Map( + results.tasks.map(r => [mapId(r.id), { id: mapId(r.id), maxPoints: r.max_points, name: r.name, points: r.points, solved: r.points > r.max_points - 0.001, submitted: r.points > 0 }]) + ) +} diff --git a/frontend/src/ksp-task-grabber.ts b/frontend/src/ksp-task-grabber.ts index e35e64f..ea4bb59 100644 --- a/frontend/src/ksp-task-grabber.ts +++ b/frontend/src/ksp-task-grabber.ts @@ -14,16 +14,6 @@ type TaskLocation = { startElement: string } -export type TaskStatus = { - id: string - name: string - submitted: boolean - solved: boolean - points: number - maxPoints: number - type: string -} - function fixAllLinks(e: any) { if (typeof e.src == "string") { e.src = e.src @@ -150,27 +140,6 @@ function parseTask(startElementId: string, doc: HTMLDocument): TaskAssignmentDat } } -function parseTaskStatuses(doc: HTMLDocument): TaskStatus[] { - const rows = Array.from(doc.querySelectorAll("table.zs-tasklist tr")).slice(1) as HTMLTableRowElement[] - return rows.map(r => { - const submitted = !r.classList.contains("zs-unsubmitted") - const id = r.cells[0].textContent!.trim() - const type = r.cells[1].textContent!.trim() - const name = r.cells[2].textContent!.trim() - const pointsStr = r.cells[4].textContent!.trim() - const pointsMatch = /((–|\.|\d)+) *\/ *(\d+)/.exec(pointsStr) - if (!pointsMatch) throw new Error() - let points = +pointsMatch[1] - // points was a dash, means 0 - if (isNaN(points)) { - points = 0 - } - const maxPoints = +pointsMatch[3] - const solved = r.classList.contains("zs-submitted") - return { id, name, submitted, type, points, maxPoints, solved } - }) -} - export async function fetchHtml(url: string) { const r = await fetch(url, { headers: { "Accept": "text/html,application/xhtml+xml" } }) if (r.status >= 400) { @@ -196,21 +165,6 @@ export function isLoggedIn(): boolean { return !!document.head.querySelector("meta[name=x-ksp-uid]") } -export async function grabTaskStates(kspIds: string[]): Promise> { - if (!isLoggedIn()) throw new Error() - - const ids = new Set(kspIds.map(parseTaskId).filter(t => t != null).map(t => t!.rocnik)) - const results = await Promise.all(Array.from(ids.keys()).map(async (rocnik) => { - const html = await fetchHtml(`/cviciste/?year=${rocnik}`) - return parseTaskStatuses(html) - })) - - return new Map( - ([] as TaskStatus[]).concat(...results) - .map(r => [r.id, r]) - ) -} - export async function grabAssignment(id: string): Promise { return await loadTask(getLocation(id, false)) } diff --git a/frontend/src/task-status-cache.ts b/frontend/src/task-status-cache.ts index d499522..58e30ee 100644 --- a/frontend/src/task-status-cache.ts +++ b/frontend/src/task-status-cache.ts @@ -1,5 +1,6 @@ -import { grabTaskStates, isLoggedIn} from "./ksp-task-grabber" -import type { TaskStatus } from "./ksp-task-grabber" +import { isLoggedIn } from "./ksp-task-grabber" +import { grabTaskSummary } from './ksp-submit-api' +import type { TaskStatus } from "./ksp-submit-api" import { readable } from 'svelte/store'; let writeFn: (value: Map) => void = null!; @@ -14,12 +15,14 @@ export const taskStatuses = readable(lastVal, write => { writeFn = v => { lastVal = v; write(v); } }) -export function refresh(ids: string[]) { +export function refresh() { if (!isLoggedIn()) return; - return grabTaskStates(ids).then(t => { + return grabTaskSummary().then(t => { const tt = Array.from(t.entries()) writeFn(new Map(Array.from(lastVal.entries()).concat(tt))) localStorage.setItem("taskStatuses-cache", JSON.stringify(tt)) }) } + +refresh()