| 1 |
|
defmodule DaProductApp.Partners.EmailService do |
| 2 |
|
@moduledoc """ |
| 3 |
|
Service for sending API credential emails to partners. |
| 4 |
|
Uses Swoosh for email delivery with professional templates. |
| 5 |
|
""" |
| 6 |
|
|
| 7 |
|
import Swoosh.Email |
| 8 |
|
alias DaProductApp.Mailer |
| 9 |
|
alias DaProductApp.Partners.Partner |
| 10 |
|
|
| 11 |
|
@from_email "noreply@mercurypay.com" |
| 12 |
|
@support_email "support@mercurypay.com" |
| 13 |
|
|
| 14 |
|
@doc """ |
| 15 |
|
Sends API credentials to partner contact email. |
| 16 |
|
""" |
| 17 |
|
def send_api_credentials(%Partner{} = partner, credentials, admin_user) do |
| 18 |
:-( |
email = |
| 19 |
|
new() |
| 20 |
:-( |
|> to(partner.contact_email) |
| 21 |
|
|> from(@from_email) |
| 22 |
|
|> subject("Your Mercury UPI PSP API Credentials") |
| 23 |
|
|> html_body(credentials_html_template(partner, credentials, admin_user)) |
| 24 |
|
|> text_body(credentials_text_template(partner, credentials, admin_user)) |
| 25 |
|
|
| 26 |
:-( |
case Mailer.deliver(email) do |
| 27 |
:-( |
{:ok, _email} -> |
| 28 |
:-( |
{:ok, "API credentials sent successfully to #{partner.contact_email}"} |
| 29 |
|
|
| 30 |
:-( |
{:error, reason} -> |
| 31 |
|
{:error, "Failed to send email: #{inspect(reason)}"} |
| 32 |
|
end |
| 33 |
|
end |
| 34 |
|
|
| 35 |
|
@doc """ |
| 36 |
|
Sends API key revocation notification. |
| 37 |
|
""" |
| 38 |
|
def send_revocation_notice(%Partner{} = partner, admin_user) do |
| 39 |
:-( |
email = |
| 40 |
|
new() |
| 41 |
:-( |
|> to(partner.contact_email) |
| 42 |
|
|> from(@from_email) |
| 43 |
|
|> subject("Mercury UPI PSP API Access Revoked") |
| 44 |
|
|> html_body(revocation_html_template(partner, admin_user)) |
| 45 |
|
|> text_body(revocation_text_template(partner, admin_user)) |
| 46 |
|
|
| 47 |
:-( |
case Mailer.deliver(email) do |
| 48 |
:-( |
{:ok, _email} -> |
| 49 |
:-( |
{:ok, "Revocation notice sent successfully to #{partner.contact_email}"} |
| 50 |
|
|
| 51 |
:-( |
{:error, reason} -> |
| 52 |
|
{:error, "Failed to send email: #{inspect(reason)}"} |
| 53 |
|
end |
| 54 |
|
end |
| 55 |
|
|
| 56 |
|
@doc """ |
| 57 |
|
Sends API key expiration warning. |
| 58 |
|
""" |
| 59 |
|
def send_expiration_warning(%Partner{} = partner, days_remaining) do |
| 60 |
:-( |
email = |
| 61 |
|
new() |
| 62 |
:-( |
|> to(partner.contact_email) |
| 63 |
|
|> from(@from_email) |
| 64 |
|
|> subject("Mercury UPI PSP API Key Expiring Soon") |
| 65 |
|
|> html_body(expiration_warning_html_template(partner, days_remaining)) |
| 66 |
|
|> text_body(expiration_warning_text_template(partner, days_remaining)) |
| 67 |
|
|
| 68 |
:-( |
case Mailer.deliver(email) do |
| 69 |
:-( |
{:ok, _email} -> |
| 70 |
:-( |
{:ok, "Expiration warning sent successfully to #{partner.contact_email}"} |
| 71 |
|
|
| 72 |
:-( |
{:error, reason} -> |
| 73 |
|
{:error, "Failed to send email: #{inspect(reason)}"} |
| 74 |
|
end |
| 75 |
|
end |
| 76 |
|
|
| 77 |
|
# HTML Templates |
| 78 |
|
|
| 79 |
|
defp credentials_html_template(partner, credentials, admin_user) do |
| 80 |
:-( |
""" |
| 81 |
|
<!DOCTYPE html> |
| 82 |
|
<html> |
| 83 |
|
<head> |
| 84 |
|
<meta charset="utf-8"> |
| 85 |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 86 |
|
<title>API Credentials - Mercury UPI PSP</title> |
| 87 |
|
<style> |
| 88 |
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; } |
| 89 |
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; } |
| 90 |
|
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; border-radius: 8px 8px 0 0; } |
| 91 |
|
.content { background: white; padding: 30px; border: 1px solid #e5e7eb; } |
| 92 |
|
.credentials { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 20px; margin: 20px 0; } |
| 93 |
|
.credential-item { margin: 15px 0; } |
| 94 |
|
.credential-label { font-weight: 600; color: #374151; display: block; margin-bottom: 5px; } |
| 95 |
|
.credential-value { font-family: 'Monaco', 'Consolas', monospace; background: #1f2937; color: #f9fafb; padding: 10px; border-radius: 4px; word-break: break-all; } |
| 96 |
|
.warning { background: #fef3c7; border: 1px solid #f59e0b; border-radius: 6px; padding: 15px; margin: 20px 0; } |
| 97 |
|
.footer { background: #f9fafb; padding: 20px; text-align: center; color: #6b7280; border-radius: 0 0 8px 8px; } |
| 98 |
|
.button { display: inline-block; background: #4f46e5; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; margin: 10px 0; } |
| 99 |
|
</style> |
| 100 |
|
</head> |
| 101 |
|
<body> |
| 102 |
|
<div class="container"> |
| 103 |
|
<div class="header"> |
| 104 |
|
<h1>🔐 API Credentials Generated</h1> |
| 105 |
|
<p>Your Mercury UPI PSP API access credentials</p> |
| 106 |
|
</div> |
| 107 |
|
|
| 108 |
|
<div class="content"> |
| 109 |
:-( |
<p>Hello <strong>#{partner.partner_name}</strong>,</p> |
| 110 |
|
|
| 111 |
:-( |
<p>Your API credentials have been #{if String.contains?(to_string(admin_user), "regenerated"), do: "regenerated", else: "generated"} successfully. Please store these credentials securely and do not share them.</p> |
| 112 |
|
|
| 113 |
|
<div class="credentials"> |
| 114 |
|
<h3>🔑 API Credentials</h3> |
| 115 |
|
|
| 116 |
|
<div class="credential-item"> |
| 117 |
|
<label class="credential-label">API Key:</label> |
| 118 |
:-( |
<code class="credential-value">#{credentials.api_key}</code> |
| 119 |
|
</div> |
| 120 |
|
|
| 121 |
|
<div class="credential-item"> |
| 122 |
|
<label class="credential-label">API Secret:</label> |
| 123 |
:-( |
<code class="credential-value">#{credentials.api_secret}</code> |
| 124 |
|
</div> |
| 125 |
|
|
| 126 |
|
<div class="credential-item"> |
| 127 |
|
<label class="credential-label">Rate Limit:</label> |
| 128 |
:-( |
<code class="credential-value">#{credentials.rate_limit} requests/minute</code> |
| 129 |
|
</div> |
| 130 |
|
|
| 131 |
|
<div class="credential-item"> |
| 132 |
|
<label class="credential-label">Expires At:</label> |
| 133 |
:-( |
<code class="credential-value">#{format_datetime(credentials.expires_at)}</code> |
| 134 |
|
</div> |
| 135 |
|
</div> |
| 136 |
|
|
| 137 |
|
<div class="warning"> |
| 138 |
|
<strong>⚠️ Security Notice:</strong> |
| 139 |
|
<ul> |
| 140 |
|
<li>Store these credentials securely and never share them publicly</li> |
| 141 |
|
<li>Use HTTPS for all API communications</li> |
| 142 |
|
<li>Monitor your API usage regularly</li> |
| 143 |
|
<li>Contact support immediately if you suspect a compromise</li> |
| 144 |
|
</ul> |
| 145 |
|
</div> |
| 146 |
|
|
| 147 |
|
<h3>📚 Getting Started</h3> |
| 148 |
|
<p>Include the following headers in your API requests:</p> |
| 149 |
|
<div class="credentials"> |
| 150 |
|
<code class="credential-value"> |
| 151 |
:-( |
X-API-Key: #{credentials.api_key}<br> |
| 152 |
:-( |
X-API-Secret: #{credentials.api_secret} |
| 153 |
|
</code> |
| 154 |
|
</div> |
| 155 |
|
|
| 156 |
|
<a href="https://docs.mercurypay.com/api" class="button">View API Documentation</a> |
| 157 |
|
</div> |
| 158 |
|
|
| 159 |
|
<div class="footer"> |
| 160 |
:-( |
<p>Generated by: #{admin_user.email} on #{format_datetime(DateTime.utc_now())}</p> |
| 161 |
|
<p>If you have questions, contact us at <a href="mailto:#{@support_email}">#{@support_email}</a></p> |
| 162 |
:-( |
<p>© #{Date.utc_today().year} Mercury Pay - UPI PSP Services</p> |
| 163 |
|
</div> |
| 164 |
|
</div> |
| 165 |
|
</body> |
| 166 |
|
</html> |
| 167 |
|
""" |
| 168 |
|
end |
| 169 |
|
|
| 170 |
|
defp revocation_html_template(partner, admin_user) do |
| 171 |
:-( |
""" |
| 172 |
|
<!DOCTYPE html> |
| 173 |
|
<html> |
| 174 |
|
<head> |
| 175 |
|
<meta charset="utf-8"> |
| 176 |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 177 |
|
<title>API Access Revoked - Mercury UPI PSP</title> |
| 178 |
|
<style> |
| 179 |
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; } |
| 180 |
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; } |
| 181 |
|
.header { background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); color: white; padding: 30px; text-align: center; border-radius: 8px 8px 0 0; } |
| 182 |
|
.content { background: white; padding: 30px; border: 1px solid #e5e7eb; } |
| 183 |
|
.notice { background: #fef2f2; border: 1px solid #fecaca; border-radius: 6px; padding: 15px; margin: 20px 0; } |
| 184 |
|
.footer { background: #f9fafb; padding: 20px; text-align: center; color: #6b7280; border-radius: 0 0 8px 8px; } |
| 185 |
|
</style> |
| 186 |
|
</head> |
| 187 |
|
<body> |
| 188 |
|
<div class="container"> |
| 189 |
|
<div class="header"> |
| 190 |
|
<h1>🚫 API Access Revoked</h1> |
| 191 |
|
<p>Your Mercury UPI PSP API credentials have been revoked</p> |
| 192 |
|
</div> |
| 193 |
|
|
| 194 |
|
<div class="content"> |
| 195 |
:-( |
<p>Hello <strong>#{partner.partner_name}</strong>,</p> |
| 196 |
|
|
| 197 |
|
<div class="notice"> |
| 198 |
|
<p><strong>Notice:</strong> Your API credentials for Mercury UPI PSP have been revoked and are no longer valid for accessing our services.</p> |
| 199 |
|
</div> |
| 200 |
|
|
| 201 |
|
<p><strong>What this means:</strong></p> |
| 202 |
|
<ul> |
| 203 |
|
<li>All API requests using your previous credentials will be rejected</li> |
| 204 |
|
<li>Any integration using these credentials must be updated</li> |
| 205 |
|
<li>Your merchant services may be affected if dependent on API access</li> |
| 206 |
|
</ul> |
| 207 |
|
|
| 208 |
|
<p><strong>Next Steps:</strong></p> |
| 209 |
|
<ul> |
| 210 |
|
<li>Contact our support team if you need new credentials</li> |
| 211 |
|
<li>Review and update any systems using the revoked credentials</li> |
| 212 |
|
<li>Ensure compliance with any updated terms of service</li> |
| 213 |
|
</ul> |
| 214 |
|
|
| 215 |
|
<p>If you believe this was done in error, please contact our support team immediately.</p> |
| 216 |
|
</div> |
| 217 |
|
|
| 218 |
|
<div class="footer"> |
| 219 |
:-( |
<p>Revoked by: #{admin_user.email} on #{format_datetime(DateTime.utc_now())}</p> |
| 220 |
|
<p>Support: <a href="mailto:#{@support_email}">#{@support_email}</a></p> |
| 221 |
:-( |
<p>© #{Date.utc_today().year} Mercury Pay - UPI PSP Services</p> |
| 222 |
|
</div> |
| 223 |
|
</div> |
| 224 |
|
</body> |
| 225 |
|
</html> |
| 226 |
|
""" |
| 227 |
|
end |
| 228 |
|
|
| 229 |
|
defp expiration_warning_html_template(partner, days_remaining) do |
| 230 |
:-( |
""" |
| 231 |
|
<!DOCTYPE html> |
| 232 |
|
<html> |
| 233 |
|
<head> |
| 234 |
|
<meta charset="utf-8"> |
| 235 |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 236 |
|
<title>API Key Expiring Soon - Mercury UPI PSP</title> |
| 237 |
|
<style> |
| 238 |
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; } |
| 239 |
|
.container { max-width: 600px; margin: 0 auto; padding: 20px; } |
| 240 |
|
.header { background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); color: white; padding: 30px; text-align: center; border-radius: 8px 8px 0 0; } |
| 241 |
|
.content { background: white; padding: 30px; border: 1px solid #e5e7eb; } |
| 242 |
|
.warning { background: #fef3c7; border: 1px solid #f59e0b; border-radius: 6px; padding: 15px; margin: 20px 0; } |
| 243 |
|
.footer { background: #f9fafb; padding: 20px; text-align: center; color: #6b7280; border-radius: 0 0 8px 8px; } |
| 244 |
|
.button { display: inline-block; background: #4f46e5; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; margin: 10px 0; } |
| 245 |
|
</style> |
| 246 |
|
</head> |
| 247 |
|
<body> |
| 248 |
|
<div class="container"> |
| 249 |
|
<div class="header"> |
| 250 |
|
<h1>⚠️ API Key Expiring Soon</h1> |
| 251 |
:-( |
<p>Your Mercury UPI PSP API credentials expire in #{days_remaining} days</p> |
| 252 |
|
</div> |
| 253 |
|
|
| 254 |
|
<div class="content"> |
| 255 |
:-( |
<p>Hello <strong>#{partner.partner_name}</strong>,</p> |
| 256 |
|
|
| 257 |
|
<div class="warning"> |
| 258 |
:-( |
<p><strong>Important:</strong> Your API credentials will expire in <strong>#{days_remaining} days</strong>. Please take action to avoid service interruption.</p> |
| 259 |
|
</div> |
| 260 |
|
|
| 261 |
|
<p><strong>What happens when credentials expire:</strong></p> |
| 262 |
|
<ul> |
| 263 |
|
<li>All API requests will be rejected with authentication errors</li> |
| 264 |
|
<li>Your merchant services may be disrupted</li> |
| 265 |
|
<li>Payment processing through our platform will stop</li> |
| 266 |
|
</ul> |
| 267 |
|
|
| 268 |
|
<p><strong>Action Required:</strong></p> |
| 269 |
|
<ul> |
| 270 |
|
<li>Contact our support team to renew your credentials</li> |
| 271 |
|
<li>Update your systems with new credentials when provided</li> |
| 272 |
|
<li>Test your integration after updating credentials</li> |
| 273 |
|
</ul> |
| 274 |
|
|
| 275 |
:-( |
<a href="mailto:#{@support_email}?subject=API%20Key%20Renewal%20Request%20-%20#{partner.partner_name}" class="button">Request Renewal</a> |
| 276 |
|
</div> |
| 277 |
|
|
| 278 |
|
<div class="footer"> |
| 279 |
|
<p>Support: <a href="mailto:#{@support_email}">#{@support_email}</a></p> |
| 280 |
:-( |
<p>© #{Date.utc_today().year} Mercury Pay - UPI PSP Services</p> |
| 281 |
|
</div> |
| 282 |
|
</div> |
| 283 |
|
</body> |
| 284 |
|
</html> |
| 285 |
|
""" |
| 286 |
|
end |
| 287 |
|
|
| 288 |
|
# Text Templates (for email clients that don't support HTML) |
| 289 |
|
|
| 290 |
|
defp credentials_text_template(partner, credentials, admin_user) do |
| 291 |
:-( |
""" |
| 292 |
|
Mercury UPI PSP - API Credentials Generated |
| 293 |
|
|
| 294 |
:-( |
Hello #{partner.partner_name}, |
| 295 |
|
|
| 296 |
|
Your API credentials have been generated successfully. Please store these credentials securely and do not share them. |
| 297 |
|
|
| 298 |
|
API CREDENTIALS: |
| 299 |
|
================ |
| 300 |
:-( |
API Key: #{credentials.api_key} |
| 301 |
:-( |
API Secret: #{credentials.api_secret} |
| 302 |
:-( |
Rate Limit: #{credentials.rate_limit} requests/minute |
| 303 |
:-( |
Expires At: #{format_datetime(credentials.expires_at)} |
| 304 |
|
|
| 305 |
|
SECURITY NOTICE: |
| 306 |
|
================ |
| 307 |
|
- Store these credentials securely and never share them publicly |
| 308 |
|
- Use HTTPS for all API communications |
| 309 |
|
- Monitor your API usage regularly |
| 310 |
|
- Contact support immediately if you suspect a compromise |
| 311 |
|
|
| 312 |
|
GETTING STARTED: |
| 313 |
|
================ |
| 314 |
|
Include the following headers in your API requests: |
| 315 |
:-( |
X-API-Key: #{credentials.api_key} |
| 316 |
:-( |
X-API-Secret: #{credentials.api_secret} |
| 317 |
|
|
| 318 |
|
Documentation: https://docs.mercurypay.com/api |
| 319 |
|
|
| 320 |
:-( |
Generated by: #{admin_user.email} on #{format_datetime(DateTime.utc_now())} |
| 321 |
|
Support: #{@support_email} |
| 322 |
|
|
| 323 |
:-( |
© #{Date.utc_today().year} Mercury Pay - UPI PSP Services |
| 324 |
|
""" |
| 325 |
|
end |
| 326 |
|
|
| 327 |
|
defp revocation_text_template(partner, admin_user) do |
| 328 |
:-( |
""" |
| 329 |
|
Mercury UPI PSP - API Access Revoked |
| 330 |
|
|
| 331 |
:-( |
Hello #{partner.partner_name}, |
| 332 |
|
|
| 333 |
|
NOTICE: Your API credentials for Mercury UPI PSP have been revoked and are no longer valid for accessing our services. |
| 334 |
|
|
| 335 |
|
WHAT THIS MEANS: |
| 336 |
|
================ |
| 337 |
|
- All API requests using your previous credentials will be rejected |
| 338 |
|
- Any integration using these credentials must be updated |
| 339 |
|
- Your merchant services may be affected if dependent on API access |
| 340 |
|
|
| 341 |
|
NEXT STEPS: |
| 342 |
|
=========== |
| 343 |
|
- Contact our support team if you need new credentials |
| 344 |
|
- Review and update any systems using the revoked credentials |
| 345 |
|
- Ensure compliance with any updated terms of service |
| 346 |
|
|
| 347 |
|
If you believe this was done in error, please contact our support team immediately. |
| 348 |
|
|
| 349 |
:-( |
Revoked by: #{admin_user.email} on #{format_datetime(DateTime.utc_now())} |
| 350 |
|
Support: #{@support_email} |
| 351 |
|
|
| 352 |
:-( |
© #{Date.utc_today().year} Mercury Pay - UPI PSP Services |
| 353 |
|
""" |
| 354 |
|
end |
| 355 |
|
|
| 356 |
|
defp expiration_warning_text_template(partner, days_remaining) do |
| 357 |
:-( |
""" |
| 358 |
|
Mercury UPI PSP - API Key Expiring Soon |
| 359 |
|
|
| 360 |
:-( |
Hello #{partner.partner_name}, |
| 361 |
|
|
| 362 |
:-( |
IMPORTANT: Your API credentials will expire in #{days_remaining} days. Please take action to avoid service interruption. |
| 363 |
|
|
| 364 |
|
WHAT HAPPENS WHEN CREDENTIALS EXPIRE: |
| 365 |
|
===================================== |
| 366 |
|
- All API requests will be rejected with authentication errors |
| 367 |
|
- Your merchant services may be disrupted |
| 368 |
|
- Payment processing through our platform will stop |
| 369 |
|
|
| 370 |
|
ACTION REQUIRED: |
| 371 |
|
================ |
| 372 |
|
- Contact our support team to renew your credentials |
| 373 |
|
- Update your systems with new credentials when provided |
| 374 |
|
- Test your integration after updating credentials |
| 375 |
|
|
| 376 |
|
Contact support at: #{@support_email} |
| 377 |
|
|
| 378 |
:-( |
© #{Date.utc_today().year} Mercury Pay - UPI PSP Services |
| 379 |
|
""" |
| 380 |
|
end |
| 381 |
|
|
| 382 |
|
# Helper functions |
| 383 |
|
|
| 384 |
|
defp format_datetime(%DateTime{} = datetime) do |
| 385 |
|
datetime |
| 386 |
|
|> DateTime.truncate(:second) |
| 387 |
:-( |
|> DateTime.to_string() |
| 388 |
|
end |
| 389 |
|
|
| 390 |
:-( |
defp format_datetime(nil), do: "N/A" |
| 391 |
|
end |