173 lines
5.5 KiB
Python
173 lines
5.5 KiB
Python
"""
|
|
migrate_template.py
|
|
-------------------
|
|
End-to-end migration: downloads an Adobe Sign template, converts it to
|
|
DocuSign format, and uploads it to DocuSign.
|
|
|
|
Usage:
|
|
python3 src/migrate_template.py --list
|
|
Show all Adobe Sign templates available to download.
|
|
|
|
python3 src/migrate_template.py --template "Template Name"
|
|
Download, convert, and upload the named template.
|
|
If multiple templates share the same name, the most recently modified
|
|
one is used.
|
|
|
|
python3 src/migrate_template.py --template "Template Name" --skip-upload
|
|
Download and convert only — writes the DocuSign JSON to
|
|
migration-output/ without uploading.
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
sys.path.insert(0, os.path.dirname(__file__))
|
|
|
|
from adobe_api import adobe_api_get, adobe_api_get_bytes
|
|
from compose_docusign_template import compose_template
|
|
from upload_docusign_template import upload_template
|
|
|
|
DOWNLOADS_DIR = Path(__file__).parent.parent / "downloads"
|
|
OUTPUT_DIR = Path(__file__).parent.parent / "migration-output"
|
|
|
|
|
|
def safe_dirname(name):
|
|
return "".join(c if c.isalnum() or c in " -_" else "_" for c in name).strip()
|
|
|
|
|
|
def save_json(path, data):
|
|
import json
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
|
|
def fetch_template_list():
|
|
result = adobe_api_get("libraryDocuments")
|
|
return result.get("libraryDocumentList", [])
|
|
|
|
|
|
def cmd_list():
|
|
print("Fetching template list from Adobe Sign...")
|
|
templates = fetch_template_list()
|
|
if not templates:
|
|
print("No templates found.")
|
|
return
|
|
print(f"\n{'Name':<45} {'Modified':<25} {'ID'}")
|
|
print("-" * 100)
|
|
for t in sorted(templates, key=lambda x: x.get("modifiedDate", ""), reverse=True):
|
|
print(f"{t['name']:<45} {t.get('modifiedDate', 'n/a'):<25} {t['id']}")
|
|
|
|
|
|
def find_template(template_name, templates):
|
|
matches = [t for t in templates if t["name"] == template_name]
|
|
if not matches:
|
|
print(f"ERROR: No template named '{template_name}' found in Adobe Sign.")
|
|
print("Run --list to see available templates.")
|
|
sys.exit(1)
|
|
if len(matches) > 1:
|
|
print(f" {len(matches)} templates named '{template_name}' — using most recently modified.")
|
|
return max(matches, key=lambda t: t.get("modifiedDate", ""))
|
|
|
|
|
|
def download_template(template) -> Path:
|
|
import json
|
|
template_id = template["id"]
|
|
template_name = template["name"]
|
|
dir_name = f"{safe_dirname(template_name)}__{template_id[:8]}"
|
|
out_dir = DOWNLOADS_DIR / dir_name
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
print(f"\nDownloading '{template_name}' → downloads/{dir_name}/")
|
|
|
|
metadata = adobe_api_get(f"libraryDocuments/{template_id}")
|
|
save_json(out_dir / "metadata.json", metadata)
|
|
|
|
try:
|
|
form_fields = adobe_api_get(f"libraryDocuments/{template_id}/formFields")
|
|
save_json(out_dir / "form_fields.json", form_fields)
|
|
field_count = len(form_fields.get("fields", []))
|
|
print(f" {field_count} form fields")
|
|
except Exception as e:
|
|
print(f" WARNING: Could not fetch form fields: {e}")
|
|
save_json(out_dir / "form_fields.json", {"error": str(e)})
|
|
|
|
docs = adobe_api_get(f"libraryDocuments/{template_id}/documents")
|
|
save_json(out_dir / "documents.json", docs)
|
|
|
|
for doc in docs.get("documents", []):
|
|
doc_id = doc["id"]
|
|
doc_name = doc.get("name", doc_id)
|
|
if not doc_name.lower().endswith(".pdf"):
|
|
doc_name += ".pdf"
|
|
safe_name = safe_dirname(doc_name)
|
|
try:
|
|
pdf_bytes = adobe_api_get_bytes(
|
|
f"libraryDocuments/{template_id}/documents/{doc_id}"
|
|
)
|
|
with open(out_dir / safe_name, "wb") as f:
|
|
f.write(pdf_bytes)
|
|
print(f" PDF ({len(pdf_bytes) // 1024}KB) → {safe_name}")
|
|
except Exception as e:
|
|
print(f" WARNING: Could not download PDF: {e}")
|
|
|
|
return out_dir
|
|
|
|
|
|
def convert_template(template_dir: Path) -> Path:
|
|
output_path = OUTPUT_DIR / template_dir.name / "docusign-template.json"
|
|
print(f"\nConverting to DocuSign format...")
|
|
_, warnings, _ = compose_template(str(template_dir), str(output_path))
|
|
print(f" Written: {output_path}")
|
|
for w in warnings:
|
|
print(f" WARNING: {w}")
|
|
return output_path
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Migrate an Adobe Sign template to DocuSign",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog=__doc__,
|
|
)
|
|
group = parser.add_mutually_exclusive_group(required=True)
|
|
group.add_argument(
|
|
"--template", metavar="NAME",
|
|
help="Name of the Adobe Sign template to migrate"
|
|
)
|
|
group.add_argument(
|
|
"--list", action="store_true",
|
|
help="List available Adobe Sign templates"
|
|
)
|
|
parser.add_argument(
|
|
"--skip-upload", action="store_true",
|
|
help="Convert only — do not upload to DocuSign"
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
DOWNLOADS_DIR.mkdir(exist_ok=True)
|
|
OUTPUT_DIR.mkdir(exist_ok=True)
|
|
|
|
if args.list:
|
|
cmd_list()
|
|
return
|
|
|
|
templates = fetch_template_list()
|
|
template = find_template(args.template, templates)
|
|
template_dir = download_template(template)
|
|
output_path = convert_template(template_dir)
|
|
|
|
if args.skip_upload:
|
|
print(f"\nSkipped upload. DocuSign JSON: {output_path}")
|
|
else:
|
|
print()
|
|
upload_template(str(output_path))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|