Skip to content

1.5.0: optional school mail and attendance - #25

Merged
Waldo0926 merged 16 commits into
mainfrom
feat/student-services
Oct 31, 2026
Merged

Waldo0926 merged 16 commits into
mainfrom
feat/student-services

Conversation

@Waldo0926

@Waldo0926 Waldo0926 commented Oct 31, 2026 •

Copy link
Copy Markdown
Owner

Before:

公开版只有 Moodle 和 Ed。Gmail、考勤和“预览再确认”的写操作只跑在私人部署上。

After:

完整说明见 CHANGELOG 的 1.5.0 一节(发版时会成为 GitHub Release 的内容)。要点:

接入

  • 在 AI 软件里说“帮我接上学校邮箱”或“帮我接上考勤”:新工具 start_school_service_setup 自动装缺的组件,打开登录窗口,接好后同步并通知 AI 软件刷新工具列表。两样都接好后这个工具不再列出。
  • 安装包自带 Google 桌面应用(google_client.json,Monash Student MCP 项目里单独为公开版建的客户端),monash gmail login 不用自己建 Google Cloud 项目;--client 仍可用自己的。
  • 登录后全部功能自动打开,都可以用 monash config 关掉;Gmail 可用 --read-only。

学校邮箱

  • 本地副本:每页单独保存,显示进度,中断后接着下;后台每 30 分钟同步。
  • 邮件待办、离线搜索(带日期、未读、星标、分类、附件数)、读附件。
  • 起草、发送草稿、改标签:每次先预览,用户确认后才执行,凭据绑定预览内容、只能用一次(ADR 0004)。

考勤

  • login|status|sync|overview|codes|probe,以及本地 AI 里的对应工具。
  • 不开浏览器读:一次请求,用 Python 版解析器;结构不对或证书校验不过时退回浏览器。HTTPS 用系统证书校验(truststore)。
  • 按课表自动读;记录登录能维持多久;轻量续期默认关。

远程 MCP

  • 配对页上每个软件自己勾选功能,和服务器设置取交集;之前已经配对的软件只有 Moodle 和 Ed;凭据和后台任务按客户端分开。

其他

  • 课不用 Ed 的可以 monash config use_ed false。
  • monash update 保留所有已装的可选依赖;status、doctor 覆盖邮箱和考勤。
  • Windows CI 修复;__version__ 1.5.0;核心依赖仍然只有 pypdf。

How:

  • 新增测试:test_student_tools.py、test_service_setup.py、test_attendance_fast.py、test_attendance_parity.py(需要浏览器)、test_without_ed.py,test_remote.py 加了按软件授权的 HTTP 流程。
  • 工具清单的测试:上限从 18 个放宽到 19 个,总大小上限不变;原来 17 个工具的参数哈希照旧锁着。

测试结果:

  • PYTHONPATH=src pytest -q:400 passed, 8 skipped(跳过的是需要浏览器的测试;用 playwright 1.63.0 单独跑过,8 passed)
  • uvx ruff@0.6.9 check src tests scripts:All checks passed
  • uv build 加 scripts/check_dist.py:通过;装进干净的 Python 3.10 venv 跑 scripts/smoke_test.py:通过(19 个工具,7 个提示)
  • 真实账号(macOS,马来西亚校区):
    • monash gmail login(用自带的应用)成功,mode: manage;monash gmail sync 下载 500 封;
    • monash attendance probe:15 天两种读法全部一致;monash attendance sync --days 14 用 HTTP 读到 5 节课,内容正确。

尚未验证:

  • 考勤提交还没在真实账号上跑过
  • 考勤登录能维持多久(会自动记录)、轻量续期有没有用
  • 马来西亚以外校区的门户
  • 在 AI 里“说一声就接好”的完整流程,以及一台完全没装过组件的电脑上的自动安装
  • 远程勾选流程在真实的 Claude/ChatGPT 连接器上

