Skip to content

Conversation

@dzx-dzx
Copy link
Contributor

@dzx-dzx dzx-dzx commented Jan 25, 2026

Involved Issue / 该 PR 相关 Issue

Close #

Example for the Proposed Route(s) / 路由地址示例

/sjtu/publicoa

New RSS Route Checklist / 新 RSS 路由检查表

  • New Route / 新的路由
  • Anti-bot or rate limit / 反爬/频率限制
    • If yes, do your code reflect this sign? / 如果有, 是否有对应的措施?
  • Date and time / 日期和时间
    • Parsed / 可以解析
    • Correct time zone / 时区正确
  • New package added / 添加了新的包
  • Puppeteer

Note / 说明

Copilot AI review requested due to automatic review settings January 25, 2026 08:47
@github-actions github-actions bot added the route label Jan 25, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new route for SJTU (Shanghai Jiao Tong University) Public OA system, allowing users to fetch official documents through RSS feeds.

Changes:

  • Adds a new authenticated route /sjtu/publicoa that fetches documents from the university's public OA system
  • Implements cookie-based authentication using JAAuthCookie configuration
  • Adds configuration support for JAAuthCookie in the config file

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
lib/routes/sjtu/publicoa.ts Implements the Public OA route with authentication and document fetching logic
lib/config.ts Adds JAAuthCookie configuration support for SJTU routes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


async function handler() {
if (!config.sjtu?.JAAuthCookie) {
throw 'JAAuthCookie needs to be set to use this route.';
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message should use new Error() instead of throwing a plain string. According to JavaScript best practices and conventions in this codebase, errors should be thrown as Error objects.

Suggested change
throw 'JAAuthCookie needs to be set to use this route.';
throw new Error('JAAuthCookie needs to be set to use this route.');

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +37
const cookieJar = new CookieJar();

async function handler() {
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global cookieJar instance may cause issues in concurrent requests since it's shared across all handler invocations. Consider creating a new CookieJar instance inside the handler function, similar to the pattern used in lib/routes/gdut/oa-news.ts (line 98) where new CookieJar() is created within the handler function scope.

Suggested change
const cookieJar = new CookieJar();
async function handler() {
async function handler() {
const cookieJar = new CookieJar();

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +77
while (true) {
// eslint-disable-next-line no-await-in-loop
const res = await ofetch.raw(requestUrl, {
headers: {
// eslint-disable-next-line no-await-in-loop
cookie: (await cookieJar.getCookieString(requestUrl)) as string,
},
redirect: 'manual',
});
const setCookies = res.headers.getSetCookie();
for (const c of setCookies) {
cookieJar.setCookieSync(c, requestUrl);
}

if (res.status >= 300 && res.status < 400) {
const location = res.headers.get('location');
if (typeof location === 'string') {
requestUrl = new URL(location, requestUrl).href;
}
} else {
break;
}
}
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error response handling in this redirect loop doesn't handle cases where the authentication flow fails completely or where redirects might be malicious. The loop should include a maximum iteration count to prevent infinite loops and should validate redirect URLs before following them.

Copilot uses AI. Check for mistakes.
}
}
return await getPublicOAList();
}
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the initial API request at line 44 doesn't return a 401 error but fails in some other way (network error, timeout, 500 error, etc.), the promise will resolve with undefined. This will cause a runtime error at line 86 when trying to access list.entities. The error handling should be expanded to handle all failure cases, not just 401 authentication errors.

Suggested change
}
}
throw error;

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 94
import { CookieJar } from 'tough-cookie';

import { config } from '@/config';
import type { Route } from '@/types';
import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
import timezone from '@/utils/timezone';

const urlRoot = 'https://publicoa.sjtu.edu.cn';

export const route: Route = {
path: '/publicoa',
categories: ['university'],
example: '/sjtu/publicoa',
parameters: {},
features: {
requireConfig: [
{
name: 'JAAuthCookie',
description: 'JAAuthCookie, 登陆后提取自jaccount.sjtu.edu.cn',
},
],
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: '上海交通大学公文系统',
maintainers: [''],
handler,
description: `需要用户认证`,
};

const cookieJar = new CookieJar();

async function handler() {
if (!config.sjtu?.JAAuthCookie) {
throw 'JAAuthCookie needs to be set to use this route.';
}

cookieJar.setCookieSync(`JAAuthCookie=${config.sjtu.JAAuthCookie}; Domain=.jaccount.sjtu.edu.cn; Path=/`, 'https://jaccount.sjtu.edu.cn');
async function getPublicOAList() {
return await ofetch(`${urlRoot}/api/doc/list`, {
headers: {
cookie: (await cookieJar.getCookieString(urlRoot)) as string,
},
});
}
const list: any = await new Promise((resolve) => {
resolve(
getPublicOAList().catch(async (error) => {
if (error.response?.status === 401) {
let requestUrl = urlRoot;
while (true) {
// eslint-disable-next-line no-await-in-loop
const res = await ofetch.raw(requestUrl, {
headers: {
// eslint-disable-next-line no-await-in-loop
cookie: (await cookieJar.getCookieString(requestUrl)) as string,
},
redirect: 'manual',
});
const setCookies = res.headers.getSetCookie();
for (const c of setCookies) {
cookieJar.setCookieSync(c, requestUrl);
}

if (res.status >= 300 && res.status < 400) {
const location = res.headers.get('location');
if (typeof location === 'string') {
requestUrl = new URL(location, requestUrl).href;
}
} else {
break;
}
}
return await getPublicOAList();
}
})
);
});

return {
title: '上海交通大学公文系统',
item: list.entities.map((item) => ({
title: item.title,
author: item.doccode,
pubDate: timezone(parseDate(item.qfdate), +8),
link: item.pdfpath,
})),
link: urlRoot,
};
}
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description's example routes section is empty. According to the PR template, this section should contain the complete route path(s) starting with /, for example: /sjtu/publicoa. This is a requirement stated in the template.

Copilot uses AI. Check for mistakes.
@github-actions github-actions bot added the auto: not ready to review Users can't get the RSS feed output according to automated testing results label Jan 25, 2026
@github-actions
Copy link
Contributor

Successfully generated as following:

http://localhost:1200/sjtu/publicoa - Failed ❌
HTTPError: Response code 500 (Internal Server Error)

Comment on lines +57 to +63
const res = await ofetch.raw(requestUrl, {
headers: {
// eslint-disable-next-line no-await-in-loop
cookie: (await cookieJar.getCookieString(requestUrl)) as string,
},
redirect: 'manual',
});

Check failure

Code scanning / ESLint

Disallow `await` inside of loops Error

Unexpected await inside a loop.
const res = await ofetch.raw(requestUrl, {
headers: {
// eslint-disable-next-line no-await-in-loop
cookie: (await cookieJar.getCookieString(requestUrl)) as string,

Check failure

Code scanning / ESLint

Disallow `await` inside of loops Error

Unexpected await inside a loop.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto: not ready to review Users can't get the RSS feed output according to automated testing results route

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant