Skip to content

Commit d274eb6

Browse files
authored
Merge pull request #9 from AptS-1547/feat-template
Feat template
2 parents 0caa443 + 78502c6 commit d274eb6

21 files changed

Lines changed: 1269 additions & 573 deletions

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ RUN mkdir -p /app/templates \
1414

1515
COPY --chown=appuser:appuser . .
1616

17-
VOLUME [ "/app/config" ]
17+
VOLUME [ "/app/templates" ]
1818

1919
USER appuser
2020

app/api/__init__.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright 2025 AptS-1547
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
"""
15+
Onebot GitHub Webhook API 模块
16+
本模块包含应用的所有 API 路由
17+
作者:AptS:1547
18+
版本:0.1.0-alpha
19+
日期:2025-04-17
20+
本程序遵循 Apache License 2.0 许可证
21+
"""
22+
23+
from fastapi import APIRouter
24+
25+
from .github_webhook import router as github_webhook_router
26+
27+
# 主路由
28+
api_router = APIRouter()
29+
30+
# 注册子路由
31+
api_router.include_router(github_webhook_router, prefix="/github-webhook", tags=["github"])
32+
33+
__all__ = ["api_router"]

app/api/github_webhook.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Copyright 2025 AptS-1547
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
"""
15+
GitHub Webhook 路由模块
16+
本模块用于处理 GitHub Webhook 事件,并将其转发到配置的 OneBot 目标。
17+
作者:AptS:1547
18+
版本:0.1.0-alpha
19+
日期:2025-04-17
20+
本程序遵循 Apache License 2.0 许可证
21+
"""
22+
23+
import logging
24+
from fastapi import APIRouter, Request, HTTPException
25+
26+
from app.core import GitHubWebhookHandler
27+
from app.onebot import text, get_onebot_client
28+
from app.models.config import get_settings
29+
30+
router = APIRouter()
31+
logger = logging.getLogger(__name__)
32+
33+
config = get_settings()
34+
35+
@router.post("")
36+
async def github_webhook(
37+
request: Request,
38+
): # pylint: disable=too-many-return-statements
39+
"""处理 GitHub webhook 请求"""
40+
41+
onebot_client = get_onebot_client()
42+
43+
if not onebot_client:
44+
logger.error("OneBot 客户端未初始化,无法处理请求")
45+
raise HTTPException(status_code=503, detail="OneBot 客户端未初始化")
46+
47+
content_type = request.headers.get("Content-Type")
48+
if content_type != "application/json":
49+
logger.info("收到非 JSON 格式的请求,忽略")
50+
return {"status": "ignored", "message": "只处理 application/json 格式的请求"}
51+
52+
event_type = request.headers.get("X-GitHub-Event", "")
53+
if not event_type:
54+
logger.info("缺少 X-GitHub-Event 头,忽略")
55+
return {"status": "ignored", "message": "缺少 X-GitHub-Event 头"}
56+
57+
try:
58+
await GitHubWebhookHandler.verify_signature(
59+
request,
60+
config.GITHUB_WEBHOOK,
61+
request.headers.get("X-Hub-Signature-256")
62+
)
63+
except HTTPException as e:
64+
logger.info("签名验证失败: %s", e.detail)
65+
return {"status": "ignored", "message": f"签名验证失败: {e.detail}"}
66+
67+
payload = await request.json()
68+
if not payload:
69+
logger.info("请求体为空,忽略")
70+
return {"status": "ignored", "message": "请求体为空"}
71+
72+
repo_name = payload.get("repository", {}).get("full_name")
73+
branch = payload.get("ref", "").replace("refs/heads/", "")
74+
75+
matched_webhook = GitHubWebhookHandler.find_matching_webhook(
76+
repo_name,
77+
branch,
78+
event_type,
79+
config.GITHUB_WEBHOOK
80+
)
81+
82+
if not matched_webhook:
83+
logger.info("找不到匹配的 webhook 配置: 仓库 %s, 分支 %s, 事件类型 %s", repo_name, branch, event_type)
84+
return {"status": "ignored", "message": "找不到匹配的 webhook 配置"}
85+
86+
# 处理不同类型的事件,暂时只支持 push 事件
87+
if event_type == "push":
88+
push_data = GitHubWebhookHandler.extract_push_data(payload)
89+
90+
logger.info("发现新的 push 事件,来自 %s 仓库", push_data["repo_name"])
91+
logger.info("分支: %s,推送者: %s,提交数量: %s",
92+
push_data["branch"],
93+
push_data["pusher"],
94+
push_data["commit_count"])
95+
96+
# 向配置的所有 OneBot 目标发送通知
97+
for target in matched_webhook.ONEBOT:
98+
logger.info("正在发送消息到 QQ %s %s", target.type, target.id)
99+
100+
message = format_github_push_message(
101+
repo_name=push_data["repo_name"],
102+
branch=push_data["branch"],
103+
pusher=push_data["pusher"],
104+
commit_count=push_data["commit_count"],
105+
commits=push_data["commits"]
106+
)
107+
108+
# 使用已有的客户端发送消息
109+
await onebot_client.send_message(target.type, target.id, message)
110+
111+
return {"status": "success", "message": "处理 push 事件成功"}
112+
113+
logger.info("收到 %s 事件,但尚未实现处理逻辑", event_type)
114+
return {"status": "ignored", "message": f"暂不处理 {event_type} 类型的事件"}
115+
116+
117+
def format_github_push_message(repo_name, branch, pusher, commit_count, commits):
118+
"""格式化 GitHub 推送消息"""
119+
120+
message = [
121+
text("📢 GitHub 推送通知\n"),
122+
text(f"仓库:{repo_name}\n"),
123+
text(f"分支:{branch}\n"),
124+
text(f"推送者:{pusher}\n"),
125+
text(f"提交数量:{commit_count}\n\n"),
126+
text("最新提交:\n")
127+
]
128+
129+
# 最多展示3条最新提交
130+
for commit in commits[:3]:
131+
short_id = commit["id"][:7]
132+
commit_message = commit["message"].split("\n")[0] # 只取第一行
133+
author = commit.get("author", {}).get("name", "未知")
134+
135+
message.append(text(f"[{short_id}] {commit_message} (by {author})\n"))
136+
137+
return message

app/core/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright 2025 AptS-1547
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
"""
15+
OneBot GitHub Webhook core 模块
16+
本模块用于处理 GitHub Webhook 事件的匹配逻辑,包括验证签名、查找匹配的 webhook 配置和提取 push 事件数据。
17+
作者:AptS:1547
18+
版本:0.1.0-alpha
19+
日期:2025-04-17
20+
本程序遵循 Apache License 2.0 许可证
21+
"""
22+
23+
from .github import GitHubWebhookHandler
24+
25+
__all__ = [
26+
"GitHubWebhookHandler",
27+
]

0 commit comments

Comments
 (0)