fix: resolve latent bugs found in code review
- Fix ValueError crash in migrate_template.py and migrate_paul_template.py: compose_template() returns a 3-tuple since Phase 23 but both CLI scripts were still unpacking 2 values - Fix ImportError in bulk-send/bulk_send.py: replace non-existent auth_helper import with docusign_auth.get_access_token via sys.path - Activate log sanitizer at web app startup so tokens never appear in logs - Log a warning at startup when SESSION_SECRET_KEY is the default dev value - Add reportlab to requirements.txt (used by generate_pdfs.py, was missing) - Move asyncio import from bottom of templates.py to top where it belongs - Correct stale coordinate comment in generate_pdfs.py (both platforms use top-left origin; the comment incorrectly described bottom-left inversion) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
210f273c05
commit
c5b7b9f5b8
|
|
@ -13,12 +13,15 @@ DocuSign API reference:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import csv
|
import csv
|
||||||
import json
|
import json
|
||||||
import argparse
|
import argparse
|
||||||
import requests
|
import requests
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from auth_helper import get_access_token # reuses existing JWT auth
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
||||||
|
from docusign_auth import get_access_token
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ uvicorn[standard]
|
||||||
itsdangerous
|
itsdangerous
|
||||||
httpx
|
httpx
|
||||||
|
|
||||||
|
# PDF generation (sample template tooling)
|
||||||
|
reportlab
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
responses
|
responses
|
||||||
respx
|
respx
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ Generates realistic sample PDFs for adobe-to-docusign migration testing.
|
||||||
Each PDF mirrors the form fields described in the matching *-formfields.json
|
Each PDF mirrors the form fields described in the matching *-formfields.json
|
||||||
so that tab positions map to visible labels on the document.
|
so that tab positions map to visible labels on the document.
|
||||||
|
|
||||||
Adobe rect coordinates are top-left origin; DocuSign yPosition is bottom-left.
|
Both Adobe Sign and DocuSign use top-left origin with y increasing downward — no
|
||||||
Formula: docusign_y = PAGE_HEIGHT - adobe_top - adobe_height
|
coordinate inversion is needed. DocuSign xPosition = adobe left, yPosition = adobe top.
|
||||||
To place a *label* just above a field: label_y = PAGE_HEIGHT - adobe_top + 2
|
To place a *label* just above a field in this PDF: label_y = page_height - adobe_top + 2
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ def run_migration(template_dir: Path) -> Path:
|
||||||
|
|
||||||
output_path = MIGRATION_OUTPUT_DIR / template_dir.name / "docusign-template.json"
|
output_path = MIGRATION_OUTPUT_DIR / template_dir.name / "docusign-template.json"
|
||||||
print(f"\nRunning migration: {template_dir.name}")
|
print(f"\nRunning migration: {template_dir.name}")
|
||||||
template_dict, warnings = compose_template(str(template_dir), str(output_path))
|
template_dict, warnings, field_issues = compose_template(str(template_dir), str(output_path))
|
||||||
|
|
||||||
print(f" Written: {output_path}")
|
print(f" Written: {output_path}")
|
||||||
if warnings:
|
if warnings:
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ def download_template(template) -> Path:
|
||||||
def convert_template(template_dir: Path) -> Path:
|
def convert_template(template_dir: Path) -> Path:
|
||||||
output_path = OUTPUT_DIR / template_dir.name / "docusign-template.json"
|
output_path = OUTPUT_DIR / template_dir.name / "docusign-template.json"
|
||||||
print(f"\nConverting to DocuSign format...")
|
print(f"\nConverting to DocuSign format...")
|
||||||
_, warnings = compose_template(str(template_dir), str(output_path))
|
_, warnings, _ = compose_template(str(template_dir), str(output_path))
|
||||||
print(f" Written: {output_path}")
|
print(f" Written: {output_path}")
|
||||||
for w in warnings:
|
for w in warnings:
|
||||||
print(f" WARNING: {w}")
|
print(f" WARNING: {w}")
|
||||||
|
|
|
||||||
15
web/app.py
15
web/app.py
|
|
@ -12,11 +12,26 @@ From the project root.
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.responses import FileResponse, HTMLResponse
|
from fastapi.responses import FileResponse, HTMLResponse
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from web.config import settings
|
from web.config import settings
|
||||||
from web.routers import auth, templates, migrate, verify, audit, admin
|
from web.routers import auth, templates, migrate, verify, audit, admin
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||||
|
from src.utils.log_sanitizer import install_sanitizing_filter
|
||||||
|
|
||||||
|
install_sanitizing_filter()
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_DEFAULT_SECRET = "dev-secret-change-in-production"
|
||||||
|
if settings.session_secret_key == _DEFAULT_SECRET:
|
||||||
|
logger.warning(
|
||||||
|
"SESSION_SECRET_KEY is using the default dev value — set a random secret in .env before exposing this app"
|
||||||
|
)
|
||||||
|
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="Adobe Sign → DocuSign Migrator",
|
title="Adobe Sign → DocuSign Migrator",
|
||||||
version=settings.version,
|
version=settings.version,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ Template listing endpoints for Adobe Sign and DocuSign.
|
||||||
Computes per-template migration status for the side-by-side UI.
|
Computes per-template migration status for the side-by-side UI.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
@ -243,7 +244,3 @@ def _dedupe(items: list[str]) -> list[str]:
|
||||||
seen.add(item)
|
seen.add(item)
|
||||||
result.append(item)
|
result.append(item)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
# asyncio needed for gather — import at top of module
|
|
||||||
import asyncio
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue