Skip to content
This repository has been archived by the owner on Sep 24, 2023. It is now read-only.

Commit

Permalink
fix: course registration APIs for graduate students
Browse files Browse the repository at this point in the history
  • Loading branch information
UNIDY2002 committed Sep 8, 2023
1 parent b25053d commit 9b89f99
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 32 deletions.
12 changes: 12 additions & 0 deletions src/constants/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,18 @@ export const CR_TREE_URL =
"https://webvpn.tsinghua.edu.cn/https-443/77726476706e69737468656265737421eaff4b8b3f3b2653770bc7b88b5c2d320506b1aec738590a49ba/xkBks.vxkBksXkbBs.do?m=showTree&p_xnxq=";
export const CR_SELECT_URL =
"https://webvpn.tsinghua.edu.cn/https-443/77726476706e69737468656265737421eaff4b8b3f3b2653770bc7b88b5c2d320506b1aec738590a49ba/xkBks.vxkBksXkbBs.do";
export const CR_SEARCH_YJS_URL =
"https://webvpn.tsinghua.edu.cn/https-443/77726476706e69737468656265737421eaff4b8b3f3b2653770bc7b88b5c2d320506b1aec738590a49ba/xkYjs.vxkYjsJxjhBs.do";
export const CR_ZYTJB_YJS_URL =
"https://webvpn.tsinghua.edu.cn/https-443/77726476706e69737468656265737421eaff4b8b3f3b2653770bc7b88b5c2d320506b1aec738590a49ba/xkYjs.xkYjsZytjb.do";
export const COURSE_PLAN_YJS_URL =
"https://webvpn.tsinghua.edu.cn/http/77726476706e69737468656265737421eaff4b8b3f3b2653770bc7b88b5c2d320506b1aec738590a49ba/jhYjs.vjhYjsGrpyfab.do";
export const CR_MAIN_YJS_URL =
"https://webvpn.tsinghua.edu.cn/https-443/77726476706e69737468656265737421eaff4b8b3f3b2653770bc7b88b5c2d320506b1aec738590a49ba/xkYjs.vxkYjsXkbBs.do?m=main";
export const CR_TREE_YJS_URL =
"https://webvpn.tsinghua.edu.cn/https-443/77726476706e69737468656265737421eaff4b8b3f3b2653770bc7b88b5c2d320506b1aec738590a49ba/xkYjs.vxkYjsXkbBs.do?m=showTree&p_xnxq=";
export const CR_SELECT_YJS_URL =
"https://webvpn.tsinghua.edu.cn/https-443/77726476706e69737468656265737421eaff4b8b3f3b2653770bc7b88b5c2d320506b1aec738590a49ba/xkYjs.vxkYjsXkbBs.do";
export const SPORTS_BASE_URL =
"https://webvpn.tsinghua.edu.cn/http/77726476706e69737468656265737421a5a70f8834396657761d88e29d51367b6a00/gymbook/gymBookAction.do?ms=viewGymBook&viewType=m";
export const SPORTS_DETAIL_URL =
Expand Down
80 changes: 48 additions & 32 deletions src/lib/cr.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import {InfoHelper} from "../index";
import {
COURSE_PLAN_URL_PREFIX,
COURSE_PLAN_YJS_URL,
CR_CAPTCHA_URL,
CR_LOGIN_HOME_URL,
CR_LOGIN_SUBMIT_URL,
CR_MAIN_URL,
CR_MAIN_YJS_URL,
CR_SEARCH_URL,
CR_SEARCH_YJS_URL,
CR_SELECT_URL,
CR_SELECT_YJS_URL,
CR_TIMETABLE_URL,
CR_TREE_URL,
CR_TREE_YJS_URL,
CR_ZYTJB_URL,
CR_ZYTJB_YJS_URL,
} from "../constants/strings";
import {uFetch} from "../utils/network";
import cheerio from "cheerio";
Expand Down Expand Up @@ -184,12 +190,12 @@ export const getCrAvailableSemesters = async (helper: InfoHelper): Promise<CrSem
undefined,
"",
async () => {
const root = await crFetch(CR_MAIN_URL);
const root = await crFetch(helper.graduate() ? CR_MAIN_YJS_URL : CR_MAIN_URL);
const baseSemIdRes = /m=showTree&p_xnxq=(\d\d\d\d-\d\d\d\d-\d)/.exec(root);
if (baseSemIdRes === null) {
throw new CrError();
}
const $ = await crFetch(CR_TREE_URL + baseSemIdRes[1]).then(cheerio.load);
const $ = await crFetch((helper.graduate() ? CR_TREE_YJS_URL : CR_TREE_URL) + baseSemIdRes[1]).then(cheerio.load);
return $("option").toArray().map((e) => ({
id: (e as TagElement).attribs.value,
name: ((e as TagElement).children[0] as TextElement).data?.trim(),
Expand All @@ -203,20 +209,30 @@ export const getCoursePlan = async (helper: InfoHelper, semester: string) => roa
undefined,
"",
async () => {
const data = await crFetch(COURSE_PLAN_URL_PREFIX + semester);
const data = await crFetch(helper.graduate() ? COURSE_PLAN_YJS_URL : COURSE_PLAN_URL_PREFIX + semester);
const courses = cheerio(".trr2", data);
const result: CoursePlan[] = [];
courses.each((_, element) => {
if (element.type === "tag") {
const rawItems = cheerio(element).children();
const items = rawItems.length === 7 ? rawItems.slice(2) : rawItems;
result.push({
id: getCheerioText(items[0], 1),
name: cheerio(cheerio(cheerio(cheerio(items[1]).children()[0]).children()[0]).children()[0]).text().trim(),
property: getCheerioText(items[2], 1),
credit: Number(getCheerioText(items[3], 1)),
group: getCheerioText(items[4], 1),
});
if (helper.graduate()) {
result.push({
id: getCheerioText(items[1], 0),
name: (items[2] as TagElement).attribs.title,
property: getCheerioText(items[5], 0),
credit: Number(getCheerioText(items[3], 0)),
group: getCheerioText(items[6], 0),
});
} else {
result.push({
id: getCheerioText(items[0], 1),
name: cheerio(cheerio(cheerio(cheerio(items[1]).children()[0]).children()[0]).children()[0]).text().trim(),
property: getCheerioText(items[2], 1),
credit: Number(getCheerioText(items[3], 1)),
group: getCheerioText(items[4], 1),
});
}
}
});
return result;
Expand All @@ -242,7 +258,7 @@ export const searchCrRemaining = async (helper: InfoHelper, {page, semester, id,
undefined,
"",
async () => {
const $ = await crFetch(CR_SEARCH_URL, {
const $ = await crFetch(helper.graduate() ? CR_SEARCH_YJS_URL : CR_SEARCH_URL, {
m: "kylSearch",
page: page ?? -1,
"p_sort.p1": "",
Expand Down Expand Up @@ -286,7 +302,7 @@ export const searchCrPrimaryOpen = async (helper: InfoHelper, {page, semester, i
undefined,
"",
async () => {
const $ = await crFetch(CR_SEARCH_URL, {
const $ = await crFetch(helper.graduate() ? CR_SEARCH_YJS_URL : CR_SEARCH_URL, {
m: "kkxxSearch",
page: page ?? -1,
"p_sort.p1": "",
Expand Down Expand Up @@ -361,14 +377,14 @@ export const searchCrCourses = async (helper: InfoHelper, params: SearchParams):
MOCK_CR_SEARCH_RESULT,
);

export type Priority = "bx" | "xx" | "rx" | "ty" | "cx"
export type Priority = "bx" | "xx" | "rx" | "ty" | "xwk" | "fxwk" | "tyk" | "cx"; // 必修|限选|任选|体育(本)|学位课|非学位课|体育课(研)|重修(本研)

export const selectCourse = async (helper: InfoHelper, semesterId: string, priority: Priority, courseId: string, courseSeq: string, will: 1 | 2 | 3) => roamingWrapperWithMocks(
helper,
undefined,
"",
async () => {
const mainHtml = await crFetch(`${CR_SELECT_URL}?m=${priority}Search&p_xnxq=${semesterId}&tokenPriFlag=${priority}`);
const mainHtml = await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=${priority}Search&p_xnxq=${semesterId}&tokenPriFlag=${priority}`);
const $ = cheerio.load(mainHtml);
const m = `save${priority[0].toUpperCase()}${priority[1]}Kc`;
const token = $("input[name=token]").attr().value;
Expand All @@ -381,7 +397,7 @@ export const selectCourse = async (helper: InfoHelper, semesterId: string, prior
const fieldKey = priority === "rx" ? "rx" : priority === "ty" ? "rxTy" : priority + "k";
post[`p_${fieldKey}_id`] = `${semesterId};${courseId};${courseSeq};`;
post[`p_${fieldKey}_xkzy`] = will;
const responseHtml = await crFetch(CR_SELECT_URL, post);
const responseHtml = await crFetch(helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL, post);
const responseMsg = /showMsg\("(.+?)"\);/g.exec(responseHtml);
if (responseMsg === null) {
throw new CrError("Failed to match regex");
Expand All @@ -396,7 +412,7 @@ export const deleteCourse = async (helper: InfoHelper, semesterId: string, cours
undefined,
"",
async () => {
const yxHtml = await crFetch(`${CR_SELECT_URL}?m=yxSearchTab&p_xnxq=${semesterId}&tokenPriFlag=yx`);
const yxHtml = await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=yxSearchTab&p_xnxq=${semesterId}&tokenPriFlag=yx`);
const $ = cheerio.load(yxHtml);
const post: {[key: string]: string | number} = {
m: "deleteYxk",
Expand All @@ -405,7 +421,7 @@ export const deleteCourse = async (helper: InfoHelper, semesterId: string, cours
tokenPriFlag: "yx",
};
post["p_del_id"] = `${semesterId};${courseId};${courseSeq};`;
const responseHtml = await crFetch(CR_SELECT_URL, post);
const responseHtml = await crFetch(helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL, post);
const responseMsg = /showMsg\("(.+?)"\);/g.exec(responseHtml);
if (responseMsg === null) {
throw new CrError("Failed to match regex");
Expand All @@ -428,7 +444,7 @@ export const getSelectedCourses = async (helper: InfoHelper, semesterId: string)
undefined,
"",
async () => {
const yxHtml = await crFetch(`${CR_SELECT_URL}?m=yxSearchTab&p_xnxq=${semesterId}&tokenPriFlag=yx`);
const yxHtml = await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=yxSearchTab&p_xnxq=${semesterId}&tokenPriFlag=yx`);
const $ = cheerio.load(yxHtml);
return $(".trr2").map((_, e) => {
const tds = cheerio(e).find(".tdd2");
Expand All @@ -453,9 +469,9 @@ export const changeCourseWill = async (helper: InfoHelper, semesterId: string, c
undefined,
"",
async () => {
const yxHtml = await crFetch(`${CR_SELECT_URL}?m=yxSearchTab&p_xnxq=${semesterId}&tokenPriFlag=yx`);
const yxHtml = await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=yxSearchTab&p_xnxq=${semesterId}&tokenPriFlag=yx`);
const $ = cheerio.load(yxHtml);
const responseHtml = await crFetch(CR_SELECT_URL, {
const responseHtml = await crFetch(helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL, {
m: "changeZY",
token: $("input[name=token]").attr().value,
p_xnxq: semesterId,
Expand Down Expand Up @@ -485,7 +501,7 @@ export const getCrCurrentStage = async (
undefined,
"",
async () => {
const html = await crFetch(`${CR_SELECT_URL}?m=selectKc&p_xnxq=${semesterId}&pathContent=%D2%BB%BC%B6%D1%A1%BF%CE`);
const html = await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=selectKc&p_xnxq=${semesterId}&pathContent=%D2%BB%BC%B6%D1%A1%BF%CE`);
const stageRes = /"当前选课阶段:(.+?)&nbsp;&nbsp;"/.exec(html);
const beginRes = /"(.+?)开始&nbsp;&nbsp;"/.exec(html);
const endRes = /"(.+?)结束"/.exec(html);
Expand All @@ -509,7 +525,7 @@ export const searchCoursePriorityMeta = async (
undefined,
"",
async () => {
const $ = cheerio.load(await crFetch(`${CR_SELECT_URL}?m=xkqkSearch&p_xnxq=${semesterId}`));
const $ = cheerio.load(await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=xkqkSearch&p_xnxq=${semesterId}`));
const pad = $(".pad");
return {
curr: pad.find("font").text(),
Expand All @@ -531,11 +547,11 @@ export const searchCoursePriorityInformation = async (
const responseHtml = await (async () => {
const tag = query.isSports ? "Ty" : "BR";
if (query.selected) {
return await crFetch(`${CR_ZYTJB_URL}?m=tbzySearch${tag}&p_xnxq=${semesterId}&type=GR`);
return await crFetch(`${helper.graduate() ? CR_ZYTJB_YJS_URL : CR_ZYTJB_URL}?m=tbzySearch${tag}&p_xnxq=${semesterId}&type=GR`);
} else {
const xkHtml = await crFetch(`${CR_ZYTJB_URL}?m=tbzySearch${tag}&p_xnxq=${semesterId}`);
const xkHtml = await crFetch(`${helper.graduate() ? CR_ZYTJB_YJS_URL : CR_ZYTJB_URL}?m=tbzySearch${tag}&p_xnxq=${semesterId}`);
const $ = cheerio.load(xkHtml);
return await crFetch(CR_ZYTJB_URL, {
return await crFetch(helper.graduate() ? CR_ZYTJB_YJS_URL : CR_ZYTJB_URL, {
m: `tbzySearch${tag}`,
page: query.page ?? -1,
token: $("input[name=token]").attr().value,
Expand Down Expand Up @@ -583,7 +599,7 @@ export const getQueueInfo = async (
undefined,
"",
async () => {
const data = await crFetch(`${CR_SELECT_URL}?m=dlSearch&p_xnxq=${semesterId}&pathContent=%B6%D3%C1%D0%D0%C5%CF%A2%B2%E9%D1%AF`);
const data = await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=dlSearch&p_xnxq=${semesterId}&pathContent=%B6%D3%C1%D0%D0%C5%CF%A2%B2%E9%D1%AF`);
const courses = cheerio(".trr2", data);
const result: QueueInfo[] = [];
courses.each((_, e) => {
Expand Down Expand Up @@ -614,8 +630,8 @@ export const cancelCoursePF = async (
undefined,
"",
async () => {
await crFetch(`${CR_SELECT_URL}?m=pfkcxz&p_xnxq=${semesterId}`);
const pfHtml = await crFetch(`${CR_SELECT_URL}?m=yxpfxz&p_xnxq=${semesterId}&tokenPriFlag=yx`);
await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=pfkcxz&p_xnxq=${semesterId}`);
const pfHtml = await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=yxpfxz&p_xnxq=${semesterId}&tokenPriFlag=yx`);
const $ = cheerio.load(pfHtml);
const token = $("input[name=token]").attr().value;
const availableCourses = $(".xinXi2 > #content_1 .table1 tr");
Expand All @@ -630,7 +646,7 @@ export const cancelCoursePF = async (
});
post.token = token;
post.m = "editpfcancle";
const result = await crFetch(CR_SELECT_URL, post);
const result = await crFetch(helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL, post);
if (!result.includes("showMsg(\"任选课取消置为P/F成功\");")) {
throw new CrError(`Failed to cancel PF for course #${courseId}`);
}
Expand All @@ -652,8 +668,8 @@ export const setCoursePF = async (
undefined,
"",
async () => {
await crFetch(`${CR_SELECT_URL}?m=pfkcxz&p_xnxq=${semesterId}`);
const pfHtml = await crFetch(`${CR_SELECT_URL}?m=yxpfxz&p_xnxq=${semesterId}&tokenPriFlag=yx`);
await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=pfkcxz&p_xnxq=${semesterId}`);
const pfHtml = await crFetch(`${helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL}?m=yxpfxz&p_xnxq=${semesterId}&tokenPriFlag=yx`);
const $ = cheerio.load(pfHtml);
const token = $("input[name=token]").attr().value;
const availableCourses = $(".tabdiv #content_1 .table1 tr");
Expand All @@ -673,7 +689,7 @@ export const setCoursePF = async (
post.p_pf_id = pfRadio.first().attr().value;
post.token = token;
post.m = "editpfyes";
const result = await crFetch(CR_SELECT_URL, post);
const result = await crFetch(helper.graduate() ? CR_SELECT_YJS_URL : CR_SELECT_URL, post);
if (!result.includes("showMsg(\"任选课置为P/F成功\")")) {
throw new CrError(`Failed to set PF for course #${courseId}`);
}
Expand Down

0 comments on commit 9b89f99

Please sign in to comment.