dy-dashboard/scripts/renumber_spot_confirmations.py
2026-10-28 11:14:17 +08:00

86 lines
3.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""Renumber the current history import to its source application IDs."""
import argparse
import gzip
import json
import re
import sys
from datetime import datetime
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
def run(local=False):
if local:
import test_wsgi # noqa: F401
from services.db import get_db
conn = get_db()
foreign_keys_disabled = False
try:
with conn.cursor() as cur:
cur.execute("""SELECT a.id,a.status,a.product_name,a.image_path
FROM spot_applications a ORDER BY a.id FOR UPDATE""")
applications = cur.fetchall()
imported = []
for row in applications:
match = re.fullmatch(r'/static/uploads/spot_application/history_(\d+)_[0-9a-f]{16}\.[A-Za-z0-9]+',
row.get('image_path') or '')
if match:
imported.append((row['id'], int(match.group(1))))
if len(imported) != 547 or {target for _, target in imported} != set(range(1, 548)):
raise RuntimeError('导入记录不是完整且唯一的1-547,停止重排')
imported_ids = {old for old, _ in imported}
retained = [row for row in applications if row['id'] not in imported_ids]
max_id = max(row['id'] for row in applications)
retained_moves = []
next_id = max_id + 1000
targets = {target for _, target in imported}
for row in retained:
if row['id'] in targets:
retained_moves.append((row['id'], next_id))
next_id += 1
backup = ROOT / 'var/manual-updates' / ('spot-confirmation-renumber-' + datetime.now().strftime('%Y%m%dT%H%M%S') + '.json.gz')
backup.parent.mkdir(parents=True, exist_ok=True)
with gzip.open(backup, 'wt', encoding='utf-8') as handle:
json.dump({'imported': imported, 'retained_moves': retained_moves}, handle, ensure_ascii=False)
offset = next_id + 1000
cur.execute('SET FOREIGN_KEY_CHECKS=0')
foreign_keys_disabled = True
for old, new in retained_moves:
cur.execute('UPDATE spot_confirmations SET application_id=%s WHERE application_id=%s', (new, old))
cur.execute('UPDATE spot_applications SET id=%s WHERE id=%s', (new, old))
for old, target in imported:
temporary = offset + target
cur.execute('UPDATE spot_confirmations SET application_id=%s WHERE application_id=%s', (temporary, old))
cur.execute('UPDATE spot_applications SET id=%s WHERE id=%s', (temporary, old))
for _, target in imported:
temporary = offset + target
cur.execute('UPDATE spot_applications SET id=%s WHERE id=%s', (target, temporary))
cur.execute('UPDATE spot_confirmations SET application_id=%s WHERE application_id=%s', (target, temporary))
cur.execute('SET FOREIGN_KEY_CHECKS=1')
foreign_keys_disabled = False
conn.commit()
print(json.dumps({'renumbered': len(imported), 'retained_moved': retained_moves,
'backup': str(backup.relative_to(ROOT))}, ensure_ascii=False))
except Exception:
conn.rollback()
raise
finally:
if foreign_keys_disabled:
try:
with conn.cursor() as cur:
cur.execute('SET FOREIGN_KEY_CHECKS=1')
except Exception:
pass
conn.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--local', action='store_true')
run(parser.parse_args().local)