security(p0): set strong ADMIN_PASSWORD in .env and sync DB admin hash; remove hardcoded 'admin123' in example; update TODO
This commit is contained in:
268
examples/advanced_template_example.py
Normal file
268
examples/advanced_template_example.py
Normal file
@@ -0,0 +1,268 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Advanced Template Features Example
|
||||
|
||||
This script demonstrates how to use the enhanced template system
|
||||
with conditional sections, loops, and rich formatting.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import httpx
|
||||
import json
|
||||
from datetime import date, datetime
|
||||
|
||||
|
||||
class AdvancedTemplateExample:
|
||||
def __init__(self, base_url="http://localhost:8000"):
|
||||
self.base_url = base_url
|
||||
self.auth_token = None
|
||||
|
||||
async def authenticate(self, username="admin", password=None):
|
||||
"""Authenticate and get access token"""
|
||||
async with httpx.AsyncClient() as client:
|
||||
from os import getenv
|
||||
if password is None:
|
||||
password = getenv("ADMIN_PASSWORD", "")
|
||||
response = await client.post(
|
||||
f"{self.base_url}/api/auth/token",
|
||||
data={"username": username, "password": password}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
self.auth_token = response.json()["access_token"]
|
||||
print("✅ Authentication successful")
|
||||
else:
|
||||
print(f"❌ Authentication failed: {response.text}")
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
if not self.auth_token:
|
||||
raise ValueError("Not authenticated")
|
||||
return {"Authorization": f"Bearer {self.auth_token}"}
|
||||
|
||||
async def test_variable_formatting(self):
|
||||
"""Test variable formatting without generating documents"""
|
||||
print("\n📝 Testing Variable Formatting...")
|
||||
|
||||
test_cases = [
|
||||
{"value": "1234.56", "format": "currency", "expected": "$1,234.56"},
|
||||
{"value": "2023-12-25", "format": "date:%B %d, %Y", "expected": "December 25, 2023"},
|
||||
{"value": "5551234567", "format": "phone", "expected": "(555) 123-4567"},
|
||||
{"value": "hello world", "format": "title", "expected": "Hello World"},
|
||||
{"value": "75.5", "format": "percentage:1", "expected": "75.5%"}
|
||||
]
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
for test in test_cases:
|
||||
response = await client.post(
|
||||
f"{self.base_url}/api/templates/test-formatting",
|
||||
headers=self.headers,
|
||||
data={
|
||||
"variable_value": test["value"],
|
||||
"format_spec": test["format"]
|
||||
}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
actual = result["formatted_result"]
|
||||
status = "✅" if actual == test["expected"] else "❌"
|
||||
print(f" {status} {test['value']} | {test['format']} → {actual}")
|
||||
else:
|
||||
print(f" ❌ Error testing {test['format']}: {response.text}")
|
||||
|
||||
async def demonstrate_template_features(self):
|
||||
"""Demonstrate advanced template features with sample data"""
|
||||
print("\n🎯 Demonstrating Advanced Template Features...")
|
||||
|
||||
# Sample context data that would come from database
|
||||
sample_context = {
|
||||
"CLIENT_NAME": "Smith Family Trust",
|
||||
"FILE_NO": "2023-1001",
|
||||
"ATTORNEY": "Jane Doe, Esq.",
|
||||
"TODAY": date.today().isoformat(),
|
||||
"CLIENT_BALANCE": 2500.00,
|
||||
"total_amount": 8750.00,
|
||||
"payment_terms": "Net 30",
|
||||
|
||||
# Sample services for loop demonstration
|
||||
"services": [
|
||||
{
|
||||
"description": "Estate Planning Consultation",
|
||||
"date": "2023-11-15",
|
||||
"hours": 2.5,
|
||||
"rate": 350.00,
|
||||
"amount": 875.00
|
||||
},
|
||||
{
|
||||
"description": "Trust Document Preparation",
|
||||
"date": "2023-11-20",
|
||||
"hours": 6.0,
|
||||
"rate": 350.00,
|
||||
"amount": 2100.00
|
||||
},
|
||||
{
|
||||
"description": "Document Review and Revision",
|
||||
"date": "2023-11-25",
|
||||
"hours": 3.5,
|
||||
"rate": 350.00,
|
||||
"amount": 1225.00
|
||||
},
|
||||
{
|
||||
"description": "Client Meeting and Execution",
|
||||
"date": "2023-11-30",
|
||||
"hours": 2.0,
|
||||
"rate": 350.00,
|
||||
"amount": 700.00
|
||||
}
|
||||
],
|
||||
|
||||
# Sample payments for another loop
|
||||
"payments": [
|
||||
{"date": "2023-11-01", "amount": 1000.00, "method": "Check"},
|
||||
{"date": "2023-11-15", "amount": 1500.00, "method": "Wire Transfer"}
|
||||
]
|
||||
}
|
||||
|
||||
print("Sample context data:")
|
||||
print(json.dumps(sample_context, indent=2, default=str))
|
||||
|
||||
return sample_context
|
||||
|
||||
async def get_formatting_help(self):
|
||||
"""Get and display formatting help"""
|
||||
print("\n📚 Available Formatting Options...")
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(
|
||||
f"{self.base_url}/api/templates/formatting-help",
|
||||
headers=self.headers
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
help_data = response.json()
|
||||
|
||||
print("\n🔧 Formatting Options:")
|
||||
for category, info in help_data["formatting_options"].items():
|
||||
print(f"\n {category.upper()}:")
|
||||
print(f" Description: {info['description']}")
|
||||
if 'syntax' in info:
|
||||
print(f" Syntax: {info['syntax']}")
|
||||
if 'examples' in info:
|
||||
print(" Examples:")
|
||||
for example in info['examples'][:2]: # Show first 2 examples
|
||||
print(f" {example['input']} | {example['format']} → {example['output']}")
|
||||
|
||||
print("\n📝 Template Syntax:")
|
||||
for syntax_type, syntax in help_data["template_syntax"].items():
|
||||
print(f" {syntax_type}: {syntax}")
|
||||
else:
|
||||
print(f"❌ Error getting help: {response.text}")
|
||||
|
||||
async def create_sample_template_content(self):
|
||||
"""Generate sample template content for demonstration"""
|
||||
template_content = """
|
||||
LEGAL SERVICES INVOICE
|
||||
|
||||
Client: {{ CLIENT_NAME | title }}
|
||||
File Number: {{ FILE_NO }}
|
||||
Attorney: {{ ATTORNEY }}
|
||||
Date: {{ TODAY | date }}
|
||||
|
||||
{% if CLIENT_BALANCE > 0 %}
|
||||
⚠️ NOTICE: Outstanding balance of {{ CLIENT_BALANCE | currency }}
|
||||
{% endif %}
|
||||
|
||||
SERVICES PROVIDED:
|
||||
{% for service in services %}
|
||||
{{ service_index }}. {{ service.description }}
|
||||
Date: {{ service.date | date:%m/%d/%Y }}
|
||||
Hours: {{ service.hours | number:1 }}
|
||||
Rate: {{ service.rate | currency }}
|
||||
Amount: {{ service.amount | currency }}
|
||||
{% endfor %}
|
||||
|
||||
SUBTOTAL: {{ format_currency(total_amount) }}
|
||||
|
||||
{% if payments %}
|
||||
PAYMENTS RECEIVED:
|
||||
{% for payment in payments %}
|
||||
- {{ payment.date | date:%m/%d/%Y }}: {{ payment.amount | currency }} ({{ payment.method }})
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if payment_terms %}
|
||||
PAYMENT TERMS: {{ payment_terms }}
|
||||
{% else %}
|
||||
Payment due within 30 days of invoice date.
|
||||
{% endif %}
|
||||
|
||||
{% if CLIENT_BALANCE > 1000 %}
|
||||
Please remit payment immediately to avoid service interruption.
|
||||
{% else %}
|
||||
Thank you for your prompt payment.
|
||||
{% endif %}
|
||||
|
||||
Generated on {{ TODAY | date }} by the Delphi Database System
|
||||
"""
|
||||
|
||||
print("\n📄 Sample Template Content:")
|
||||
print("=" * 60)
|
||||
print(template_content)
|
||||
print("=" * 60)
|
||||
|
||||
return template_content
|
||||
|
||||
async def run_demonstration(self):
|
||||
"""Run the complete demonstration"""
|
||||
print("🚀 Advanced Template Features Demonstration")
|
||||
print("=" * 50)
|
||||
|
||||
# Authenticate
|
||||
if not await self.authenticate():
|
||||
return
|
||||
|
||||
# Show available formatting options
|
||||
await self.get_formatting_help()
|
||||
|
||||
# Test individual formatting functions
|
||||
await self.test_variable_formatting()
|
||||
|
||||
# Show sample template and context
|
||||
context = await self.demonstrate_template_features()
|
||||
template_content = await self.create_sample_template_content()
|
||||
|
||||
print("\n✨ This demonstrates the following advanced features:")
|
||||
print(" • Conditional sections ({% if %} blocks)")
|
||||
print(" • Loop sections ({% for %} blocks)")
|
||||
print(" • Variable formatting ({{ var | format }})")
|
||||
print(" • Template functions ({{ format_currency() }})")
|
||||
print(" • Rich context data with nested objects")
|
||||
|
||||
print("\n🔄 To use these features in your application:")
|
||||
print(" 1. Create a DOCX template with the syntax above")
|
||||
print(" 2. Upload it via /api/templates/upload")
|
||||
print(" 3. Generate documents via /api/templates/{id}/generate-advanced")
|
||||
print(" 4. Optionally convert to PDF by setting output_format: 'PDF'")
|
||||
|
||||
print("\n✅ Advanced template features are ready to use!")
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main demonstration function"""
|
||||
demo = AdvancedTemplateExample()
|
||||
await demo.run_demonstration()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Advanced Template Features Example")
|
||||
print("Make sure the Delphi Database server is running on http://localhost:8000")
|
||||
print()
|
||||
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:
|
||||
print("\n👋 Demonstration interrupted")
|
||||
except Exception as e:
|
||||
print(f"\n❌ Error: {e}")
|
||||
Reference in New Issue
Block a user