星枢: PST处理脚本备份 (2026-04-13)
This commit is contained in:
101
openclaw/xingshu/pst-processing/rules/apply_rules.py
Normal file
101
openclaw/xingshu/pst-processing/rules/apply_rules.py
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
PST 邮件清理规则执行脚本 v1.2
|
||||
用法: python3 apply_rules.py <csv_file>
|
||||
"""
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
RULES_FILE = '/Users/weishen/pst-processing/rules/delete_rules.json'
|
||||
|
||||
def load_rules():
|
||||
with open(RULES_FILE) as f:
|
||||
return json.load(f)['rules']
|
||||
|
||||
def apply_rules(csv_path):
|
||||
rules = load_rules()
|
||||
rows = list(csv.DictReader(open(csv_path, encoding='utf-8')))
|
||||
|
||||
for r in rows:
|
||||
r['delete_flag'] = 'N'
|
||||
|
||||
total_deleted = 0
|
||||
|
||||
for rule in rules:
|
||||
folder_pattern = rule['folder_contains']
|
||||
action = rule['action']
|
||||
|
||||
folder_rows = [r for r in rows if folder_pattern in r['folder']]
|
||||
if not folder_rows:
|
||||
continue
|
||||
|
||||
deleted_count = 0
|
||||
kept_count = 0
|
||||
|
||||
if action == 'keep':
|
||||
kept_count = len(folder_rows)
|
||||
|
||||
elif action == 'delete_all':
|
||||
for r in folder_rows:
|
||||
r['delete_flag'] = 'Y'
|
||||
deleted_count += 1
|
||||
|
||||
elif action == 'keep_sample':
|
||||
keep_limit = rule['keep_count']
|
||||
subject_map = defaultdict(list)
|
||||
for r in folder_rows:
|
||||
subj = r['subject'].strip()[:80]
|
||||
subject_map[subj].append(r)
|
||||
sorted_subjects = sorted(subject_map.items(), key=lambda x: -len(x[1]))
|
||||
|
||||
for subj, emails in sorted_subjects:
|
||||
if kept_count >= keep_limit:
|
||||
for r in emails:
|
||||
r['delete_flag'] = 'Y'
|
||||
deleted_count += 1
|
||||
else:
|
||||
for i, r in enumerate(emails):
|
||||
if i == 0:
|
||||
kept_count += 1
|
||||
else:
|
||||
r['delete_flag'] = 'Y'
|
||||
deleted_count += 1
|
||||
|
||||
elif action == 'keep_if_attachment':
|
||||
for r in folder_rows:
|
||||
if r['has_attachment'] == 'Y':
|
||||
kept_count += 1
|
||||
else:
|
||||
r['delete_flag'] = 'Y'
|
||||
deleted_count += 1
|
||||
|
||||
print(f" {folder_pattern}: {len(folder_rows)} | 保留{kept_count} | 删除{deleted_count}")
|
||||
total_deleted += deleted_count
|
||||
|
||||
total_kept = len(rows) - total_deleted
|
||||
print(f"📊 总计: 保留{total_kept} | 删除{total_deleted}")
|
||||
|
||||
fieldnames = list(rows[0].keys())
|
||||
out_marked = csv_path.replace('.csv', '_marked.csv')
|
||||
out_delete = csv_path.replace('.csv', '_delete_list.csv')
|
||||
|
||||
with open(out_marked, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
with open(out_delete, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows([r for r in rows if r['delete_flag'] == 'Y'])
|
||||
|
||||
print(f"✅ 输出: {out_marked}")
|
||||
print(f"✅ 删除清单: {out_delete} ({total_deleted} 封)")
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("用法: python3 apply_rules.py <csv_file>")
|
||||
sys.exit(1)
|
||||
apply_rules(sys.argv[1])
|
||||
84
openclaw/xingshu/pst-processing/rules/delete_rules.json
Normal file
84
openclaw/xingshu/pst-processing/rules/delete_rules.json
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"version": "1.2",
|
||||
"description": "PST邮件清理规则",
|
||||
"rules": [
|
||||
{
|
||||
"id": "aws_notification",
|
||||
"folder_contains": "AWS Notification",
|
||||
"action": "keep_sample",
|
||||
"keep_count": 5,
|
||||
"keep_by": "unique_subject",
|
||||
"description": "AWS告警通知,每不同subject保留1封,最多5封"
|
||||
},
|
||||
{
|
||||
"id": "prisma_cloud",
|
||||
"folder_contains": "Prisma Cloud Notifications",
|
||||
"action": "keep_sample",
|
||||
"keep_count": 5,
|
||||
"keep_by": "unique_subject",
|
||||
"description": "Prisma Cloud通知,每不同subject保留1封,最多5封"
|
||||
},
|
||||
{
|
||||
"id": "x4x_tenant_provisioning",
|
||||
"folder_contains": "X4X-Tenant Provisioning",
|
||||
"action": "keep_sample",
|
||||
"keep_count": 5,
|
||||
"keep_by": "unique_subject",
|
||||
"description": "X4X租户配置通知,每不同subject保留1封,最多5封"
|
||||
},
|
||||
{
|
||||
"id": "qualys",
|
||||
"folder_contains": "Qualys",
|
||||
"action": "keep_sample",
|
||||
"keep_count": 5,
|
||||
"keep_by": "unique_subject",
|
||||
"description": "Qualys安全扫描通知,每不同subject保留1封,最多5封"
|
||||
},
|
||||
{
|
||||
"id": "teams_notification",
|
||||
"folder_contains": "Teams Notification",
|
||||
"action": "keep_if_attachment",
|
||||
"description": "Teams会议通知,有附件保留,无附件删除"
|
||||
},
|
||||
{
|
||||
"id": "sma_notification",
|
||||
"folder_contains": "SMA Notficiation",
|
||||
"action": "keep_sample",
|
||||
"keep_count": 10,
|
||||
"keep_by": "unique_subject",
|
||||
"description": "SMA工单通知,每月保留10封不同subject,其余删除"
|
||||
},
|
||||
{
|
||||
"id": "ppm_saas_change",
|
||||
"folder_contains": "PPM SaaS Change",
|
||||
"action": "delete_all",
|
||||
"description": "PPM故障单解决通知,全部删除"
|
||||
},
|
||||
{
|
||||
"id": "cloudhealth",
|
||||
"folder_contains": "CloudHealth",
|
||||
"action": "keep",
|
||||
"description": "CloudHealth成本报告,全部保留"
|
||||
},
|
||||
{
|
||||
"id": "saas_bi_report",
|
||||
"folder_contains": "SaaS BI Report",
|
||||
"action": "keep",
|
||||
"description": "BI数据推送,全部保留"
|
||||
},
|
||||
{
|
||||
"id": "x4x_tenant_decommissioning",
|
||||
"folder_contains": "X4X-Tenant Decommissioning",
|
||||
"action": "delete_all",
|
||||
"description": "租户下线通知,全部删除"
|
||||
},
|
||||
{
|
||||
"id": "x4x_license_renewal",
|
||||
"folder_contains": "X4X-License Renewal",
|
||||
"action": "delete_all",
|
||||
"description": "续期通知,全部删除"
|
||||
}
|
||||
],
|
||||
"default_action": "keep",
|
||||
"updated": "2026-04-13"
|
||||
}
|
||||
Reference in New Issue
Block a user