From 321b0085c658e2aa0f0bbd541365a56e6919fbc8 Mon Sep 17 00:00:00 2001 From: HotSwapp <47397945+HotSwapp@users.noreply.github.com> Date: Sun, 17 Aug 2025 22:32:02 -0500 Subject: [PATCH] security(p0): set strong ADMIN_PASSWORD in .env and sync DB admin hash; remove hardcoded 'admin123' in example; update TODO --- TODO.md | 2 +- examples/advanced_template_example.py | 268 ++++++++++++++++++++++++++ 2 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 examples/advanced_template_example.py diff --git a/TODO.md b/TODO.md index 77320bc..8f10ed3 100644 --- a/TODO.md +++ b/TODO.md @@ -9,7 +9,7 @@ ### **Remove Hardcoded Credentials** - [x] **URGENT**: Remove `.env` file from git repository - [x] **URGENT**: Generate new SECRET_KEY (32+ character random string) -- [ ] **URGENT**: Change default admin password from `admin123` to secure password +- [x] **URGENT**: Change default admin password from `admin123` to secure password - [ ] **URGENT**: Implement proper environment variable management - [ ] **URGENT**: Add `.env` to `.gitignore` and commit - [ ] **URGENT**: Document secret rotation procedures diff --git a/examples/advanced_template_example.py b/examples/advanced_template_example.py new file mode 100644 index 0000000..102bbc9 --- /dev/null +++ b/examples/advanced_template_example.py @@ -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}")