feat: export a import kampani a cenoviek pre prenos na novy server
- npm run db:export: kampane a sablony cenoviek do supabase/data/ (+ obrazky z uloziska) - npm run db:import [-- --dry-run]: nahra data s povodnymi ID, prepise odkazy na nove ulozisko, da sa spustit opakovane - aktualny export: 7 kampani, 1 sablona cenovky Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5d1900740c
commit
5f6a39debe
7 files changed
+4832
-4
No files matched your search
@@ -0,0 +1,69 @@
|
||||
// Export kampaní (templates) a šablón cenoviek (badges) zo Supabase do supabase/data/
|
||||
// pre prenos na nový server. Stiahne aj obrázky z úložiska newsletter-assets, na ktoré
|
||||
// dáta odkazujú a nie sú medzi statickými obrázkami v supabase/assets/.
|
||||
// Spustenie: npm run db:export (číta .env.local pôvodného projektu)
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import { mkdir, writeFile, access } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
|
||||
const BUCKET = 'newsletter-assets';
|
||||
const TABLES = ['templates', 'badges'];
|
||||
const DATA_DIR = path.join(process.cwd(), 'supabase', 'data');
|
||||
const FILES_DIR = path.join(DATA_DIR, 'files');
|
||||
const ASSETS_DIR = path.join(process.cwd(), 'supabase', 'assets');
|
||||
|
||||
const url = (process.env.NEXT_PUBLIC_SUPABASE_URL || '').replace(/\/$/, '');
|
||||
const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
||||
if (!url || !key) {
|
||||
console.error('Chýba NEXT_PUBLIC_SUPABASE_URL alebo kľúč (SUPABASE_SERVICE_ROLE_KEY / NEXT_PUBLIC_SUPABASE_ANON_KEY) v .env.local');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const supabase = createClient(url, key);
|
||||
const storageBase = `${url}/storage/v1/object/public/${BUCKET}/`;
|
||||
await mkdir(FILES_DIR, { recursive: true });
|
||||
|
||||
const referenced = new Set();
|
||||
for (const table of TABLES) {
|
||||
const { data, error } = await supabase.from(table).select('*').order('created_at', { ascending: true });
|
||||
if (error) {
|
||||
console.error(`✗ ${table}: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
await writeFile(path.join(DATA_DIR, `${table}.json`), JSON.stringify(data, null, 2) + '\n');
|
||||
console.log(`✓ ${table}: ${data.length} záznamov`);
|
||||
|
||||
// Odkazy na súbory v úložisku (cesta v rámci bucketu)
|
||||
const json = JSON.stringify(data);
|
||||
let i = 0;
|
||||
while ((i = json.indexOf(storageBase, i)) !== -1) {
|
||||
const start = i + storageBase.length;
|
||||
let end = start;
|
||||
while (end < json.length && !`"'()\\ `.includes(json[end])) end++;
|
||||
referenced.add(decodeURIComponent(json.slice(start, end)));
|
||||
i = end;
|
||||
}
|
||||
}
|
||||
|
||||
const exists = (p) => access(p).then(() => true, () => false);
|
||||
let downloaded = 0;
|
||||
for (const filePath of referenced) {
|
||||
// Statické obrázky šablóny sú už v supabase/assets a nahrajú sa cez db:upload-assets
|
||||
if (!filePath.includes('/') && (await exists(path.join(ASSETS_DIR, filePath)))) continue;
|
||||
const res = await fetch(storageBase + filePath.split('/').map(encodeURIComponent).join('/'));
|
||||
if (!res.ok) {
|
||||
console.warn(`! ${filePath}: HTTP ${res.status} (preskočené)`);
|
||||
continue;
|
||||
}
|
||||
const target = path.join(FILES_DIR, filePath);
|
||||
await mkdir(path.dirname(target), { recursive: true });
|
||||
await writeFile(target, Buffer.from(await res.arrayBuffer()));
|
||||
downloaded++;
|
||||
}
|
||||
|
||||
await writeFile(
|
||||
path.join(DATA_DIR, 'meta.json'),
|
||||
JSON.stringify({ exportedAt: new Date().toISOString(), sourceStorageBase: storageBase }, null, 2) + '\n'
|
||||
);
|
||||
console.log(`✓ obrázky: ${referenced.size} odkazov, ${downloaded} stiahnutých do supabase/data/files/`);
|
||||
console.log('\nHotovo. Commitnite priečinok supabase/data/ a na novom serveri spustite npm run db:import.');
|
||||
Reference in new issue
Block a user