Skip to content

Upload articles by parsing urls - #5

Closed
CeitherNSW wants to merge 2 commits into
InvolutionHell:mainfrom
CeitherNSW:Upload-and-Parse
Closed

Upload articles by parsing urls#5
CeitherNSW wants to merge 2 commits into
InvolutionHell:mainfrom
CeitherNSW:Upload-and-Parse

Conversation

@CeitherNSW

Copy link
Copy Markdown
Contributor
image

@longsizhuo longsizhuo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

提个建议,css单独创一个和你新增的东西同名的css,不然找不到了

@longsizhuo
longsizhuo requested a review from Copilot September 12, 2025 11:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 upload feature for parsing and uploading articles via URLs, introducing a dedicated upload page with URL input functionality. The changes also refactor existing styles by extracting inline styles into CSS classes for better maintainability.

  • Creates a new upload page with URL input field and upload button
  • Refactors inline styles to CSS classes for the docs page
  • Adds comprehensive CSS variables and utility classes for consistent styling

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 9 comments.

File Description
app/upload/page.tsx New upload page with URL input form for article parsing
app/page.tsx Refactored to use CSS classes instead of inline styles
app/globals.css Added CSS variables and utility classes for consistent styling

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread app/upload/page.tsx
const [value, setValue] = useState('')

const handleClick = () => {
console.log('输入内容:', value)

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

The console.log message contains Chinese characters '输入内容:'. Consider using English for consistency with the codebase, such as 'Input content:' or 'URL input:'.

Suggested change
console.log('输入内容:', value)
console.log('Input content:', value)

Copilot uses AI. Check for mistakes.
Comment thread app/upload/page.tsx
<div className="doc-card" style={{ display: 'flex', gap: 8 }}>
<input
type="text"
placeholder="公众号url"

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

The placeholder text '公众号url' is in Chinese. Consider using English for consistency, such as 'Enter article URL' or 'WeChat article URL'.

Suggested change
placeholder="公众号url"
placeholder="Enter article URL"

Copilot uses AI. Check for mistakes.
Comment thread app/upload/page.tsx
<button
onClick={handleClick}
>
上传

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

The button text '上传' is in Chinese. Consider using English for consistency with the codebase, such as 'Upload' or 'Submit'.

Suggested change
上传
Upload

Copilot uses AI. Check for mistakes.
Comment thread app/globals.css
}
}

/* globals.css */

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

[nitpick] This comment is redundant since it's already clear from the filename. Consider removing it or replacing with a more descriptive comment about the purpose of the following CSS rules.

Suggested change
/* globals.css */
/* Custom properties for layout and design */

Copilot uses AI. Check for mistakes.
Comment thread app/globals.css
--list-gap: 12px;
}

/* 全局 main 容器 */

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

The comment '全局 main 容器' is in Chinese. Consider using English for consistency, such as '/* Global main container */'.

Suggested change
/* 全局 main 容器 */
/* Global main container */

Copilot uses AI. Check for mistakes.
Comment thread app/globals.css
padding: var(--page-padding);
}

/* 标题 */

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

The comment '标题' is in Chinese. Consider using English for consistency, such as '/* Page title /' or '/ Heading */'.

Suggested change
/* 标题 */
/* Page title */

Copilot uses AI. Check for mistakes.
Comment thread app/globals.css
margin-bottom: var(--heading-margin-bottom);
}

/* 列表 */

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

The comment '列表' is in Chinese. Consider using English for consistency, such as '/* Document list /' or '/ List styles */'.

Suggested change
/* 列表 */
/* Document list */

Copilot uses AI. Check for mistakes.
Comment thread app/globals.css
padding: 0;
}

/* 卡片 */

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

The comment '卡片' is in Chinese. Consider using English for consistency, such as '/* Card styles /' or '/ Document card */'.

Suggested change
/* 卡片 */
/* Card styles */

Copilot uses AI. Check for mistakes.
Comment thread app/globals.css
padding: var(--card-padding);
}

/* 链接 */

Copilot AI Sep 12, 2025

Copy link

Choose a reason for hiding this comment

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

The comment '链接' is in Chinese. Consider using English for consistency, such as '/* Link styles /' or '/ Document links */'.

Suggested change
/* 链接 */
/* Link styles */

Copilot uses AI. Check for mistakes.
longsizhuo added a commit that referenced this pull request Apr 16, 2026
- UserPaperItem 加 itemKey 字段(可选)
- page.tsx 提取所有 itemKey 批量调 /api/user-center/zotero/items,
  Zotero 拉到的元信息作为主数据源,手填字段作为离线 fallback
