feat(v1.4.0): CSV/Excel/JSON/NextUp exports + hybrid smart year standing #4

Merged
adrianbonpin merged 5 commits from feat/ismis-helper-v1.4.0 into prod 2026-08-20 04:39:09 +00:00
Owner

v1.4.0 — Exports + Smart Year Standing

Exports (on the Study Load page, next to Download PDF)

  • CSV — header block + course table + total, RFC-4180 with UTF-8 BOM
  • Excel (.xlsx) — zero-dependency hand-rolled XLSX/ZIP writer (verified opens in openpyxl)
  • JSON — clean improved schema (meta / courses / totals)
  • Next Up — CSV in the exact raycast/nextup column contract so schedules import directly

Hybrid Smart Year Level (per-semester standing)

For the semester being printed:

  1. custom setting wins
  2. View Grades history (exact per-semester standing)
  3. units math (prospectus total − lacking), clamped
  4. profile-scraped fallback

Popup gains a Year Level mode setting (auto / custom / off).

Pipeline

  • Builds now run only on v tags*; tests on pushes/PRs via new ci.yml
  • Optional AMO sign step produces a signed .xpi for permanent install
  • CI validates XLSX via openpyxl

Verification

  • 35 unit tests pass; XLSX validated via real openpyxl; web-ext lint 0 errors
  • Parsers validated against real View Grades / prospectus / lacking HTML
  • Version bumped to 1.4.0 (fresh version for AMO signing)
## v1.4.0 — Exports + Smart Year Standing ### Exports (on the Study Load page, next to Download PDF) - **CSV** — header block + course table + total, RFC-4180 with UTF-8 BOM - **Excel (.xlsx)** — zero-dependency hand-rolled XLSX/ZIP writer (verified opens in openpyxl) - **JSON** — clean improved schema (`meta` / `courses` / `totals`) - **Next Up** — CSV in the exact `raycast/nextup` column contract so schedules import directly ### Hybrid Smart Year Level (per-semester standing) For the semester being printed: 1. custom setting wins 2. View Grades history (exact per-semester standing) 3. units math (prospectus total − lacking), clamped 4. profile-scraped fallback Popup gains a Year Level mode setting (auto / custom / off). ### Pipeline - Builds now run **only on v* tags**; tests on pushes/PRs via new `ci.yml` - Optional AMO sign step produces a signed `.xpi` for permanent install - CI validates XLSX via openpyxl ### Verification - 35 unit tests pass; XLSX validated via real openpyxl; web-ext lint 0 errors - Parsers validated against real View Grades / prospectus / lacking HTML - Version bumped to 1.4.0 (fresh version for AMO signing)
adrianbonpin added 2 commits 2026-08-19 23:14:41 +00:00
- Export modules (export-csv/json/xlsx) mirroring the PDF layout, plus a
  Next Up import CSV matching the raycast/nextup column contract.
- Hybrid Year Level: View Grades history (exact per-semester standing),
  falling back to units math (prospectus total - lacking), then profile.
  Popup adds a year-mode setting (auto/custom/off).
- On-page button row now offers PDF / CSV / Excel / JSON / Next Up.
- Bump version to 1.4.0.
- Tag-only build workflow with an optional AMO sign step for a signed .xpi;
  separate ci.yml keeps tests on pushes/PRs.
- Tests: year-standing parser tests + export tests (CSV quoting, JSON schema,
  XLSX structure); CI validates XLSX via openpyxl.
ci: run tests on v1.4.0 feature branch
ci / test (push) Successful in 2m9s
ci / test (pull_request) Successful in 42s
3067335274
adrianbonpin added 1 commit 2026-08-20 00:54:58 +00:00
fix(year-level): prefer units-passed standing over calendar-year history count
ci / test (push) Successful in 2m21s
ci / test (pull_request) Successful in 38s
90e4107bf0
The grade-history method counted distinct academic years, which over-advanced
standing for students who repeated/failed a year (e.g. showing Year 5 when the
student is genuinely Year 4, since a partial 2025 year didn't advance them).

Reorder the hybrid so the UNITS math (total prospectus units minus still-lacking
units = units actually passed) is primary, and View Grades history is only a
fallback when units data is unavailable.
adrianbonpin added 1 commit 2026-08-20 01:02:19 +00:00
feat(progress): live status bar + % complete during exports
ci / test (push) Successful in 39s
ci / test (pull_request) Successful in 44s
eb7087d506
Adds a progress bar below the export buttons showing the current step
(reading table, fetching course descriptions i/N, profile, year level,
building file) with a 0-100% fill. Threads an onProgress callback through
scrapeStudyLoad and resolveYearLevel. Buttons disable during export to
prevent double-triggers; bar clears ~3s after success.
adrianbonpin added 1 commit 2026-08-20 04:28:02 +00:00
feat(security): encrypt profile passwords at rest with AES-GCM
ci / test (push) Successful in 57s
ci / test (pull_request) Successful in 52s
7adad7cbc8
Passwords are now encrypted with Web Crypto AES-GCM (256-bit) before being
stored in browser.storage.local. The random key is persisted so it survives
browser/service-worker restarts (otherwise old ciphertext could never be
decrypted). Encryption/decryption happen in the background via
encrypt-password/decrypt-password messages; autoLogin decrypts on the fly and
falls back to a legacy plaintext password for pre-encryption profiles. The
popup never reveals a stored password and preserves it when editing with a
blank field.

Removes the plaintext-password-at-rest smell flagged in the design review.
Note: this is at-rest obfuscation-level security (the key ships with the
extension); the extension only talks to the school portal.
adrianbonpin merged commit 0cb70ecee0 into prod 2026-08-20 04:39:09 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adrianbonpin/ismis-helper#4