Use x-summary endpoint for points
This endpoint includes points from the old tasks in series - resolves #44
This commit is contained in:
parent
d77686e6f0
commit
e2b6bdc319
6 changed files with 36 additions and 58 deletions
|
@ -191,7 +191,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const y = prompt("Který ročník (číslo 26...X)");
|
const y = prompt("Který ročník (číslo 26...X)");
|
||||||
await refreshTaskStatuses([`${y}-Z1-1`]);
|
await refreshTaskStatuses();
|
||||||
const newTasks = Array.from($taskStatuses.values()).filter(
|
const newTasks = Array.from($taskStatuses.values()).filter(
|
||||||
(t) =>
|
(t) =>
|
||||||
t.id.startsWith(y + "-") &&
|
t.id.startsWith(y + "-") &&
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { isLoggedIn, parseTaskId } from "./ksp-task-grabber";
|
import { isLoggedIn, parseTaskId } from "./ksp-task-grabber";
|
||||||
import type { TaskStatus } from "./ksp-task-grabber";
|
import type { TaskSubmitStatus, SubtaskSubmitStatus, TaskStatus } from './ksp-submit-api'
|
||||||
import type { TaskSubmitStatus, SubtaskSubmitStatus } from './ksp-submit-api'
|
|
||||||
import * as api from './ksp-submit-api'
|
import * as api from './ksp-submit-api'
|
||||||
import { taskStatuses, refresh as refreshTaskStatus } from './task-status-cache'
|
import { taskStatuses, refresh as refreshTaskStatus } from './task-status-cache'
|
||||||
import * as s from 'svelte'
|
import * as s from 'svelte'
|
||||||
|
@ -164,7 +163,7 @@
|
||||||
|
|
||||||
async function upload(file: File) {
|
async function upload(file: File) {
|
||||||
const x = await api.submit(id, uploadSubtaskId!, file)
|
const x = await api.submit(id, uploadSubtaskId!, file)
|
||||||
refreshTaskStatus([id])
|
refreshTaskStatus()
|
||||||
const subtasks = [...task.subtasks]
|
const subtasks = [...task.subtasks]
|
||||||
subtasks[subtasks.findIndex(s => s.id == x.id)] = x
|
subtasks[subtasks.findIndex(s => s.id == x.id)] = x
|
||||||
task = { ...task, subtasks }
|
task = { ...task, subtasks }
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { TasksFile } from "./tasks";
|
import type { TasksFile } from "./tasks";
|
||||||
import { refresh } from './task-status-cache'
|
|
||||||
|
|
||||||
export let promise: Promise<TasksFile>;
|
export let promise: Promise<TasksFile>;
|
||||||
|
|
||||||
|
@ -9,14 +8,12 @@
|
||||||
let err: any | null = null;
|
let err: any | null = null;
|
||||||
promise.then(
|
promise.then(
|
||||||
(d) => {
|
(d) => {
|
||||||
refresh(d.tasks.map(t => t.id))
|
|
||||||
data = d;
|
data = d;
|
||||||
},
|
},
|
||||||
(e) => {
|
(e) => {
|
||||||
err = e;
|
err = e;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if data == null && err == null}
|
{#if data == null && err == null}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { fetchHtml } from "./ksp-task-grabber";
|
import { fetchHtml, isLoggedIn } from "./ksp-task-grabber";
|
||||||
|
|
||||||
let apitoken : string | null = null
|
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<Map<string, TaskStatus>> {
|
||||||
|
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<string, TaskStatus>(
|
||||||
|
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 }])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -14,16 +14,6 @@ type TaskLocation = {
|
||||||
startElement: string
|
startElement: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TaskStatus = {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
submitted: boolean
|
|
||||||
solved: boolean
|
|
||||||
points: number
|
|
||||||
maxPoints: number
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
|
|
||||||
function fixAllLinks(e: any) {
|
function fixAllLinks(e: any) {
|
||||||
if (typeof e.src == "string") {
|
if (typeof e.src == "string") {
|
||||||
e.src = e.src
|
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) {
|
export async function fetchHtml(url: string) {
|
||||||
const r = await fetch(url, { headers: { "Accept": "text/html,application/xhtml+xml" } })
|
const r = await fetch(url, { headers: { "Accept": "text/html,application/xhtml+xml" } })
|
||||||
if (r.status >= 400) {
|
if (r.status >= 400) {
|
||||||
|
@ -196,21 +165,6 @@ export function isLoggedIn(): boolean {
|
||||||
return !!document.head.querySelector("meta[name=x-ksp-uid]")
|
return !!document.head.querySelector("meta[name=x-ksp-uid]")
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function grabTaskStates(kspIds: string[]): Promise<Map<string, TaskStatus>> {
|
|
||||||
if (!isLoggedIn()) throw new Error()
|
|
||||||
|
|
||||||
const ids = new Set<string>(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<string, TaskStatus>(
|
|
||||||
([] as TaskStatus[]).concat(...results)
|
|
||||||
.map(r => [r.id, r])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function grabAssignment(id: string): Promise<TaskAssignmentData> {
|
export async function grabAssignment(id: string): Promise<TaskAssignmentData> {
|
||||||
return await loadTask(getLocation(id, false))
|
return await loadTask(getLocation(id, false))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { grabTaskStates, isLoggedIn} from "./ksp-task-grabber"
|
import { isLoggedIn } from "./ksp-task-grabber"
|
||||||
import type { TaskStatus } from "./ksp-task-grabber"
|
import { grabTaskSummary } from './ksp-submit-api'
|
||||||
|
import type { TaskStatus } from "./ksp-submit-api"
|
||||||
import { readable } from 'svelte/store';
|
import { readable } from 'svelte/store';
|
||||||
|
|
||||||
let writeFn: (value: Map<string, TaskStatus>) => void = null!;
|
let writeFn: (value: Map<string, TaskStatus>) => void = null!;
|
||||||
|
@ -14,12 +15,14 @@ export const taskStatuses = readable(lastVal, write => {
|
||||||
writeFn = v => { lastVal = v; write(v); }
|
writeFn = v => { lastVal = v; write(v); }
|
||||||
})
|
})
|
||||||
|
|
||||||
export function refresh(ids: string[]) {
|
export function refresh() {
|
||||||
if (!isLoggedIn()) return;
|
if (!isLoggedIn()) return;
|
||||||
|
|
||||||
return grabTaskStates(ids).then(t => {
|
return grabTaskSummary().then(t => {
|
||||||
const tt = Array.from(t.entries())
|
const tt = Array.from(t.entries())
|
||||||
writeFn(new Map(Array.from(lastVal.entries()).concat(tt)))
|
writeFn(new Map(Array.from(lastVal.entries()).concat(tt)))
|
||||||
localStorage.setItem("taskStatuses-cache", JSON.stringify(tt))
|
localStorage.setItem("taskStatuses-cache", JSON.stringify(tt))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refresh()
|
||||||
|
|
Reference in a new issue