发布:合并后在 main 上打 v1.5.0 tag 并推送,release 工作流会检查版本号和 CHANGELOG、跑测试、发 PyPI、建 GitHub Release。

  • Tests added or updated, and uv run pytest -q passes
  • uvx ruff@0.6.9 check src tests scripts passes
  • If src/ changed: __version__ bumped and CHANGELOG.md updated
  • Still read-only, and no real names, ids, cookies or tokens in test samples(测试样例只有 example.edu 这类假数据。Moodle 和 Ed 仍然只读;邮箱和考勤的操作登录后就有,每次执行都要确认。google_client.json 是公开发布用的桌面应用客户端,按 Google 的设计不算机密)

Replaces the six shared modules with the versions running on the private
deployment after real-account testing on 2026-10-31, and adds their tests
and the Chinese setup guide. Not yet integrated: two existing tests fail
(rollback expectation and optional-dependency policy) and the CLI/MCP glue
still targets the earlier module API. See the porting PR for the remaining
work.

Fixes carried over: Gmail rate-limit retries, per-page sync commits,
history label/deletion events without downloads, search result flags,
mail to-do, label names and whole-thread actions, rejected state for
pre-send checks, 30-day record cleanup, Attendance day selection through
the portal's #daySel menu, configurable portal origin and timezone.
- Rewrite the rollback test for per-page sync commits and allow the gmail
  and attendance extras in the dependency test (core still only pypdf).
- cli_gmail: add `gmail todo`, explain resumable and pending syncs.
- New `monash attendance login|status|sync`; login turns on
  attendance_enabled.
- student_tools picks the local MCP tools from settings: read-only mail
  (now with get_gmail_inbox_todo) and attendance_status/overview when
  enabled; gmail_prepare_action, attendance_prepare_submit and
  execute_student_action only with gmail_manage_enabled or
  attendance_submit_enabled. Writes still go through preview tickets.
- Server instructions point mail questions at this server; help lists
  mail and attendance only when on.
- remote.py rejects every mail and attendance tool, as before.
- Docs: README sections, setup guide on public commands, design notes
  updated, changelog entry. Lock file now includes the extras; tzdata
  for Windows attendance.
Background mail sync: while the MCP server runs (local or remote serve),
mail syncs every gmail_sync_minutes (30, 0 turns it off) in its own
thread. It keeps the last query, comes back about a minute later while
the first download is unfinished, indexes up to five attachments after a
full round and logs an expired login only once.

Remote per-app grants: the pairing page shows a checkbox for each mail
and attendance feature the server has turned on (read-only ticked, write
unticked). The choice is stored on codes and tokens, kept on refresh,
intersected with the server settings on every call and shown by
`monash remote clients`. Tokens from before the new column stay
monash-only. Remote apps get the student_services catalog plus
gmail_inbox_todo and student_job_status; tickets and jobs are keyed by
client ID so one app cannot run another's ticket.
@Waldo0926 Waldo0926 changed the title Optional Gmail and attendance in the CLI and local MCP Optional Gmail and attendance: CLI, local MCP, background mail sync and per-app remote grants Oct 31, 2026
- Local MCP with attendance_enabled now also registers attendance_sync,
  attendance_find_codes and attendance_export as background jobs, plus
  student_job_status. With gmail_enabled it adds gmail_read_attachment.
- gmail_prepare_action checks the saved Google authorization has write
  access before preparing, so a read-only login no longer ends with a
  ticket stuck as unknown (local and remote).
- monash update keeps every installed extra (gmail, attendance, media);
  it used to keep only media and would have dropped the others.
- monash attendance overview and codes for use without an AI app.
- monash status and doctor show mail and attendance when they are on;
  doctor never prints the mail address.
- A missing [gmail] install says what to install instead of looking like
  a network error.
- Agent skill, help menu, README, setup guide, design notes, privacy note
  and changelog updated, including the measured token cost.
… HTTP read

- Background attendance reads follow the timetable: weekday mornings at
  8 and 15 minutes after each class not yet checked in to; nothing at
  night, at weekends or for finished classes (attendance_auto_sync).
- Browser reads open Units.aspx once and switch days with #daySel
  instead of reloading for each day.
- attendance_http: optional browser-free read with the saved cookies and
  a Python port of extract-rows.js (attendance_fast_read, off by
  default). Falls back to the browser when the menu or a day panel is
  missing. Parity tests run both parsers on the same pages.
