index.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /**
  2. * Send Purge Report Edge Function
  3. * Version: 2.0
  4. * Last updated: 2025-01-20
  5. * Purpose: Send email reports about article purge operations to admin users
  6. */
  7. import { serve } from "https://deno.land/std@0.177.0/http/server.ts";
  8. import { Resend } from "npm:resend@2.0.0";
  9. const resend = new Resend(Deno.env.get("RESEND_API_KEY"));
  10. const corsHeaders = {
  11. "Access-Control-Allow-Origin": "*",
  12. "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
  13. };
  14. interface PurgeReportRequest {
  15. deletedCount: number;
  16. adminEmails: string[];
  17. timestamp: string;
  18. }
  19. const handler = async (req: Request): Promise<Response> => {
  20. console.log('📧 Send-purge-report function invoked at', new Date().toISOString());
  21. // Handle CORS preflight requests
  22. if (req.method === "OPTIONS") {
  23. console.log('📝 CORS preflight request handled');
  24. return new Response(null, { headers: corsHeaders });
  25. }
  26. try {
  27. const { deletedCount, adminEmails, timestamp }: PurgeReportRequest = await req.json();
  28. console.log('📨 Preparing to send purge report email...');
  29. console.log(`📊 Report details: ${deletedCount} articles deleted, ${adminEmails?.length || 0} admins to notify`);
  30. console.log('📧 Admin emails:', adminEmails);
  31. const emailDate = new Date(timestamp);
  32. const formattedDate = emailDate.toLocaleDateString('fr-FR', {
  33. weekday: 'long',
  34. year: 'numeric',
  35. month: 'long',
  36. day: 'numeric',
  37. hour: '2-digit',
  38. minute: '2-digit'
  39. });
  40. const emailHtml = `
  41. <!DOCTYPE html>
  42. <html>
  43. <head>
  44. <meta charset="utf-8">
  45. <style>
  46. body {
  47. font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
  48. line-height: 1.6;
  49. color: #333;
  50. max-width: 600px;
  51. margin: 0 auto;
  52. padding: 20px;
  53. }
  54. .header {
  55. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  56. color: white;
  57. padding: 30px;
  58. border-radius: 10px 10px 0 0;
  59. text-align: center;
  60. }
  61. .header h1 {
  62. margin: 0;
  63. font-size: 24px;
  64. }
  65. .content {
  66. background: #f9fafb;
  67. padding: 30px;
  68. border-radius: 0 0 10px 10px;
  69. }
  70. .stat-box {
  71. background: white;
  72. border-left: 4px solid #667eea;
  73. padding: 20px;
  74. margin: 20px 0;
  75. border-radius: 5px;
  76. box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  77. }
  78. .stat-number {
  79. font-size: 36px;
  80. font-weight: bold;
  81. color: #667eea;
  82. margin: 10px 0;
  83. }
  84. .stat-label {
  85. color: #666;
  86. font-size: 14px;
  87. text-transform: uppercase;
  88. letter-spacing: 1px;
  89. }
  90. .criteria {
  91. background: white;
  92. padding: 20px;
  93. border-radius: 5px;
  94. margin: 20px 0;
  95. }
  96. .criteria h3 {
  97. margin-top: 0;
  98. color: #667eea;
  99. }
  100. .criteria ul {
  101. margin: 10px 0;
  102. padding-left: 20px;
  103. }
  104. .criteria li {
  105. margin: 8px 0;
  106. }
  107. .footer {
  108. text-align: center;
  109. margin-top: 30px;
  110. padding-top: 20px;
  111. border-top: 1px solid #e5e7eb;
  112. color: #666;
  113. font-size: 12px;
  114. }
  115. .success-badge {
  116. display: inline-block;
  117. background: #10b981;
  118. color: white;
  119. padding: 5px 15px;
  120. border-radius: 20px;
  121. font-size: 12px;
  122. font-weight: bold;
  123. margin-top: 10px;
  124. }
  125. </style>
  126. </head>
  127. <body>
  128. <div class="header">
  129. <h1>🗑️ Rapport de Purge Automatique</h1>
  130. <div class="success-badge">✓ EXÉCUTION RÉUSSIE</div>
  131. </div>
  132. <div class="content">
  133. <p>Bonjour,</p>
  134. <p>La purge automatique des articles a été exécutée avec succès.</p>
  135. <div class="stat-box">
  136. <div class="stat-label">Articles supprimés</div>
  137. <div class="stat-number">${deletedCount}</div>
  138. </div>
  139. <div class="stat-box">
  140. <div class="stat-label">Date d'exécution</div>
  141. <div style="font-size: 18px; margin-top: 10px;">${formattedDate}</div>
  142. </div>
  143. <div class="criteria">
  144. <h3>📋 Critères de purge appliqués</h3>
  145. <ul>
  146. <li><strong>Âge des articles :</strong> Plus de 48 heures (2 jours)</li>
  147. <li><strong>Articles préservés :</strong>
  148. <ul>
  149. <li>Articles épinglés par au moins un utilisateur</li>
  150. <li>Articles avec plus de 20 lectures</li>
  151. </ul>
  152. </li>
  153. <li><strong>Fréquence :</strong> Tous les jours à 3h00 du matin</li>
  154. </ul>
  155. </div>
  156. ${deletedCount === 0 ? `
  157. <div style="background: #fef3c7; border-left: 4px solid #f59e0b; padding: 15px; border-radius: 5px; margin: 20px 0;">
  158. <strong>ℹ️ Information :</strong> Aucun article ne correspondait aux critères de purge.
  159. </div>
  160. ` : ''}
  161. <div class="footer">
  162. <p>Ce rapport est généré automatiquement par le système de purge.</p>
  163. <p>Pour toute question, veuillez consulter les logs de la base de données.</p>
  164. </div>
  165. </div>
  166. </body>
  167. </html>
  168. `;
  169. const emailResponse = await resend.emails.send({
  170. from: "News Aggregator <onboarding@resend.dev>",
  171. to: adminEmails,
  172. subject: `📊 Rapport de purge automatique - ${deletedCount} article${deletedCount > 1 ? 's' : ''} supprimé${deletedCount > 1 ? 's' : ''}`,
  173. html: emailHtml,
  174. });
  175. console.log("Purge report email sent successfully:", emailResponse);
  176. return new Response(JSON.stringify({ success: true, emailResponse }), {
  177. status: 200,
  178. headers: {
  179. "Content-Type": "application/json",
  180. ...corsHeaders,
  181. },
  182. });
  183. } catch (error: any) {
  184. console.error("Error in send-purge-report function:", error);
  185. return new Response(
  186. JSON.stringify({ error: error?.message || 'Unknown error' }),
  187. {
  188. status: 500,
  189. headers: { "Content-Type": "application/json", ...corsHeaders },
  190. }
  191. );
  192. }
  193. };
  194. serve(handler);