【XIUNOX插件】Gitee 项目展示 v1.0.0

管理员组

xnx_gitee_projects Gitee 项目展示

在个人主页、用户公开主页、帖子作者卡片展示绑定的 Gitee 公开项目,用户可手动选择要展示的项目(最多 10 个)。依赖 xnx_oauth 完成账号绑定,通过 Gitee 公开 API 拉取项目列表,24 小时本地缓存。

功能特性

  • 三处展示入口:个人中心独立页(gitee-projects-{uid})、用户公开主页「项目」Tab(user_nav_end.htm hook 注入)、帖子详情页右侧作者卡片摘要(thread_user_after.htm hook 注入,最多 3 个)
  • 项目选择:用户在设置页(gitee-projects-settings)从已同步的公开项目列表中勾选要展示的项目,最多 10 个;前端 JS 实时计数 + 超额拦截
  • 同步缓存:调用 GiteeProjectsService::syncRepos() 拉取项目列表写入 repos_cache(longtext JSON),24 小时内复用缓存,超时或手动「同步项目」按钮触发强制刷新
  • 分页拉取:调用 Gitee API /users/{username}/repos,按 updated desc 排序,最多分页 5 页 × 100 条 = 500 个项目,自动跳过私有项目
  • htmx 体验:设置页「同步项目」按钮走 htmx POST 流程,含 loading 状态与同步后自动刷新;用户主页「项目」Tab 提供独立 htmx 片段端点
  • 多语言:内置简体中文、繁体中文、English 三套语言包
  • 与 xnx_oauth 解耦:仅读取 xnx_oauth_bind 表的 raw_data.login 字段获取 Gitee 用户名,复用 xnx_oauth 的代理配置,不依赖 access_token,调用的是无需鉴权的 Gitee 公开 API

安装说明

  1. 先安装并启用依赖插件 xnx_oauth(在 conf.json 中声明 "dependencies": {"xnx_oauth": "*"}
  2. xnx_oauth 中完成 Gitee OAuth 应用配置与个人 Gitee 账号绑定(绑定后 xnx_oauth_bind.raw_data 会写入 Gitee 用户信息)
  3. 将本插件目录放入 plugin/xnx_gitee_projects/
  4. 进入后台「插件管理」找到「Gitee 项目展示」点击安装,自动建 xnx_gitee_projects
  5. 卸载时会执行 uninstall.php 自动 DROP TABLE

关于依赖

  • 本插件不直接调用 Gitee OAuth Token,Gitee API 请求走公开端点 /users/{username}/repos(无需 access_token)
  • 依赖 xnx_oauth 仅为:①从其 xnx_oauth_bind 表读取用户绑定的 Gitee login 用户名;②复用其后台保存的 HTTP 代理配置(proxy_host / proxy_port / proxy_type / proxy_user / proxy_pass),便于服务器无法直连 Gitee 时使用代理
  • 因此即使 xnx_oauth 的 token 过期,本插件仍可正常拉取公开项目

使用指南

用户侧

  1. 在「个人中心」通过 xnx_oauth 完成 Gitee 账号绑定
  2. 绑定后,「个人中心」侧边栏(PC + 移动端均注入)会出现「我的 Gitee 项目」菜单项(仅绑定用户可见)
  3. 点击进入独立页 gitee-projects-{uid},首次访问会自动触发同步(带缓存,不强制);页面右上角「设置」按钮进入选择页
  4. 在设置页 gitee-projects-settings 中:
- 顶部「同步项目」按钮:强制刷新(POST gitee-projects-sync),同步成功后页面自动重载

- 列表勾选要展示的项目,最多 10 个(超额前端自动拦截并 toast 提示) - 「保存选择」按钮提交(POST gitee-projects-save),成功后跳回独立页

  1. 其他用户访问该用户公开主页时,「项目」Tab 自动出现(仅在该用户已绑定且有选中项目时);帖子详情页作者卡片下方也会显示最多 3 个项目摘要

展示字段

每个项目卡片显示:项目名、Fork 标记、License、描述、主要语言、Star 数、Fork 数、最近更新时间(formatTimeAgo 友好格式:刚刚 / X 分钟前 / X 小时前 / X 天前 / X 个月前 / X 年前)。项目链接跳转至 Gitee 仓库 Web 页面(自动去掉 html_url 末尾的 .git)。

权限

  • 设置页、同步、保存操作均要求登录($uid 非空)
  • syncsave 子动作强制 POST + CsrfService::check() CSRF 校验
  • 任何访客均可查看用户公开主页的项目 Tab 与帖子作者卡片的项目摘要(展示的是 Gitee 公开项目)

技术细节

路由解析

Xiuno URL 按 - 分隔参数,通过 index_route_case_end.php hook 注册 case 'gitee',将 gitee-* 路由到 route/gitee.php

| URL | param(2) 类型 | 动作 | |---|---|---| | gitee-projects-{uid} | 数字 | 独立展示页 | | gitee-projects-settings | 字符串 | 设置页 | | gitee-projects-sync | 字符串 | 手动强制刷新(POST) | | gitee-projects-save | 字符串 | 保存选中项目(POST) | | gitee-projects-tab-{uid} | 字符串 | htmx 片段端点 |

model_route_table_end.php hook 注册 5 个路由模板,使 url() 函数能正确生成上述 URL。

Gitee API 调用

GiteeProjectsService::fetchReposFromGitee() 调用:

GET https://gitee.com/api/v5/users/{username}/repos?page={page}&per_page={perPage}&sort=updated&direction=desc
  • per_page 限制在 1~100
  • syncRepos() 中循环分页最多 5 页,单页返回少于 100 条提前终止
  • 仅保留 private 不为 true 的公开项目
  • normalizeRepo() 提取展示需要的字段:id、name、path、full_name、description、html_url(去 .git)、language、stargazers_count、forks_count、watchers_count、open_issues_count、updated_at、pushed_at、homepage、license、fork
  • HTTP 请求:cURL,TIMEOUT=15CONNECTTIMEOUT=10User-Agent: Xiuno-GiteeProjects/1.0,关闭 SSL 校验(适配自签证书环境),从 setting_get('xnx_oauth') 读取代理配置

缓存策略

  • 单例 GiteeProjectsService$cacheTtl = 86400(24 小时)
  • syncRepos($uid, $force=false):未到 TTL 且 repos_cache 非空时直接返回缓存(synced=false);强制刷新($force=true,对应「同步项目」按钮)或缓存过期时重新拉取并写库
  • 缓存以 JSON 形式存于 xnx_gitee_projects.repos_cache(longtext),selected_repo_ids 单独存为 JSON 数组
  • 展示侧 getSelectedRepos()selected_repo_ids 顺序从 repos_cache 中筛选,保证用户选择的展示顺序

与 xnx_oauth 的关系

| 用途 | 实现方式 | |---|---| | 获取 Gitee 用户名 | db_find_one('xnx_oauth_bind', ['uid'=>$uid, 'provider'=>'gitee']),解析 raw_data JSON 中的 login 字段 | | 调用 Gitee API | 走公开端点 /users/{username}/repos不使用 access_token | | HTTP 代理 | setting_get('xnx_oauth') 读取 proxy_host / proxy_port / proxy_type(socks5 时切换 CURLPROXY_SOCKS5)/ proxy_user / proxy_pass |

Hook 注入点

| Hook 文件 | 注入点 | 作用 | |---|---|---| | index_route_case_end.php | 路由 switch | 注册 case 'gitee' | | model_inc_file.php | model 加载列表 | 注册 GiteeProjectsService.php | | model_route_table_end.php | 路由表 | 注册 5 个 URL 模板 | | my_sidebar_nav_threads_before.htm | PC 个人中心侧栏 | 注入「我的 Gitee 项目」菜单(仅绑定用户可见) | | my_sidebar_nav_threads_before_mobile.htm | 移动端个人中心侧栏 | 同上,移动端模板 | | thread_user_after.htm | 帖子详情页作者卡片下方 | 注入项目摘要卡片(最多 3 个) | | user_nav_end.htm | 用户公开主页 Tab 末尾 | 注入「项目」Tab(仅绑定 + 有选中项目时) |

所有 htm hook 均以 class_exists('GiteeProjectsService', false) 守卫,插件禁用后不渲染。

数据表

安装时创建一张表 xnx_gitee_projectsutf8mb4):

