fix: kanban API timestamp normalization — _fmt_ts unify epoch/ISO to ISO 8601 output (from mohe, t_a1858603)
This commit is contained in:
+31
-2
@@ -17,6 +17,29 @@ def db():
|
|||||||
return sqlite3.connect(KANBAN_DB)
|
return sqlite3.connect(KANBAN_DB)
|
||||||
|
|
||||||
|
|
||||||
|
def _fmt_ts(v):
|
||||||
|
"""统一时间格式:epoch 或 ISO 字符串 → ISO 8601 字符串。
|
||||||
|
DB 存储以 epoch 为主(CLI 写入),历史数据有少量 ISO 混存(半路接入),
|
||||||
|
输出层统一成 ISO,调用方无需感知存储格式差异。"""
|
||||||
|
if v is None:
|
||||||
|
return None
|
||||||
|
if isinstance(v, (int, float)):
|
||||||
|
try:
|
||||||
|
return datetime.fromtimestamp(int(v)).strftime("%Y-%m-%dT%H:%M:%S")
|
||||||
|
except (OverflowError, OSError, ValueError):
|
||||||
|
return str(v)
|
||||||
|
s = str(v)
|
||||||
|
try:
|
||||||
|
# 已带 T 的 ISO 直接返回;纯数字字符串按 epoch 转
|
||||||
|
if "T" in s:
|
||||||
|
return s[:19]
|
||||||
|
if s.isdigit():
|
||||||
|
return datetime.fromtimestamp(int(s)).strftime("%Y-%m-%dT%H:%M:%S")
|
||||||
|
except (OverflowError, OSError, ValueError):
|
||||||
|
pass
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
class KanbanAPI(http.server.BaseHTTPRequestHandler):
|
class KanbanAPI(http.server.BaseHTTPRequestHandler):
|
||||||
def _json(self, data, status=200):
|
def _json(self, data, status=200):
|
||||||
self.send_response(status)
|
self.send_response(status)
|
||||||
@@ -37,6 +60,7 @@ class KanbanAPI(http.server.BaseHTTPRequestHandler):
|
|||||||
title = body.get("title", "")
|
title = body.get("title", "")
|
||||||
assignee = body.get("assignee", "")
|
assignee = body.get("assignee", "")
|
||||||
body_text = body.get("body", "")
|
body_text = body.get("body", "")
|
||||||
|
created_by = body.get("created_by", "") or body.get("author", "")
|
||||||
if not title:
|
if not title:
|
||||||
return self._json({"error": "title required"}, 400)
|
return self._json({"error": "title required"}, 400)
|
||||||
|
|
||||||
@@ -47,6 +71,8 @@ class KanbanAPI(http.server.BaseHTTPRequestHandler):
|
|||||||
cmd += ["--assignee", assignee]
|
cmd += ["--assignee", assignee]
|
||||||
if body_text:
|
if body_text:
|
||||||
cmd += ["--body", body_text]
|
cmd += ["--body", body_text]
|
||||||
|
if created_by:
|
||||||
|
cmd += ["--created-by", created_by]
|
||||||
r = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
r = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||||
|
|
||||||
if r.returncode != 0:
|
if r.returncode != 0:
|
||||||
@@ -66,6 +92,7 @@ class KanbanAPI(http.server.BaseHTTPRequestHandler):
|
|||||||
title = body.get("title", "")
|
title = body.get("title", "")
|
||||||
assignee = body.get("assignee", "")
|
assignee = body.get("assignee", "")
|
||||||
body_text = body.get("body", "")
|
body_text = body.get("body", "")
|
||||||
|
created_by = body.get("created_by", "") or body.get("author", "")
|
||||||
if not title:
|
if not title:
|
||||||
return self._json({"error": "title required"}, 400)
|
return self._json({"error": "title required"}, 400)
|
||||||
|
|
||||||
@@ -75,6 +102,8 @@ class KanbanAPI(http.server.BaseHTTPRequestHandler):
|
|||||||
cmd += ["--assignee", assignee]
|
cmd += ["--assignee", assignee]
|
||||||
if body_text:
|
if body_text:
|
||||||
cmd += ["--body", body_text]
|
cmd += ["--body", body_text]
|
||||||
|
if created_by:
|
||||||
|
cmd += ["--created-by", created_by]
|
||||||
r = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
r = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||||
if r.returncode != 0:
|
if r.returncode != 0:
|
||||||
return self._json({"error": r.stderr.strip()}, 500)
|
return self._json({"error": r.stderr.strip()}, 500)
|
||||||
@@ -132,7 +161,7 @@ class KanbanAPI(http.server.BaseHTTPRequestHandler):
|
|||||||
for r in rows:
|
for r in rows:
|
||||||
tasks.append({
|
tasks.append({
|
||||||
"id": r[0], "title": r[1], "body": r[2], "status": r[3],
|
"id": r[0], "title": r[1], "body": r[2], "status": r[3],
|
||||||
"assignee": r[4], "created_by": r[5], "created_at": r[6]
|
"assignee": r[4], "created_by": r[5], "created_at": _fmt_ts(r[6])
|
||||||
})
|
})
|
||||||
return self._json({"tasks": tasks})
|
return self._json({"tasks": tasks})
|
||||||
|
|
||||||
@@ -208,7 +237,7 @@ class KanbanAPI(http.server.BaseHTTPRequestHandler):
|
|||||||
return self._json({
|
return self._json({
|
||||||
"id": row[0], "title": row[1], "body": row[2],
|
"id": row[0], "title": row[1], "body": row[2],
|
||||||
"status": row[3], "assignee": row[4],
|
"status": row[3], "assignee": row[4],
|
||||||
"created_by": row[5], "created_at": row[6]
|
"created_by": row[5], "created_at": _fmt_ts(row[6])
|
||||||
})
|
})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user