Files
dingtalk-workspace-cli/skills/mono/scripts/report_inbox_today.py
qinze a65d6f23ec fix: resolve real-machine QA findings across CLI, scripts and skill docs
Fix CLI command bugs surfaced by full real-machine QA:
- aitable: make chart/dashboard share update --enabled a string flag so
  "--enabled false" disables instead of silently enabling (bool flag +
  space-syntax help example inverted the action); clarify chart update
  requires --config; make form get filter by view-id client-side so it
  returns a single form; drop inline // comments from chart JSON examples
- chat: resolve conversation-info --user to openDingTalkId, register
  --id/--conversation-id/--chat aliases; cap list-all-conversations
  --limit at 100 and reject larger values instead of silent truncation;
  detect webhook errcode failures instead of wrapping them as success;
  remove duplicate group/members subcommand registration in help
- contact: register --dept/--depts as the primary dept flags to match
  the RunE parsing (were only registered as --id/--ids)
- sheet: emit clean JSON for media-upload and export under --format json,
  suppressing progress lines that leaked onto stdout
- wiki: correct node create --type enum (drop unsupported asheet, add
  axls/able/appt/adraw/amind)
- ding: default message list --type to ALL since the server rejects an
  empty type

Fix helper scripts (mono and multi):
- aitable import/export flag names and tableId length regex
- mail search --limit, contact dept response keys and userInfo nesting
- attendance_my_record whoami compatibility, calendar_schedule_meeting
  event id unwrapping, drive_tree_list recursion via fileId, report
  scripts migrated off deprecated report list/detail

Sync skill docs (mono and multi) to real-machine behavior across all
products: command indexes, flag names, enums, return-structure keys, and
cross-product intent routing; annotate genuinely server-side limitations
and the no-op global --jq/--fields flags.
2026-07-07 23:38:23 +08:00

161 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""
查看今天收到的日志列表及详情
基于 `dws report inbox list` + `dws report entry get`(旧的 report list / report detail
已废弃)。inbox list 返回的 result[] 使用中文展示键:日期 / 标题 / 发送人 / 状态 / 钉钉链接;
reportId 不在 result[] 里,只在 _internalDetailCommands[].command 中,按页与 result[] 同序对应。
用法:
python report_inbox_today.py
python report_inbox_today.py --days 3 # 最近 3 天
python report_inbox_today.py --detail # 额外拉取每条正文 (entry get)
python report_inbox_today.py --dry-run
"""
import sys
import json
import subprocess
import argparse
from datetime import datetime, timedelta
from typing import List, Any, Optional, Tuple
def run_dws(
args: List[str], dry_run: bool = False,
) -> Optional[Any]:
cmd = ['dws'] + args
if dry_run:
print(f"[dry-run] {' '.join(cmd)}")
return None
try:
result = subprocess.run(
cmd, capture_output=True, text=True, timeout=60
)
if result.returncode != 0:
print(f"错误:{result.stderr.strip()}", file=sys.stderr)
return None
return json.loads(result.stdout)
except (subprocess.TimeoutExpired, json.JSONDecodeError,
FileNotFoundError) as e:
print(f"错误:{e}", file=sys.stderr)
return None
def iso_start(dt: datetime) -> str:
return dt.strftime('%Y-%m-%dT00:00:00+08:00')
def iso_end(dt: datetime) -> str:
return dt.strftime('%Y-%m-%dT23:59:59+08:00')
def report_id_from_command(cmd: str) -> str:
parts = cmd.split()
if '--report-id' in parts:
i = parts.index('--report-id')
if i + 1 < len(parts):
return parts[i + 1]
return ''
def fetch_inbox(
start: str, end: str, dry_run: bool,
) -> List[Tuple[dict, str]]:
"""按 cursor 翻页拉全 inbox;返回 (result_item, reportId) 列表。"""
pairs: List[Tuple[dict, str]] = []
cursor = 0
while True:
data = run_dws([
'report', 'inbox', 'list',
'--start', start,
'--end', end,
'--cursor', str(cursor),
'--size', '20',
'--format', 'json',
], dry_run=dry_run)
if dry_run or not isinstance(data, dict):
return pairs
items = data.get('result') or []
cmds = data.get('_internalDetailCommands') or []
for idx, item in enumerate(items):
rid = ''
if idx < len(cmds):
rid = report_id_from_command(
cmds[idx].get('command', '')
)
pairs.append((item, rid))
if data.get('hasMore') and data.get('nextCursor') is not None:
cursor = data['nextCursor']
else:
break
return pairs
def print_detail(rid: str) -> None:
detail = run_dws([
'report', 'entry', 'get',
'--report-id', rid, '--format', 'json',
])
if not isinstance(detail, dict):
return
result = detail.get('result')
if not isinstance(result, dict):
return
for c in (result.get('report_content') or [])[:3]:
key = c.get('key', '')
val = c.get('value', '')
if key and val:
print(f" {key}: {str(val).strip()[:60]}")
def main():
parser = argparse.ArgumentParser(description='查看收到的日志')
parser.add_argument(
'--days', type=int, default=1, help='查询天数 (默认 1,即今天)'
)
parser.add_argument(
'--detail', action='store_true', help='额外拉取每条正文'
)
parser.add_argument('--dry-run', action='store_true')
args = parser.parse_args()
now = datetime.now()
start_dt = now - timedelta(days=max(args.days - 1, 0))
start = iso_start(start_dt)
end = iso_end(now)
label = '今天' if args.days == 1 else f'最近 {args.days} 天'
print(f'查看{label}收到的日志...\n')
pairs = fetch_inbox(start, end, args.dry_run)
if args.dry_run:
return
if not pairs:
print(' 暂无收到的日志')
return
print(f"{label}日志 ({len(pairs)} 条)")
print('=' * 50)
for item, rid in pairs:
title = item.get('标题') or '日志'
sender = item.get('发送人') or '未知'
date = item.get('日期') or ''
status = item.get('状态') or ''
link = item.get('钉钉链接') or ''
print(f"\n {title} - {sender}")
print(f" 时间: {date}")
if status:
print(f" 状态: {status}")
if link:
print(f" 链接: {link}")
if args.detail and rid:
print_detail(rid)
if __name__ == '__main__':
main()