- EditProfileForm papers 区增加 itemKey 输入框(提示可选),保存条件放宽为 itemKey 或 title 至少有一个
- 完全向后兼容:历史 pinned_papers(只有 title/authors 的)照常渲染

配套后端 commit involutionhell-backend 1fb697f(Zotero API 代理 + Caffeine 1h)

V2 全部完成:#1 编辑页 / #2 docs/history 迁 Java / #3 活跃度热力图 /
#4 关注系统 / #5 GitHub repos 同步 / #6 保留 analyticsEvent / #7 Zotero itemKey
longsizhuo added a commit that referenced this pull request Apr 16, 2026
* feat(profile): 个人主页 /u/[username] SSR + Bento 布局

MVP 范围(UX + PM 对齐后砍刀):
- 路由:/u/[username] SSR(ISR 300s)
- 数据源:后端 GET /api/user-center/profile/{username}
- 布局:12-col bento,左 col-span-5 Identity,右 col-span-7 小卡网格
- 间距:gap-8 统一,用户明确要求松散
- 三种卡片:PROJ / PAPER / DOC,前两者读 preferences,DOC 读 leaderboard
- hover 展开用 max-height 原地展开;mobile 改 tap toggle

砍掉(V2):
- sticky 左大块(滚动竞争)
- 绝对定位浮层(移动端 mess)
- 编辑页(复用后端 PATCH /preferences)
- Zotero 实时关联(pinned_papers 直接存 title/author/year)

配套后端改动见 involutionhell-backend main commit 8efae54
(新增 GET /api/user-center/profile/{username} + SaToken 白名单)

同步新增:
- docs/architecture/frontend-backend-separation.md 固化前后端分离约定

* feat(profile): 入口收口 + URL 支持 github_id 双路径

- UserMenu 登录态增加"我的主页"链接(基于 githubId)
- AuthNav 透传 githubId 到 UserMenu
- ContributorRow 弹窗加"VIEW DOSSIER"跳站内个人主页,GitHub 外链保留
- page.tsx 改按 user.githubId 从 leaderboard JSON 匹配贡献数据
  (之前按 name 字符串匹配踩坑:leaderboard.name="longsizhuo" vs user.username="github_114939201")
- 新增 EditLinkIfOwner 客户端小组件,只在访问者 == 主页主人时渲染编辑入口

* feat(profile): 编辑页 /u/[username]/edit 支持 bio/tagline/links/projects/papers

- 新 page.tsx 壳 + EditProfileForm 客户端表单
- useAuth 读当前用户,URL username 与 githubId / username 都不匹配时显示"只能编辑自己"
- GET /api/user-center/preferences 拉现有值 → 表单 state
- 提交走 PATCH /api/user-center/preferences(后端合并 JSONB 顶层 key 保留其他)
- RepeatableList 通用泛型组件支持 links/projects/papers 增删
- editorial 风格:border 无圆角 / SEC 编号 / 硬阴影 submit 按钮

* refactor(api): /api/docs/history 迁到 Java 后端

删 Next API Route,next.config 加 rewrite 把 /api/docs/history 透传到 Java,
Vercel 不再跑 Node function 去调 GitHub API。后端带 Caffeine 10min 缓存 +
GITHUB_TOKEN。配套后端 commit 见 involutionhell-backend#main。

* perf(build): leaderboard 用 git log 反推 login + 加 dailyCounts 字段

- 从 noreply 邮箱(1234567+alice@users.noreply.github.com) 离线提取 id→login 映射,
  14/21 命中直接拿到 login,剩下 7 才走 GitHub API。规避限流风险。
- DB 聚合时同时按日分桶贡献次数写进 dailyCounts: { "YYYY-MM-DD": count },
  供前端活跃度热力图渲染,零运行时 DB 查询。

generated/site-leaderboard.json 一并重新生成带 dailyCounts。

* feat(profile): 活跃度热力图 52 周 GitHub 风格

