xnx_gitee_projects Gitee 项目展示
在个人主页、用户公开主页、帖子作者卡片展示绑定的 Gitee 公开项目,用户可手动选择要展示的项目(最多 10 个)。依赖 xnx_oauth 完成账号绑定,通过 Gitee 公开 API 拉取项目列表,24 小时本地缓存。
功能特性
- 三处展示入口:个人中心独立页(
gitee-projects-{uid})、用户公开主页「项目」Tab(user_nav_end.htmhook 注入)、帖子详情页右侧作者卡片摘要(thread_user_after.htmhook 注入,最多 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
安装说明
- 先安装并启用依赖插件
xnx_oauth(在conf.json中声明"dependencies": {"xnx_oauth": "*"}) - 在
xnx_oauth中完成 Gitee OAuth 应用配置与个人 Gitee 账号绑定(绑定后xnx_oauth_bind.raw_data会写入 Gitee 用户信息) - 将本插件目录放入
plugin/xnx_gitee_projects/ - 进入后台「插件管理」找到「Gitee 项目展示」点击安装,自动建
xnx_gitee_projects表 - 卸载时会执行
uninstall.php自动DROP TABLE
关于依赖
- 本插件不直接调用 Gitee OAuth Token,Gitee API 请求走公开端点
/users/{username}/repos(无需 access_token) - 依赖
xnx_oauth仅为:①从其xnx_oauth_bind表读取用户绑定的 Giteelogin用户名;②复用其后台保存的 HTTP 代理配置(proxy_host/proxy_port/proxy_type/proxy_user/proxy_pass),便于服务器无法直连 Gitee 时使用代理 - 因此即使
xnx_oauth的 token 过期,本插件仍可正常拉取公开项目
使用指南
用户侧
- 在「个人中心」通过
xnx_oauth完成 Gitee 账号绑定 - 绑定后,「个人中心」侧边栏(PC + 移动端均注入)会出现「我的 Gitee 项目」菜单项(仅绑定用户可见)
- 点击进入独立页
gitee-projects-{uid},首次访问会自动触发同步(带缓存,不强制);页面右上角「设置」按钮进入选择页 - 在设置页
gitee-projects-settings中:
gitee-projects-sync),同步成功后页面自动重载 - 列表勾选要展示的项目,最多 10 个(超额前端自动拦截并 toast 提示) - 「保存选择」按钮提交(POST gitee-projects-save),成功后跳回独立页
- 其他用户访问该用户公开主页时,「项目」Tab 自动出现(仅在该用户已绑定且有选中项目时);帖子详情页作者卡片下方也会显示最多 3 个项目摘要
展示字段
每个项目卡片显示:项目名、Fork 标记、License、描述、主要语言、Star 数、Fork 数、最近更新时间(formatTimeAgo 友好格式:刚刚 / X 分钟前 / X 小时前 / X 天前 / X 个月前 / X 年前)。项目链接跳转至 Gitee 仓库 Web 页面(自动去掉 html_url 末尾的 .git)。
权限
- 设置页、同步、保存操作均要求登录(
$uid非空) sync与save子动作强制 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~100syncRepos()中循环分页最多 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=15,CONNECTTIMEOUT=10,User-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_projects(utf8mb4):
| 字段 | 类型 | 说明 | |---|---|---| | 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
开发者:贰先生