| 字段 | 类型 | 说明 | |---|---|---| | id | int(11) AUTO_INCREMENT | 主键 | | uid | int(11) | Xiuno 用户 ID,UNIQUE KEY | | gitee_username | varchar(100) | Gitee 用户名(login) | | repos_cache | longtext | JSON:全部公开项目缓存(24h 刷新) | | selected_repo_ids | text | JSON:选中的 repo id 数组(最多 10 个) | | last_sync_time | int(11) | 最后同步时间戳 | | last_sync_ip | int(11) unsigned | 最后同步 IP($longip) |

卸载时 DROP TABLE IF EXISTS xnx_gitee_projects。不创建/删除 xnx_oauth_bind 表(由 xnx_oauth 维护)。

兼容性

  • Xiuno BBS X 1.1+(bbs_version: 1.1
  • PHP 8.x(全局数组访问已加 isset 兜底)
  • Bootstrap 5 + Tabler Icons
  • 依赖 htmx(设置页同步按钮与「项目」Tab 端点使用)
  • 依赖 xnx_oauth 插件提供 Gitee 绑定与代理配置
  • 依赖 CsrfService 进行 POST 校验
  • 无 jQuery 依赖(前端交互使用原生 JS + htmx)
  • 通过 hook 注入,核心代码无硬编码插件名,禁用后 hook 自动不执行

版本历史

  • 1.0.0:首版发布,包含 Gitee 公开项目同步、24h 缓存、用户选择展示(最多 10 个)、个人主页 / 用户公开主页 Tab / 帖子作者卡片三处展示、htmx 同步与 Tab 片段、PC + 移动端侧边栏入口、简繁英三语

版本 1.0.0 | 兼容 Xiuno 1.1+



版本:v1.0.0
适用版本:1.1
开发者:贰先生

请登录后查看此内容
最新回复

请先登录后再回复 登录