index.ts 6.4 KB

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