diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 191c7ba..0910252 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -53,7 +53,7 @@ Unit files live in this repo (deploy/systemd/) and are installed in ~/.config/sy (+0-15 min random, Persistent=true so a missed run happens at boot). Steps: list -> Claude triage -> details -> Claude score -> Claude category -> pool -> notifications (see docs/PIPELINE.md). Also: marks jobs applied to by hand as Applied, asks NUworks about every sent row (the total - limit counts what NUworks has: jobs.check_applications, data/applications.json; it also sets the sheet's Status + limit counts what NUworks has: jobs.check_applications, data/applications.json; a Rejected row NUworks still has is listed in the log and in the morning message until you withdraw it there; it also sets the sheet's Status dropdown again, so Accepted / Rejected reach an older sheet), warns the day before the Google login expires. Every run records its counts in data/scans.json. The morning run adds deadline reminders and the "NUauto morning" message (always sent): new postings and new pool jobs in the last 24h, then the to-do list (company-site applications owed, diff --git a/src/nuauto/daily.py b/src/nuauto/daily.py index 1c9b4c9..ed888bb 100644 --- a/src/nuauto/daily.py +++ b/src/nuauto/daily.py @@ -199,6 +199,13 @@ def applications(): missing = sorted(sheet.not_on_nuworks(rows, seen)) log(f"applications: {sheet.total_count(rows, seen)} count toward the total" + (f"; NUworks has none for row{'s' if len(missing) > 1 else ''} {', '.join(map(str, missing))}" if missing else "")) + waiting = sheet.rejected_not_withdrawn(rows, seen) + if waiting: + log(f"rejected, not withdrawn on NUworks: row{'s' if len(waiting) > 1 else ''} {', '.join(str(r.number) for r in waiting)}") + if datetime.now().hour < 12: # the message once a day, with the morning run + notify(f"{len(waiting)} rejected application{'s' if len(waiting) > 1 else ''} still on NUworks", + "\n".join(f"{r.title[:40]} | {r.company[:22]}" for r in waiting) + + "\nWithdraw on NUworks: until you do they count toward the total.") def internships(): diff --git a/src/nuauto/sheet.py b/src/nuauto/sheet.py index b665dc7..3f004b7 100644 --- a/src/nuauto/sheet.py +++ b/src/nuauto/sheet.py @@ -135,6 +135,19 @@ def not_on_nuworks(rows, seen=None): return out +def rejected_not_withdrawn(rows, seen=None): + """The Rejected rows of the NUworks tab whose application NUworks still has (the last check, about the row as it is + now): you haven't withdrawn it there, so it still counts toward the total. Never asked = not listed.""" + from nuauto import jobs + seen = nuworks_seen() if seen is None else seen + out = [] + for r in rows: + s = seen.get(jobs.job_id(r.url)) if r.status == "Rejected" and r.url else None + if s and s.get("applied") and s.get("fingerprint") == fingerprint(r): + out.append(r) + return out + + def total_count(rows, seen=None): """What counts toward the total limit: the sent rows NUworks has (or hasn't been asked about yet). The NUworks tab's rows only (the Other jobs tab has no limits). Until 2026-10-16 every Applied row counted, also those never sent diff --git a/tests/test_daily.py b/tests/test_daily.py index 80d4834..b274182 100644 --- a/tests/test_daily.py +++ b/tests/test_daily.py @@ -38,6 +38,7 @@ assert asked == ["dropdown", 2], asked log_text = open(daily.LOG_PATH).read() assert "applications: 1 count toward the total; NUworks has none for row 2" in log_text, log_text[-300:] +assert "rejected, not withdrawn on NUworks: row 3" in log_text, log_text[-300:] # NUworks still has the Rejected row's application def no_nuworks(rows): raise SystemExit(daily.jobs.NOT_LOGGED_IN) daily.jobs.check_applications = no_nuworks diff --git a/tests/test_sheet.py b/tests/test_sheet.py index cb58f90..b1f3092 100644 --- a/tests/test_sheet.py +++ b/tests/test_sheet.py @@ -89,6 +89,11 @@ def expect(exc, fn): "c": {"applied": False, "fingerprint": "an earlier version of the row"}} assert sheet.not_on_nuworks(R3, seen) == {2} and sheet.total_count(R3, seen) == 2 assert check_limits(R3, TODAY, seen=seen) == (3, 2) # the week still counts all three +# a Rejected row NUworks still has an application for is one you haven't withdrawn there: listed until it is +on = {"c": {"applied": True, "fingerprint": fp["c"]}} +assert [r.number for r in sheet.rejected_not_withdrawn(R3, on)] == [4] +on["c"]["applied"] = False +assert sheet.rejected_not_withdrawn(R3, on) == [] and sheet.rejected_not_withdrawn(R3, {}) == [] # withdrawn / never asked R3[0].notes += " NUworks side submitted." # it changed since NUworks was asked: it counts assert sheet.total_count(R3, seen) == 3 and sheet.total_count(R3, {}) == 3 # (never asked: counts) many = rows_with([("Applied", "2026-09-01")] * sheet.MAX_TOTAL)