Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 101 lines 3.3 kB view raw
1#!/usr/bin/env node 2// Bulk fix ACLs for recent paintings by listing from S3 3 4import { S3Client, ListObjectsV2Command, PutObjectAclCommand } from '@aws-sdk/client-s3'; 5import { config } from 'dotenv'; 6 7config(); 8 9const DRY_RUN = process.argv.includes('--dry-run'); 10const DAYS = parseInt(process.argv.find(arg => arg.startsWith('--days='))?.split('=')[1]) || 30; 11 12const s3Client = new S3Client({ 13 endpoint: 'https://sfo3.digitaloceanspaces.com', 14 region: 'us-east-1', 15 credentials: { 16 accessKeyId: process.env.DO_SPACES_KEY, 17 secretAccessKey: process.env.DO_SPACES_SECRET 18 } 19}); 20 21console.log('╔═══════════════════════════════════════════════════════════════╗'); 22console.log('║ 🔓 Fix Painting ACLs to Public-Read ║'); 23console.log('╚═══════════════════════════════════════════════════════════════╝\n'); 24 25if (DRY_RUN) { 26 console.log('🔍 DRY RUN MODE - No changes will be made\n'); 27} 28 29const bucket = 'user-aesthetic-computer'; 30const cutoffDate = new Date(); 31cutoffDate.setDate(cutoffDate.getDate() - DAYS); 32 33console.log(`📊 Scanning bucket: ${bucket}`); 34console.log(` Looking for .png files modified after: ${cutoffDate.toISOString()}\n`); 35 36let processed = 0; 37let fixed = 0; 38let skipped = 0; 39let errors = 0; 40 41async function processPrefix(prefix = '') { 42 let continuationToken; 43 44 do { 45 const listCommand = new ListObjectsV2Command({ 46 Bucket: bucket, 47 Prefix: prefix, 48 ContinuationToken: continuationToken, 49 MaxKeys: 1000 50 }); 51 52 const response = await s3Client.send(listCommand); 53 54 if (!response.Contents) break; 55 56 for (const object of response.Contents) { 57 if (!object.Key.endsWith('.png')) continue; 58 if (!object.Key.includes('/painting/')) continue; 59 if (object.LastModified < cutoffDate) continue; 60 61 processed++; 62 const shortKey = object.Key.length > 70 ? object.Key.substring(0, 67) + '...' : object.Key; 63 console.log(`[${processed}] ${shortKey}`); 64 console.log(` Modified: ${object.LastModified.toISOString()}`); 65 66 if (!DRY_RUN) { 67 try { 68 const aclCommand = new PutObjectAclCommand({ 69 Bucket: bucket, 70 Key: object.Key, 71 ACL: 'public-read' 72 }); 73 await s3Client.send(aclCommand); 74 console.log(' ✅ ACL set to public-read'); 75 fixed++; 76 } catch (error) { 77 console.log(` ❌ Error: ${error.message}`); 78 errors++; 79 } 80 } else { 81 console.log(' 🔍 Would set ACL to public-read'); 82 } 83 } 84 85 continuationToken = response.NextContinuationToken; 86 } while (continuationToken); 87} 88 89// Process the bucket 90await processPrefix(); 91 92console.log('\n' + '═'.repeat(65)); 93console.log('📊 Summary:'); 94console.log(` Processed: ${processed}`); 95if (!DRY_RUN) { 96 console.log(` Fixed: ${fixed}`); 97 console.log(` Errors: ${errors}`); 98} else { 99 console.log(` Would fix: ${processed}`); 100} 101console.log('═'.repeat(65) + '\n');