- `monash attendance probe` compares both reads on the real portal and
  prints only counts and match results.
- attendance_auto records logins, successful reads and the first expiry;
  status and doctor show how long the login lasted. Optional HTTP
  keepalive saves renewed cookies (attendance_keepalive_minutes, off).
- Gmail test messages use a real timestamp. Windows cannot turn a time
  in the first day after 1970 into local time (OSError 22), which broke
  three tests there; real mail never has such a time.
- The browser-free attendance read verifies HTTPS with the system
  certificate store through truststore, so a portal that leaves out its
  intermediate certificate still verifies on macOS and Windows. When it
  still cannot be verified the read falls back to the browser and probe
  reports it instead of exiting. Verification is never disabled.
- __version__ 1.5.0 for the new features, as the version check requires.
@Waldo0926
Waldo0926 force-pushed the feat/student-services branch from f63eb1a to 4cd0886 Compare October 31, 2026 04:21
monash attendance probe on the Malaysia portal: all 15 day panels are in
the page HTML and the Python and browser reads matched on every day, with
the system certificate store. The read still falls back to the browser
when the page does not look as expected.

Every portal request now counts toward the login lifetime, so a
successful probe or read updates it too (it showed 0 hours before).
The portal writes times first and as "4:00 pm". Check the parser and the
after-class schedule with that format, as seen on a real read.
monash gmail login now asks for gmail.modify and turns on both Gmail
settings; --read-only asks for gmail.readonly and leaves mailbox actions
off (--manage is still accepted). monash attendance login turns on both
attendance settings. Every action still goes through the preview and
confirmation ticket, and each can be switched off with monash config.

ADR 0004 records the decision: Moodle and Ed stay read-only, mail and
attendance actions are on after login and only run after confirmation.
README, setup guide, design notes, privacy policy and changelog updated.
monash gmail login now checks the --client file first and says what the
path should be, how to drag the file into Terminal on macOS, and where
the setup guide explains creating it.
monash config use_ed false, or answering yes in monash setup after
skipping the Ed token, stops sync, the to-do list and monash doctor from
reporting a missing token, hides the four Ed tools and the Ed part of the
help, and tells the AI app not to suggest Ed. The default is unchanged and
monash login ed turns it back on. Everything else already worked without
Ed; this removes the nagging.
monash gmail login uses google_client.json from the package when no
--client is given, so students only need to click through Google's
consent page. --client still uses your own desktop client. A test checks
that a bundled file is a desktop client, never a web client.

The guide and READMEs now point people who only want to ask about their
inbox to the AI apps' built-in Gmail connectors, explain the unverified
app warning, and make creating your own Google app optional. The privacy
policy says what the bundled client is and that mail never passes
through the maintainer.
A separate desktop client in the Monash Student MCP project, so students
can run monash gmail login without their own Google Cloud setup. The
private deployment keeps its own client.
start_school_service_setup lets a student say "connect my school email"
or "connect my attendance" in the AI app. In the background it installs
the missing packages into the running install (uv, or pip), downloads
the Playwright browser for attendance, opens the sign-in window, turns
the features on, syncs once and sends notifications/tools/list_changed.
Passwords and codes stay in the student's browser. The tool is local
only (not offered remotely) and hidden once both are connected.

The catalog limit goes from 18 to 19 tools; the size limit and the
pinned contracts of the original 17 tools are unchanged. Default cost is
145 tokens per conversation (3,377 in total).

monash gmail sync now downloads one page at a time and prints a line per
page, so the first sync no longer looks stuck.
Turn the Unreleased notes into a 1.5.0 section grouped by connecting,
school mail, attendance, remote and other changes; it becomes the GitHub
release text. Install commands in the READMEs and setup guide now use
PyPI, both READMEs get a "What's new in 1.5" section, and the release
doc no longer says the smoke test expects 17 tools.
@Waldo0926 Waldo0926 changed the title Optional Gmail and attendance: CLI, local MCP, background mail sync and per-app remote grants 1.5.0: optional school mail and attendance Oct 31, 2026
@Waldo0926
Waldo0926 merged commit 01f401e into main Oct 31, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant