Skip to content

Commit 25f12db

Browse files
tangmc0210claude
andcommitted
feat(timetable): catalog links, scoped overrides, tags, exam schedule and share assets
Iteration 3 of the timetable (README §8): - Entries link to the course catalog on import (blank fields filled, the student's values win) and carry role (已选/旁听), category (course/exam/ other) and a free tag; POST catalog/<id>/add/ adds a catalog course as 旁听. - Per-week overrides (TimetableEntryOverride) back PATCH entries/<id>/ with scope all/single/following and a canceled flag; imported entries keep the student's edits across re-imports; GET entries/<id>/ and DELETE overrides. - Settings expose the registered sources, the student's tags and hidden_tags; a new exam source matches the term's CourseExam rows (import_exam_schedule) to the student's courses; terms gain exam_week_start / teaching_weeks and the seed calendars cover the exam weeks. - GET share/assets/ serves the mini-program code (wxacode, cached) and the official-account QR code for the poster. - Spectacular enum names pinned for the new choice sets. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012t4BD5H1P5nn2zF7oU6q9e
1 parent ba4ff59 commit 25f12db

42 files changed

Lines changed: 4371 additions & 168 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ then be registered with `include()` in `api/urls.py`.
4444
| `org/` | Organization subscription listing and subscription status updates. | `/api/v2/org/` |
4545
| `generic/` | Cross-feature mini-program data, currently the homepage carousel. | `/api/v2/generic/` |
4646
| `pku_account/` | PKU (IAAA) account binding: portal login with one-time credentials, binding status, consents, unbinding. Contract in `timetable/README.md` §3. | `/api/v2/pku/` |
47-
| `timetable/` | Personal timetable: terms, week view, stored entries, portal/text import, settings, ICS link, subscribe-message quota, course-catalog search. Contract in `timetable/README.md` §4 and §6. | `/api/v2/timetable/` |
47+
| `timetable/` | Personal timetable: terms, week view, agenda, stored entries with per-week overrides (scoped edits) and catalog links, catalog search and quick add (旁听), portal/text import, settings (source toggles, hidden tags), ICS link, subscribe-message quota, exam schedule source, poster share assets. Contract in `timetable/README.md` §4, §6 and §8. | `/api/v2/timetable/` |
4848
| `academic_record/` | Consent-gated grade records fetched through the PKU binding: stored grades, live sync, deletion. Contract in `timetable/README.md` §6.2. | `/api/v2/grades/` |
4949

5050
Many modules use DRF `DefaultRouter`; routes generated from ViewSets and

api/activity/serializers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
from app.models import Activity, Participation
88
from app.utils import get_person_or_org
99

10+
# Named in SPECTACULAR_SETTINGS['ENUM_NAME_OVERRIDES'] so the schema keeps a
11+
# stable component name for the activity category enum.
12+
ACTIVITY_CATEGORY_CHOICES = Activity.ActivityCategory.choices
13+
1014

1115
class ActivitySummarySerializer(serializers.ModelSerializer):
1216
"""Serializer for activity summary display."""

api/config.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""
22
Configuration helpers for API layer.
33
4-
Covers the mini program (wx) login flow and the subscribe-message templates
5-
used by class reminders (``timetable/README.md`` §6.1).
4+
Covers the mini program (wx) login flow, the subscribe-message templates
5+
used by class reminders (``timetable/README.md`` §6.1) and the share
6+
assets of the timetable poster (§8.5).
67
"""
78
from boot.config import ROOT_CONFIG
89
from utils.config import Config, LazySetting
@@ -12,7 +13,10 @@
1213
"CONFIG",
1314
"DEFAULT_SUBSCRIBE_FIELDS",
1415
"DEFAULT_SUBSCRIBE_PAGE",
16+
"DEFAULT_SHARE_PAGE",
17+
"DEFAULT_SHARE_SLOGAN",
1518
"get_subscribe_template",
19+
"get_share_config",
1620
]
1721

1822
# Semantic field -> WeChat template key, used when a template omits "fields".
@@ -23,6 +27,8 @@
2327
"note": "thing4",
2428
}
2529
DEFAULT_SUBSCRIBE_PAGE = "pages/timetable/index"
30+
DEFAULT_SHARE_PAGE = "pages/timetable/index"
31+
DEFAULT_SHARE_SLOGAN = "元培智慧书院 · YPPF"
2632

2733
class WXMiniappConfig(Config):
2834
"""
@@ -47,11 +53,34 @@ class WXMiniappConfig(Config):
4753
# Subscribe-message templates: {key: {"id", "fields", "page"}}. An empty
4854
# "id" disables that template (see get_subscribe_template).
4955
subscribe_templates = LazySetting("subscribe_templates", default={}, type=dict)
56+
# Share assets of the timetable poster (timetable/README.md §8.5): the
57+
# page the mini-program code opens, the code's env_version, the
58+
# official-account QR code (absolute URL or a path under MEDIA_URL;
59+
# empty → none) and the poster slogan.
60+
share_miniapp_page = LazySetting(
61+
"share/miniapp_page", default=DEFAULT_SHARE_PAGE, type=str)
62+
share_env_version = LazySetting("share/env_version", default="release", type=str)
63+
share_official_qrcode_url = LazySetting(
64+
"share/official_qrcode_url", default="", type=str)
65+
share_slogan = LazySetting("share/slogan", default=DEFAULT_SHARE_SLOGAN, type=str)
5066

5167

5268
CONFIG = WXMiniappConfig(ROOT_CONFIG, "wx_miniapp")
5369

5470

71+
def get_share_config() -> dict:
72+
"""
73+
The ``wx_miniapp.share`` block with defaults filled in:
74+
``{"miniapp_page", "env_version", "official_qrcode_url", "slogan"}``.
75+
"""
76+
return {
77+
"miniapp_page": str(CONFIG.share_miniapp_page or DEFAULT_SHARE_PAGE).strip(),
78+
"env_version": str(CONFIG.share_env_version or "release").strip(),
79+
"official_qrcode_url": str(CONFIG.share_official_qrcode_url or "").strip(),
80+
"slogan": str(CONFIG.share_slogan or DEFAULT_SHARE_SLOGAN).strip(),
81+
}
82+
83+
5584
def get_subscribe_template(key: str) -> dict | None:
5685
"""
5786
The subscribe-message template ``key`` of ``wx_miniapp.subscribe_templates``

0 commit comments

Comments
 (0)