- 新增 ActivityHeatmap server component,无 JS
- 52 列 × 7 行小格子,色阶分 5 档(0 / 1-2 / 3-5 / 6-10 / 10+),硬红(#CC0000)系列
- 数据走 leaderboard.json 的 dailyCounts(零运行时 DB 查询,和 docs git-based 一致)
- 月份刻度 + 周几标签(周一/四/六)
- page.tsx Bento grid 下方独立一行展示,仅当有贡献数据时渲染

* feat(follows): 个人主页关注按钮 + 粉丝/关注数

- FollowButton 客户端组件:拉 /api/user-center/follows/stats 填初始值,
  点击走 POST/DELETE /api/user-center/follows/{id},乐观更新失败回滚
- 自己访问自己主页只显示统计,不显示按钮
- 匿名用户可见数字,按钮显示"登录后关注"置灰
- prisma/schema.prisma 加 user_follows model 同步(DB 已在 Neon 手动建表)

配套后端端点见 involutionhell-backend#main 30daf9d

* feat(profile): GitHub repos 小卡区 SEC. REPOS · 006

- GithubRepos server component,fetch /api/user-center/github/repos/{identifier}
- 2 列 grid,每卡显示 name / stars / description / language / 更新时间
- 数据为空时返回 null 不渲染 section

配套后端 commit involutionhell-backend b6b48b2(Caffeine 1h,不需要 OAuth scope 扩展)

* feat(profile): pinned_papers 支持 Zotero itemKey 运行时填充

- UserPaperItem 加 itemKey 字段(可选)
- page.tsx 提取所有 itemKey 批量调 /api/user-center/zotero/items,
  Zotero 拉到的元信息作为主数据源,手填字段作为离线 fallback
- EditProfileForm papers 区增加 itemKey 输入框(提示可选),保存条件放宽为 itemKey 或 title 至少有一个
- 完全向后兼容:历史 pinned_papers(只有 title/authors 的)照常渲染

配套后端 commit involutionhell-backend 1fb697f(Zotero API 代理 + Caffeine 1h)

V2 全部完成:#1 编辑页 / #2 docs/history 迁 Java / #3 活跃度热力图 /
#4 关注系统 / #5 GitHub repos 同步 / #6 保留 analyticsEvent / #7 Zotero itemKey

* fix(ts): 修复 typecheck 两处报错

1. leaderboard as Row[] → leaderboard as unknown as Row[]
   JSON 字面量的 dailyCounts 各自是不同 literal 类型,和 Row 的 Record<string, number>
   索引签名不兼容,CI tsc --noEmit 报 TS2352。先经 unknown 绕开。

2. ProfileCard title prop 必填 string,但 UserPaperItem 引入 itemKey 后 title 变可选。
   兜底为 p.title || p.itemKey || "(untitled paper)"。

* fix(review): 修复 Copilot PR CR 8 条

安全修复(P0):
- fetchProfile 只在后端真返 404 或 success=false 时 notFound();其他非 2xx 抛错进 error boundary
  (避免后端故障伪装成"用户不存在")
- links/projects/papers 的 URL 在渲染前过 sanitizeExternalUrl 白名单
  (仅 http/https/mailto + 相对路径,拦 javascript:/data: 等 XSS 向量)
- ProfileCard 内部再加 safeHref 二次防御

UX / a11y(P1):
- ProfileCard 的 click toggle 用 matchMedia('(hover: none)') 限定触屏设备
  (桌面端仍走 group-hover,避免"离开 hover 后仍保持展开"幽灵状态)
- 补 role="button" / tabIndex=0 / onKeyDown(Enter|Space) / aria-expanded,
  键盘 / 读屏用户可用;只在有 detail 时才挂这些属性

文档(P2):
- docs/architecture/frontend-backend-separation.md
  环境变量章节改成"生产禁 fallback,开发态过渡允许",与现状(next.config.mjs/upload 仍用 fallback)自洽
- fetchProfile 注释说"直连后端(BACKEND_URL)",不再错写"走 rewrite"

* refactor(profile): 调整 profile 页版式,避免文档多的用户下滑过久

- 右侧 Bento 小卡区只保留 projects / papers,DOC 卡片抽出去
- 活跃度热力图从页底提到 Bento 之后立即显示(视觉重点前置)
- 新增 SEC. DOCS 独立 section 放页尾,紧凑列表(每行 ~48px 而非 180px 小卡)
- 默认只显示前 10 篇,超过的用 <details> 折叠"展开剩余 N 篇"

旧版顺序:Identity(bio/stats)+DOC 卡(8 条) → Heatmap → Repos
新版顺序:Identity(bio/stats)+projects/papers → Heatmap → Repos → Docs 列表(折叠)

文档特别多的用户(本作者 44 条)现在热力图和 repos 一屏可见,docs 列表放最后折叠。

* refactor(header): 更新顶部导航以对齐当前信息架构

- 去掉"首页":BrandMark 点击已回首页,避免冗余
- 去掉"特点":旧 Features 组件 2026-04 重构时删除,/#features 已失效
- 新增"文档"→ /docs 和"排行榜"→ /rank,把主要产品路由提到顶
- 保留"社区"→ /#community(DispatchNetwork bar)
- "联系我们"缩写为"联系"→ /#contact(Footer 还在)

* fix(profile-edit): 改善编辑页文案,让普通用户知道每个字段填什么

用户反馈"编辑个人主页这地方不知道 edit 什么,不懂 papers 是什么意思"。
根因是字段名是工程师视角(bio/tagline/pinned_papers),普通用户不理解。

改动:
- 编辑页顶部加一段"About this page"总说明:填的东西去哪里显示、全都可选
- 每个 Section 从只有 SEC 编号,扩成「SEC 编号 + 中文大标题 + 一句话描述」
- PAPERS 块重命名为"最近在读 / 推荐的论文"(papers 太学术,降低理解门槛)
- placeholder 从抽象("项目名")换成具体示例("involutionhell.com")
- IDENTITY/LINKS/PROJECTS/PAPERS 4 块都加 heading + description 说明作用

主页空态文案:
- 旧:"该用户还没有填写 projects / papers"(用户反馈看不懂)
- 新:"Ta 还没填个人项目和最近在读的论文" + 小字补充"仍会显示 GitHub repos 和文档贡献"

* feat(i18n): 个人主页相关 UI 接入真 i18n(cookie 驱动 zh/en 切换)

基建:
- lib/i18n/messages.ts:扁平 key 字典,zh/en 同结构,{param} 占位填充
- lib/i18n/server.ts:server-only,getServerLocale + getServerT
- lib/i18n/client.tsx:LocaleProvider + useT hook
- app/layout.tsx:LocaleProvider 包在 ThemeProvider 外,locale 服务端读 cookie
  注入客户端 Context,避免 SSR/CSR 水合抖动

接入(全部 profile 相关 UI):
- page.tsx:dossier / stats / empty state / docs 列表全部走 t(key)
- ActivityHeatmap:改 async server component,月份 Jan..Dec 走 activity.month.{1..12}
- GithubRepos:heading / subtitle / count 走 t
- FollowButton / EditLinkIfOwner / ProfileCard:client hook useT
- edit/page.tsx + EditProfileForm:全套(intro / 4 个 section heading+description
  + placeholders + CTA + auth gate + RepeatableList 增删按钮文字)
- RepeatableList 新增 addLabel/removeLabel props,调用方翻译好后传入

验证:
- pnpm run typecheck 通过
- locale=zh → "活跃度/文档贡献/粉丝/积分/贡献过的文档/GitHub 仓库"
- locale=en → "Activity/Docs/Followers/Points/Docs Contributed/GitHub Repositories"
longsizhuo added a commit that referenced this pull request Apr 16, 2026
Copilot 提了 6 条 + CodeQL 2 条正则告警,全部修复:

**lib/rate-limit.ts**
- 文档头 usage 示例 API 改对(CR #1)
- getClientIp 防伪造(CR #2,**安全修复**):
  优先 x-real-ip(Vercel 等 CDN 写的是可信值);降级用 XFF 时取**最后一个**
  而非首个,避免客户端伪造 `x-forwarded-for: fakeip` 绕过 rate-limit
- Upstash 缺失 warn 改用 module-scoped flag,整个实例生命周期只打一次,
  不再按 NODE_ENV 区分 —— dev 也得看到提示(CR #3)

**app/api/chat/route.ts**
- POST 入口预读 body 判定 hasImage,true 时触发 5 req/60s 严限流;
  预读失败不阻塞,保持原有容错(CR #4)
- 新增 messagesHaveImage helper:识别 type=image / image_url / file+image 媒体
- mapUpstreamError 不再把 err.stack 拼进匹配文本:stack 里的 `:429:` 行号
  会误触发 rate-limited 分类(CR #5,**真实 bug**)
- JSON.stringify 加 try/catch 兜底 String(err),避免循环引用再抛错(CR #6)
- 所有业务码正则里的 `.*` 改成 `[^\s]{0,10}?`,限死回溯深度防 ReDoS
  (CodeQL polynomial regex 告警)
@longsizhuo

Copy link
Copy Markdown
Member

已实现类似功能, 详细见 feed 和 share 路由

@longsizhuo longsizhuo closed this Apr 19, 2026
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.

3 participants