diff --git a/lua/cp/submit.lua b/lua/cp/submit.lua
index 77e3d66..50d884f 100644
--- a/lua/cp/submit.lua
+++ b/lua/cp/submit.lua
@@ -54,6 +54,7 @@ function M.submit(opts)
logger.log('Source file not found', { level = vim.log.levels.ERROR })
return
end
+ source_file = vim.fn.fnamemodify(source_file, ':p')
prompt_credentials(platform, function(creds)
vim.cmd.update()
diff --git a/scrapers/kattis.py b/scrapers/kattis.py
index 43ce1f3..734705e 100644
--- a/scrapers/kattis.py
+++ b/scrapers/kattis.py
@@ -221,25 +221,17 @@ async def _save_kattis_cookies(client: httpx.AsyncClient) -> None:
_COOKIE_PATH.write_text(json.dumps(cookies))
-async def _check_kattis_login(client: httpx.AsyncClient) -> bool:
- try:
- r = await client.get(BASE_URL + "/", headers=HEADERS, timeout=HTTP_TIMEOUT)
- text = r.text.lower()
- return "sign out" in text or "logout" in text or "my profile" in text
- except Exception:
- return False
-
-
async def _do_kattis_login(
client: httpx.AsyncClient, username: str, password: str
) -> bool:
+ client.cookies.clear()
r = await client.post(
- f"{BASE_URL}/login/email",
+ f"{BASE_URL}/login",
data={"user": username, "password": password, "script": "true"},
headers=HEADERS,
timeout=HTTP_TIMEOUT,
)
- return r.status_code == 200 and "login failed" not in r.text.lower()
+ return r.status_code == 200
class KattisScraper(BaseScraper):
@@ -330,9 +322,7 @@ class KattisScraper(BaseScraper):
async with httpx.AsyncClient(follow_redirects=True) as client:
await _load_kattis_cookies(client)
- print(json.dumps({"status": "checking_login"}), flush=True)
- logged_in = bool(client.cookies) and await _check_kattis_login(client)
- if not logged_in:
+ if not client.cookies:
print(json.dumps({"status": "logging_in"}), flush=True)
ok = await _do_kattis_login(client, username, password)
if not ok:
@@ -351,18 +341,35 @@ class KattisScraper(BaseScraper):
}
if contest_id != problem_id:
data["contest"] = contest_id
- try:
- r = await client.post(
+
+ async def _do_submit() -> httpx.Response:
+ return await client.post(
f"{BASE_URL}/submit",
data=data,
files={"sub_file[]": (f"solution.{ext}", source, "text/plain")},
headers=HEADERS,
timeout=HTTP_TIMEOUT,
)
+
+ try:
+ r = await _do_submit()
r.raise_for_status()
except Exception as e:
return self._submit_error(f"Submit request failed: {e}")
+ if r.text == "Request validation failed":
+ _COOKIE_PATH.unlink(missing_ok=True)
+ print(json.dumps({"status": "logging_in"}), flush=True)
+ ok = await _do_kattis_login(client, username, password)
+ if not ok:
+ return self._submit_error("Login failed (bad credentials?)")
+ await _save_kattis_cookies(client)
+ try:
+ r = await _do_submit()
+ r.raise_for_status()
+ except Exception as e:
+ return self._submit_error(f"Submit request failed: {e}")
+
sid_m = re.search(r"Submission ID:\s*(\d+)", r.text, re.IGNORECASE)
sid = sid_m.group(1) if sid_m else ""
return SubmitResult(
@@ -376,21 +383,10 @@ class KattisScraper(BaseScraper):
return self._login_error("Missing username or password")
async with httpx.AsyncClient(follow_redirects=True) as client:
- await _load_kattis_cookies(client)
- if client.cookies:
- print(json.dumps({"status": "checking_login"}), flush=True)
- if await _check_kattis_login(client):
- return LoginResult(
- success=True,
- error="",
- credentials={"username": username, "password": password},
- )
-
print(json.dumps({"status": "logging_in"}), flush=True)
ok = await _do_kattis_login(client, username, password)
if not ok:
return self._login_error("Login failed (bad credentials?)")
-
await _save_kattis_cookies(client)
return LoginResult(
success=True,
diff --git a/scrapers/language_ids.py b/scrapers/language_ids.py
index 6870aa3..1abfcc6 100644
--- a/scrapers/language_ids.py
+++ b/scrapers/language_ids.py
@@ -16,7 +16,7 @@ LANGUAGE_IDS = {
"python": "python",
},
"kattis": {
- "cpp": "C++17",
+ "cpp": "C++",
"python": "Python 3",
},
"codechef": {
diff --git a/scrapers/usaco.py b/scrapers/usaco.py
index 73ec6b1..074cbf9 100644
--- a/scrapers/usaco.py
+++ b/scrapers/usaco.py
@@ -29,7 +29,7 @@ CONNECTIONS = 4
_COOKIE_PATH = Path.home() / ".cache" / "cp-nvim" / "usaco-cookies.json"
_LOGIN_PATH = "/current/tpcm/login-session.php"
-_SUBMIT_PATH = "/current/tpcm/submitproblem.php"
+_SUBMIT_PATH = "/current/tpcm/submit-solution.php"
_LANG_KEYWORDS: dict[str, list[str]] = {
"cpp": ["c++17", "c++ 17", "g++17", "c++", "cpp"],
@@ -141,13 +141,16 @@ def _parse_problem_page(html: str) -> dict[str, Any]:
def _pick_lang_option(select_body: str, language_id: str) -> str | None:
keywords = _LANG_KEYWORDS.get(language_id.lower(), [language_id.lower()])
- for m in re.finditer(
- r'