feat(codechef): implement full CodeChef support (#354)

## Problem

CodeChef had no working login, submit, or contest list. The browser
selectors were wrong, the contest list was missing present/past
contests,
and problem/contest URLs were unset.

## Solution

Fix login and submit selectors for the Drupal-based site. Paginate
`/api/list/contests/past` to collect all 228 Starters, then expand each
parent contest into individual division entries (e.g. `START228 (Div.
4)`).
Add language IDs, correct `url`/`contest_url`/`standings_url` in
metadata,
and make `:CP <platform>` open the contest picker directly.
This commit is contained in:
Barrett Ruth 2026-03-06 23:10:44 -05:00 committed by GitHub
parent c7f2af16d4
commit 3c11d609f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 336 additions and 158 deletions

View file

@ -216,6 +216,10 @@ local function run_scraper(platform, subcommand, args, opts)
end
end
---@param platform string
---@param contest_id string
---@param callback fun(data: table)?
---@param on_error fun()?
function M.scrape_contest_metadata(platform, contest_id, callback, on_error)
run_scraper(platform, 'metadata', { contest_id }, {
on_exit = function(result)
@ -253,6 +257,8 @@ function M.scrape_contest_metadata(platform, contest_id, callback, on_error)
})
end
---@param platform string
---@return { contests: ContestSummary[], supports_countdown: boolean }?
function M.scrape_contest_list(platform)
local result = run_scraper(platform, 'contests', {}, { sync = true })
if not result or not result.success or not (result.data and result.data.contests) then
@ -330,6 +336,10 @@ function M.scrape_all_tests(platform, contest_id, callback, on_done)
})
end
---@param platform string
---@param credentials table
---@param on_status fun(ev: table)?
---@param callback fun(result: table)?
function M.login(platform, credentials, on_status, callback)
local done = false
run_scraper(platform, 'login', {}, {
@ -361,6 +371,14 @@ function M.login(platform, credentials, on_status, callback)
})
end
---@param platform string
---@param contest_id string
---@param problem_id string
---@param language string
---@param source_file string
---@param credentials table
---@param on_status fun(ev: table)?
---@param callback fun(result: table)?
function M.submit(
platform,
contest_id,