index.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /**
  2. * Purge Articles Edge Function
  3. * Version: 2.1
  4. * Last updated: 2026-01-13
  5. * Purpose: Automatically purge old articles and send email reports to admins
  6. * Security: Requires super user authentication or cron secret
  7. */
  8. import { serve } from "https://deno.land/std@0.177.0/http/server.ts";
  9. import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
  10. import { verifySuperUser, validateCronSecret, isInternalCall } from '../_shared/security.ts';
  11. const corsHeaders = {
  12. 'Access-Control-Allow-Origin': '*',
  13. 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type, x-cron-secret',
  14. };
  15. serve(async (req) => {
  16. console.log('🚀 Purge-articles function invoked at', new Date().toISOString());
  17. // Handle CORS preflight requests
  18. if (req.method === 'OPTIONS') {
  19. console.log('📝 CORS preflight request handled');
  20. return new Response(null, { headers: corsHeaders });
  21. }
  22. try {
  23. // Authentication: Allow cron jobs, internal calls, or super users
  24. const isCronJob = validateCronSecret(req);
  25. const isInternal = isInternalCall(req);
  26. const isSuperUser = await verifySuperUser(req);
  27. if (!isCronJob && !isInternal && !isSuperUser) {
  28. console.log('Unauthorized access attempt to purge-articles');
  29. return new Response(
  30. JSON.stringify({
  31. success: false,
  32. error: 'Unauthorized - Super user access or cron secret required'
  33. }),
  34. {
  35. status: 401,
  36. headers: { ...corsHeaders, 'Content-Type': 'application/json' },
  37. }
  38. );
  39. }
  40. console.log('🗑️ Starting automatic article purge...');
  41. // Create Supabase client
  42. const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
  43. const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
  44. const supabase = createClient(supabaseUrl, supabaseServiceKey);
  45. // Call the purge function
  46. const { data, error } = await supabase.rpc('purge_old_articles');
  47. if (error) {
  48. console.error('Error calling purge_old_articles:', error);
  49. throw error;
  50. }
  51. console.log('Purge completed successfully:', data);
  52. const result = data[0];
  53. const deletedCount = result.deleted_count;
  54. const adminEmails = result.admin_emails;
  55. console.log(`Deleted ${deletedCount} articles`);
  56. console.log(`Admin emails count:`, adminEmails?.length || 0);
  57. // Send email report to admins
  58. if (adminEmails && adminEmails.length > 0) {
  59. console.log('Sending purge report to admins...');
  60. const emailResponse = await supabase.functions.invoke('send-purge-report', {
  61. body: {
  62. deletedCount,
  63. adminEmails,
  64. timestamp: new Date().toISOString()
  65. }
  66. });
  67. if (emailResponse.error) {
  68. console.error('Error sending purge report:', emailResponse.error);
  69. } else {
  70. console.log('Purge report sent successfully');
  71. }
  72. }
  73. return new Response(
  74. JSON.stringify({
  75. success: true,
  76. deletedCount,
  77. reportSent: adminEmails && adminEmails.length > 0
  78. }),
  79. {
  80. status: 200,
  81. headers: { ...corsHeaders, 'Content-Type': 'application/json' },
  82. }
  83. );
  84. } catch (error: any) {
  85. console.error('Error in purge-articles function:', error);
  86. return new Response(
  87. JSON.stringify({
  88. success: false,
  89. error: 'An error occurred during the purge operation'
  90. }),
  91. {
  92. status: 500,
  93. headers: { ...corsHeaders, 'Content-Type': 'application/json' },
  94. }
  95. );
  96. }
  97. });