mirror of
https://github.com/rachelos/we-mp-rss.git
synced 2026-09-21 05:44:11 +08:00
1.4.9-Fix
This commit is contained in:
+50
-4
@@ -90,20 +90,20 @@ async def get_message_task(
|
||||
return success_response(data=message_task)
|
||||
except Exception as e:
|
||||
return error_response(code=500, message=str(e))
|
||||
@router.get("/message/test/{task_id}", summary="测试消息")
|
||||
@router.post("/message/test/{task_id}", summary="测试消息")
|
||||
async def test_message_task(
|
||||
task_id: str,
|
||||
current_user: dict = Depends(get_current_user_or_ak)
|
||||
):
|
||||
db=DB.get_session()
|
||||
"""
|
||||
测试消息消息任务详情
|
||||
测试消息任务
|
||||
|
||||
参数:
|
||||
task_id: 消息任务ID
|
||||
|
||||
返回:
|
||||
包含消息任务详情的成功响应,或错误响应
|
||||
包含测试结果的响应
|
||||
|
||||
异常:
|
||||
404: 消息任务不存在
|
||||
@@ -113,8 +113,54 @@ async def test_message_task(
|
||||
message_task = db.query(MessageTask).filter(MessageTask.id == task_id).first()
|
||||
if not message_task:
|
||||
raise HTTPException(status_code=404, detail="Message task not found")
|
||||
return success_response(data=message_task)
|
||||
|
||||
# 获取第一个订阅号进行测试
|
||||
from jobs.mps import get_feeds
|
||||
import json
|
||||
feeds = get_feeds(message_task)
|
||||
|
||||
if not feeds or len(feeds) == 0:
|
||||
return error_response(code=400, message="没有可用的订阅号进行测试")
|
||||
|
||||
feed = feeds[0] # 使用第一个订阅号进行测试
|
||||
|
||||
# 创建测试用的模拟文章数据
|
||||
from datetime import datetime, timedelta
|
||||
mock_articles = [{
|
||||
"id": "test-article-001",
|
||||
"mp_id": feed.id,
|
||||
"title": "测试文章标题",
|
||||
"pic_url": "https://via.placeholder.com/300x200",
|
||||
"url": "https://example.com/test-article",
|
||||
"description": "这是一篇测试文章的描述内容,用于测试消息任务功能是否正常。",
|
||||
"publish_time": (datetime.now() - timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"content": "<p>这是测试文章的正文内容。</p>"
|
||||
}]
|
||||
|
||||
# 执行测试消息发送(web_hook函数内部会处理字典类型)
|
||||
from jobs.webhook import MessageWebHook, web_hook
|
||||
# 使用类型忽略注释,因为web_hook函数会处理字典和Article对象
|
||||
test_hook = MessageWebHook( # type: ignore
|
||||
task=message_task,
|
||||
feed=feed,
|
||||
articles=mock_articles # type: ignore
|
||||
)
|
||||
|
||||
result = web_hook(test_hook, is_test=True)
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
"task_id": task_id,
|
||||
"feed_name": feed.mp_name,
|
||||
"test_article": mock_articles[0],
|
||||
"result": result
|
||||
},
|
||||
message=f"测试消息已发送到 {feed.mp_name}"
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
print_error(e)
|
||||
return error_response(code=500, message=str(e))
|
||||
@router.get("/{task_id}/run", summary="执行单个消息任务详情")
|
||||
async def run_message_task(
|
||||
|
||||
@@ -14,7 +14,7 @@ def notice( webhook_url, title, text,notice_type: str=None):
|
||||
- text: 消息内容
|
||||
"""
|
||||
if len(str(webhook_url)) == 0:
|
||||
print('未提供webhook_url')
|
||||
raise ValueError('未提供webhook_url')
|
||||
return
|
||||
if 'qyapi.weixin.qq.com' in webhook_url:
|
||||
notice_type = 'wechat'
|
||||
@@ -35,4 +35,4 @@ def notice( webhook_url, title, text,notice_type: str=None):
|
||||
elif notice_type == 'custom':
|
||||
send_custom_message(webhook_url, title, text)
|
||||
else:
|
||||
print('不支持的通知类型')
|
||||
raise ValueError(f'不支持的通知类型: {notice_type}')
|
||||
+33
-16
@@ -36,31 +36,48 @@ from core.models.message_task import MessageTask
|
||||
# from core.queue import TaskQueue
|
||||
from .webhook import web_hook
|
||||
interval=int(cfg.get("interval",60)) # 每隔多少秒执行一次
|
||||
def do_job(mp=None,task:MessageTask=None):
|
||||
def do_job(mp=None,task:MessageTask=None,isTest=False):
|
||||
# TaskQueue.add_task(test,info=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||
# print("执行任务", task.mps_id)
|
||||
print("执行任务")
|
||||
print(f"执行任务 (测试模式: {isTest})")
|
||||
all_count=0
|
||||
wx=WxGather().Model()
|
||||
try:
|
||||
wx.get_Articles(mp.faker_id,CallBack=UpdateArticle,Mps_id=mp.id,Mps_title=mp.mp_name, MaxPage=1,Over_CallBack=Update_Over,interval=interval)
|
||||
except Exception as e:
|
||||
print_error(e)
|
||||
# raise
|
||||
finally:
|
||||
count=wx.all_count()
|
||||
all_count+=count
|
||||
from jobs.webhook import MessageWebHook
|
||||
tms=MessageWebHook(task=task,feed=mp,articles=wx.articles)
|
||||
web_hook(tms)
|
||||
print_success(f"任务({task.id})[{mp.mp_name}]执行成功,{count}成功条数")
|
||||
if isTest:
|
||||
# 测试模式使用模拟数据
|
||||
from datetime import datetime, timedelta
|
||||
mock_articles = [{
|
||||
"id": "test-article-001",
|
||||
"mp_id": mp.id,
|
||||
"title": "测试文章标题",
|
||||
"pic_url": "https://via.placeholder.com/300x200",
|
||||
"url": "https://example.com/test-article",
|
||||
"description": "这是一篇测试文章的描述内容,用于测试webhook功能是否正常。",
|
||||
"publish_time": (datetime.now() - timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"content": "<p>这是测试文章的正文内容。</p>"
|
||||
}]
|
||||
count = 1
|
||||
else:
|
||||
wx=WxGather().Model()
|
||||
try:
|
||||
wx.get_Articles(mp.faker_id,CallBack=UpdateArticle,Mps_id=mp.id,Mps_title=mp.mp_name, MaxPage=1,Over_CallBack=Update_Over,interval=interval)
|
||||
except Exception as e:
|
||||
print_error(e)
|
||||
# raise
|
||||
finally:
|
||||
count=wx.all_count()
|
||||
mock_articles = wx.articles
|
||||
all_count+=count
|
||||
|
||||
from jobs.webhook import MessageWebHook
|
||||
tms=MessageWebHook(task=task,feed=mp,articles=mock_articles)
|
||||
web_hook(tms, is_test=isTest)
|
||||
print_success(f"任务({task.id})[{mp.mp_name}]执行成功,{count}成功条数")
|
||||
|
||||
from core.queue import TaskQueue
|
||||
def add_job(feeds:list[Feed]=None,task:MessageTask=None,isTest=False):
|
||||
if isTest:
|
||||
TaskQueue.clear_queue()
|
||||
for feed in feeds:
|
||||
TaskQueue.add_task(do_job,feed,task)
|
||||
TaskQueue.add_task(do_job,feed,task,isTest)
|
||||
if isTest:
|
||||
print(f"测试任务,{feed.mp_name},加入队列成功")
|
||||
reload_job()
|
||||
|
||||
+85
-41
@@ -48,19 +48,24 @@ def send_message(hook: MessageWebHook) -> str:
|
||||
message = parser.render(data)
|
||||
# 这里可以添加发送消息的具体实现
|
||||
print("发送消息:", message)
|
||||
notice(hook.task.web_hook_url, hook.task.name, message)
|
||||
try:
|
||||
notice(hook.task.web_hook_url, hook.task.name, message)
|
||||
except Exception as e:
|
||||
logger.error(f"发送消息失败: {e}")
|
||||
raise ValueError(f"发送消息失败: {e}")
|
||||
return message
|
||||
|
||||
def call_webhook(hook: MessageWebHook) -> str:
|
||||
def call_webhook(hook: MessageWebHook, is_test: bool = False) -> str:
|
||||
"""
|
||||
调用webhook接口发送数据
|
||||
|
||||
|
||||
参数:
|
||||
hook: MessageWebHook对象,包含任务、订阅源和文章信息
|
||||
|
||||
is_test: 是否为测试模式,测试模式下使用模拟数据
|
||||
|
||||
返回:
|
||||
str: 调用结果信息
|
||||
|
||||
|
||||
异常:
|
||||
ValueError: 当webhook调用失败时抛出
|
||||
"""
|
||||
@@ -91,31 +96,48 @@ def call_webhook(hook: MessageWebHook) -> str:
|
||||
"now": "{{ now }}"
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
# 检查template是否需要content
|
||||
template_needs_content = "content" in template.lower()
|
||||
|
||||
|
||||
# 根据content_format处理内容
|
||||
content_format = cfg.get("webhook.content_format", "html")
|
||||
logger.info(f'Content将以{content_format}格式发送')
|
||||
processed_articles = []
|
||||
for article in hook.articles:
|
||||
if isinstance(article, dict) and "content" in article and article["content"]:
|
||||
processed_article = article.copy()
|
||||
# 只有template需要content时才进行格式转换
|
||||
if template_needs_content:
|
||||
processed_article["content"] = format_content(processed_article["content"], content_format)
|
||||
processed_articles.append(processed_article)
|
||||
else:
|
||||
processed_articles.append(article)
|
||||
|
||||
|
||||
# 测试模式下使用模拟数据
|
||||
if is_test:
|
||||
from datetime import timedelta
|
||||
logger.info("使用模拟数据测试webhook")
|
||||
mock_article = {
|
||||
"id": "test-article-001",
|
||||
"mp_id": hook.feed.id if hook.feed else "test-mp-id",
|
||||
"title": "测试文章标题",
|
||||
"pic_url": "https://via.placeholder.com/300x200",
|
||||
"url": "https://example.com/test-article",
|
||||
"description": "这是一篇测试文章的描述内容,用于测试webhook功能是否正常。",
|
||||
"publish_time": (datetime.now() - timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"content": "<p>这是测试文章的正文内容。</p>"
|
||||
}
|
||||
processed_articles = [mock_article]
|
||||
else:
|
||||
processed_articles = []
|
||||
for article in hook.articles:
|
||||
if isinstance(article, dict) and "content" in article and article["content"]:
|
||||
processed_article = article.copy()
|
||||
# 只有template需要content时才进行格式转换
|
||||
if template_needs_content:
|
||||
processed_article["content"] = format_content(processed_article["content"], content_format)
|
||||
processed_articles.append(processed_article)
|
||||
else:
|
||||
processed_articles.append(article)
|
||||
|
||||
data = {
|
||||
"feed": hook.feed,
|
||||
"articles": processed_articles,
|
||||
"task": hook.task,
|
||||
"now": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
}
|
||||
|
||||
|
||||
# 预处理content字段
|
||||
import json
|
||||
def process_content(content):
|
||||
@@ -125,7 +147,7 @@ def call_webhook(hook: MessageWebHook) -> str:
|
||||
json_escaped = json.dumps(content, ensure_ascii=False)
|
||||
# 去掉外层引号避免重复
|
||||
return json_escaped[1:-1]
|
||||
|
||||
|
||||
# 处理articles中的content字段,进行JSON转义
|
||||
if "articles" in data:
|
||||
for i, article in enumerate(data["articles"]):
|
||||
@@ -134,11 +156,11 @@ def call_webhook(hook: MessageWebHook) -> str:
|
||||
data["articles"][i]["content"] = process_content(article["content"])
|
||||
elif hasattr(article, "content"):
|
||||
setattr(data["articles"][i], "content", process_content(getattr(article, "content")))
|
||||
|
||||
|
||||
parser = TemplateParser(template)
|
||||
|
||||
|
||||
payload = parser.render(data)
|
||||
# logger.info(payload)
|
||||
logger.info(f'Webhook payload: {payload}')
|
||||
|
||||
# 检查web_hook_url是否为空
|
||||
if not hook.task.web_hook_url:
|
||||
@@ -181,16 +203,16 @@ def call_webhook(hook: MessageWebHook) -> str:
|
||||
except Exception as e:
|
||||
raise ValueError(f"Webhook调用失败: {str(e)}")
|
||||
|
||||
def web_hook(hook:MessageWebHook):
|
||||
def web_hook(hook:MessageWebHook, is_test:bool = False):
|
||||
"""
|
||||
根据消息类型路由到对应的处理函数
|
||||
|
||||
|
||||
参数:
|
||||
hook: MessageWebHook对象,包含任务、订阅源和文章信息
|
||||
|
||||
is_test: 是否为测试模式,测试模式下使用模拟数据
|
||||
返回:
|
||||
对应处理函数的返回结果
|
||||
|
||||
|
||||
异常:
|
||||
ValueError: 当消息类型未知时抛出
|
||||
"""
|
||||
@@ -200,36 +222,58 @@ def web_hook(hook:MessageWebHook):
|
||||
if len(hook.articles)<=0:
|
||||
# raise ValueError("没有更新到文章")
|
||||
logger.warning("没有更新到文章")
|
||||
return
|
||||
return
|
||||
for article in hook.articles:
|
||||
if isinstance(article, dict):
|
||||
# 如果是字典类型,直接使用
|
||||
def process_field_value(field_name, article):
|
||||
value = article.get(field_name, "")
|
||||
if field_name == "publish_time" and value:
|
||||
# 如果已经是格式化的字符串,直接返回
|
||||
if isinstance(value, str) and "-" in value and ":" in value:
|
||||
return value
|
||||
# 如果是时间戳整数,转换为字符串
|
||||
try:
|
||||
if isinstance(value, (int, float)):
|
||||
return datetime.fromtimestamp(value).strftime("%Y-%m-%d %H:%M:%S")
|
||||
except (ValueError, TypeError, OSError):
|
||||
pass
|
||||
return value
|
||||
return value
|
||||
|
||||
processed_article = {
|
||||
field.name: (
|
||||
datetime.fromtimestamp(article[field.name]).strftime("%Y-%m-%d %H:%M:%S")
|
||||
if field.name == "publish_time" and field.name in article
|
||||
else article.get(field.name, "")
|
||||
)
|
||||
field.name: process_field_value(field.name, article)
|
||||
for field in Article.__table__.columns
|
||||
}
|
||||
else:
|
||||
# 如果是Article对象,使用getattr获取属性
|
||||
def process_field_value_obj(field_name, article):
|
||||
value = getattr(article, field.name, "")
|
||||
if field_name == "publish_time" and value:
|
||||
# 如果已经是格式化的字符串,直接返回
|
||||
if isinstance(value, str) and "-" in value and ":" in value:
|
||||
return value
|
||||
# 如果是时间戳整数,转换为字符串
|
||||
try:
|
||||
if isinstance(value, (int, float)):
|
||||
return datetime.fromtimestamp(value).strftime("%Y-%m-%d %H:%M:%S")
|
||||
except (ValueError, TypeError, OSError):
|
||||
pass
|
||||
return value
|
||||
return value
|
||||
|
||||
processed_article = {
|
||||
field.name: (
|
||||
datetime.fromtimestamp(getattr(article, field.name)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
if field.name == "publish_time"
|
||||
else getattr(article, field.name)
|
||||
)
|
||||
field.name: process_field_value_obj(field.name, article)
|
||||
for field in Article.__table__.columns
|
||||
}
|
||||
processed_articles.append(processed_article)
|
||||
|
||||
|
||||
hook.articles = processed_articles
|
||||
|
||||
|
||||
if hook.task.message_type == 0: # 发送消息
|
||||
return send_message(hook)
|
||||
elif hook.task.message_type == 1: # 调用webhook
|
||||
return call_webhook(hook)
|
||||
return call_webhook(hook, is_test)
|
||||
else:
|
||||
raise ValueError(f"未知的消息类型: {hook.task.message_type}")
|
||||
except Exception as e:
|
||||
|
||||
@@ -16,6 +16,10 @@ export const RunMessageTask = (id: string,isTest:boolean=false) => {
|
||||
return http.get<MessageTask>(`/wx/message_tasks/${id}/run?isTest=${isTest}`)
|
||||
}
|
||||
|
||||
export const TestMessageTask = (id: string) => {
|
||||
return http.post(`/wx/message_tasks/message/test/${id}`)
|
||||
}
|
||||
|
||||
export const createMessageTask = (data: MessageTaskUpdate) => {
|
||||
return http.post('/wx/message_tasks', data)
|
||||
}
|
||||
|
||||
@@ -285,8 +285,7 @@ onMounted(() => {
|
||||
|
||||
<style scoped>
|
||||
.message-task-form {
|
||||
padding: 20px;
|
||||
max-width: 800px;
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { listMessageTasks, deleteMessageTask,FreshJobApi,FreshJobByIdApi,RunMessageTask } from '@/api/messageTask'
|
||||
import { listMessageTasks, deleteMessageTask,FreshJobApi,FreshJobByIdApi,RunMessageTask,TestMessageTask } from '@/api/messageTask'
|
||||
import type { MessageTask } from '@/types/messageTask'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Message, Modal } from '@arco-design/web-vue'
|
||||
@@ -184,22 +184,41 @@ const handleDelete = async (id: number) => {
|
||||
})
|
||||
}
|
||||
const runTask = async (id: number,isTest:boolean=false) => {
|
||||
Modal.confirm({
|
||||
title: '确认执行',
|
||||
content: '确定要执行这条消息任务吗?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
try {
|
||||
let res = await RunMessageTask(id,isTest)
|
||||
Message.success(res?.message||'执行成功')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
Message.error('执行失败')
|
||||
console.log(error)
|
||||
if (isTest) {
|
||||
Modal.confirm({
|
||||
title: '确认测试',
|
||||
content: '确定要测试这条消息任务吗?将发送一条测试消息。',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
try {
|
||||
let res = await TestMessageTask(id)
|
||||
Message.success(res?.message||'测试成功')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
Message.error('测试失败')
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
Modal.confirm({
|
||||
title: '确认执行',
|
||||
content: '确定要执行这条消息任务吗?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
try {
|
||||
let res = await RunMessageTask(id,isTest)
|
||||
Message.success(res?.message||'执行成功')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
Message.error('执行失败')
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
Reference in New Issue
Block a user