File size: 8,817 Bytes
09801ca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
"""
Signup Confirmation Email Service
Uses Resend API to send branded DataVision confirmation emails
"""

import os
import httpx
import secrets
from typing import Optional
from datetime import datetime, timedelta
import logging
import json
from pathlib import Path

logger = logging.getLogger(__name__)

# Email configuration
RESEND_API_KEY = os.getenv("RESEND_API_KEY")
FROM_EMAIL = os.getenv("FROM_EMAIL", "insights@ai20insights.tech")
APP_URL = os.getenv("APP_URL", "https://killerkumar-ai-business-analyst.hf.space")

# Storage for pending confirmations
CONFIRMATIONS_DIR = Path(__file__).parent.parent / "storage" / "pending_confirmations"
CONFIRMATIONS_DIR.mkdir(parents=True, exist_ok=True)


async def send_confirmation_email(email: str, user_id: str) -> dict:
    """Send DataVision branded confirmation email using Resend API"""
    
    if not RESEND_API_KEY:
        error_msg = "RESEND_API_KEY not configured"
        logger.error(error_msg)
        return {"success": False, "error": error_msg}
    
    # Generate confirmation token
    token = secrets.token_urlsafe(32)
    
    # Store pending confirmation
    confirmation_data = {
        "user_id": user_id,
        "email": email,
        "token": token,
        "created_at": datetime.utcnow().isoformat(),
        "expires_at": (datetime.utcnow() + timedelta(hours=24)).isoformat()
    }
    
    token_file = CONFIRMATIONS_DIR / f"{token}.json"
    with open(token_file, 'w') as f:
        json.dump(confirmation_data, f)
    
    # Build confirmation URL - points to frontend which calls API
    confirmation_url = f"{APP_URL}/auth/confirm?token={token}"
    
    # HTML email template
    html_content = f'''
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Confirm Your DataVision Account</title>
    </head>
    <body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f3f4f6;">
        <table width="100%" cellpadding="0" cellspacing="0" style="background-color: #f3f4f6; padding: 40px 20px;">
            <tr>
                <td align="center">
                    <table width="600" cellpadding="0" cellspacing="0" style="background-color: #ffffff; border-radius: 16px; overflow: hidden; box-shadow: 0 10px 25px rgba(0,0,0,0.08);">
                        <!-- Header -->
                        <tr>
                            <td style="background: linear-gradient(135deg, #0F172A 0%, #1E293B 100%); padding: 40px 30px; text-align: center;">
                                <h1 style="margin: 0; color: #ffffff; font-size: 28px; font-weight: 700;">
                                    DataVision
                                </h1>
                                <p style="margin: 8px 0 0 0; color: #14B8A6; font-size: 14px; font-weight: 600;">
                                    Autonomous Data Intelligence Platform
                                </p>
                            </td>
                        </tr>
                        
                        <!-- Content -->
                        <tr>
                            <td style="padding: 40px 30px;">
                                <h2 style="margin: 0 0 16px 0; color: #0f172a; font-size: 22px; font-weight: 700;">
                                    Welcome to DataVision! πŸ‘‹
                                </h2>
                                
                                <p style="margin: 0 0 24px 0; color: #475569; line-height: 1.7; font-size: 15px;">
                                    Thank you for signing up. Click the button below to confirm your email address and get started with autonomous data intelligence.
                                </p>
                                
                                <!-- Button -->
                                <table cellpadding="0" cellspacing="0" style="margin: 25px 0;">
                                    <tr>
                                        <td style="border-radius: 8px; background: linear-gradient(135deg, #14B8A6 0%, #0D9488 100%);">
                                            <a href="{confirmation_url}" 
                                               style="display: inline-block; padding: 14px 32px; color: #ffffff; text-decoration: none; font-weight: 600; font-size: 15px;">
                                                Confirm Your Email β†’
                                            </a>
                                        </td>
                                    </tr>
                                </table>
                                
                                <p style="margin: 24px 0 0 0; color: #64748b; font-size: 13px; line-height: 1.6;">
                                    This link will expire in 24 hours. If you didn't create an account with DataVision, you can safely ignore this email.
                                </p>
                                
                                <div style="height: 1px; background: linear-gradient(to right, transparent, #e2e8f0, transparent); margin: 30px 0;"></div>
                                
                                <p style="margin: 0; color: #94a3b8; font-size: 12px;">
                                    If the button doesn't work, copy and paste this URL into your browser:<br>
                                    <a href="{confirmation_url}" style="color: #14B8A6; word-break: break-all;">{confirmation_url}</a>
                                </p>
                            </td>
                        </tr>
                        
                        <!-- Footer -->
                        <tr>
                            <td style="padding: 30px; background: #f8fafc; border-top: 1px solid #e2e8f0; text-align: center;">
                                <p style="margin: 0; color: #64748b; font-size: 13px;">
                                    Β© 2024 DataVision β€” Autonomous Data Intelligence Platform
                                </p>
                            </td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
    </body>
    </html>
    '''
    
    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            payload = {
                "from": f"DataVision <{FROM_EMAIL}>",
                "to": [email],
                "subject": "Confirm Your DataVision Account",
                "html": html_content,
                "text": f"Welcome to DataVision!\n\nClick this link to confirm your email: {confirmation_url}\n\nThis link expires in 24 hours.",
            }
            
            response = await client.post(
                "https://api.resend.com/emails",
                headers={
                    "Authorization": f"Bearer {RESEND_API_KEY}",
                    "Content-Type": "application/json"
                },
                json=payload
            )
            
            logger.info(f"πŸ“§ Confirmation email response: {response.status_code}")
            
            if response.status_code != 200:
                error_detail = response.text
                logger.error(f"πŸ“§ Resend API error: {error_detail}")
                return {"success": False, "error": error_detail}
            
            result = response.json()
            logger.info(f"βœ… Confirmation email sent to {email}! ID: {result.get('id', 'unknown')}")
            return {"success": True, "email_id": result.get('id')}
            
    except Exception as e:
        logger.error(f"❌ Failed to send confirmation email: {str(e)}")
        return {"success": False, "error": str(e)}


async def verify_confirmation_token(token: str) -> dict:
    """Verify a confirmation token and return user info"""
    
    token_file = CONFIRMATIONS_DIR / f"{token}.json"
    
    if not token_file.exists():
        return {"success": False, "error": "Invalid or expired token"}
    
    try:
        with open(token_file, 'r') as f:
            data = json.load(f)
        
        # Check expiration
        expires_at = datetime.fromisoformat(data["expires_at"])
        if datetime.utcnow() > expires_at:
            token_file.unlink()  # Delete expired token
            return {"success": False, "error": "Token has expired"}
        
        # Token is valid - delete it (one-time use)
        token_file.unlink()
        
        return {
            "success": True,
            "user_id": data["user_id"],
            "email": data["email"]
        }
        
    except Exception as e:
        logger.error(f"Error verifying token: {e}")
        return {"success": False, "error": str(e)}