Skip to content

Commit aed767a

Browse files
committed
feat: add account restoration script for deleted accounts
Introduced a new script to restore accounts marked for deletion in the Supabase database. The script fetches accounts from the 'to_delete_accounts' table, restores associated API keys, and removes the account from the deletion list. It includes error handling for missing environment variables and potential database errors during the restoration process.
1 parent c29c521 commit aed767a

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

scripts/restore_account.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/// <reference lib="deno.ns" />
2+
import type { Database } from '../supabase/functions/_backend/utils/supabase.types.ts'
3+
import { createClient } from 'https://esm.sh/@supabase/supabase-js'
4+
import { load } from 'https://deno.land/std@0.224.0/dotenv/mod.ts'
5+
6+
const accountId = 'THE ACCOUNT ID TO RESTORE'
7+
8+
// Load environment variables from .env.prod
9+
// Running the script: deno run --allow-read --allow-net --allow-env restore_account.ts
10+
const envPath = new URL('../internal/cloudflare/.env.prod', import.meta.url).pathname
11+
const env = await load({ envPath })
12+
13+
const supabaseUrl = env.SUPABASE_URL
14+
const supabaseServiceRoleKey = env.SUPABASE_SERVICE_ROLE_KEY
15+
16+
if (!supabaseUrl || !supabaseServiceRoleKey) {
17+
console.error('Missing SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY in .env.prod')
18+
Deno.exit(1)
19+
}
20+
21+
interface ApiKey {
22+
id: number
23+
created_at: string
24+
user_id: string
25+
key: string
26+
mode: 'all' | 'upload' | 'read' | 'write'
27+
updated_at: string
28+
name: string
29+
limited_to_orgs: string[]
30+
limited_to_apps: string[]
31+
expires_at: string | null
32+
key_hash: string | null
33+
}
34+
35+
interface RemovedData {
36+
email: string
37+
apikeys: ApiKey[] | null
38+
}
39+
40+
interface ToDeleteAccount {
41+
id: number
42+
account_id: string
43+
removal_date: string
44+
removed_data: RemovedData
45+
created_at: string
46+
}
47+
48+
async function main() {
49+
const supabase = createClient<Database>(supabaseUrl, supabaseServiceRoleKey, {
50+
auth: {
51+
autoRefreshToken: false,
52+
persistSession: false,
53+
detectSessionInUrl: false,
54+
},
55+
})
56+
57+
// Get all accounts pending deletion
58+
const { data: accountsToRestore, error: fetchError } = await supabase
59+
.from('to_delete_accounts')
60+
.select('*')
61+
.eq('account_id', accountId)
62+
63+
if (fetchError) {
64+
console.error('Error fetching accounts to restore:', fetchError)
65+
Deno.exit(1)
66+
}
67+
68+
if (!accountsToRestore || accountsToRestore.length === 0) {
69+
console.log('No accounts found in to_delete_accounts table')
70+
Deno.exit(0)
71+
}
72+
73+
if (accountsToRestore.length > 1) {
74+
console.error('More than one account found in to_delete_accounts table')
75+
Deno.exit(1)
76+
}
77+
78+
console.log(`Found ${accountsToRestore.length} account(s) to restore`)
79+
80+
for (const account of accountsToRestore as unknown as ToDeleteAccount[]) {
81+
console.log(`\nProcessing account: ${account.account_id}`)
82+
console.log(` Email: ${account.removed_data?.email || 'unknown'}`)
83+
84+
const apikeys = account.removed_data?.apikeys
85+
86+
if (!apikeys || apikeys.length === 0) {
87+
console.log(' No API keys to restore for this account')
88+
}
89+
else {
90+
console.log(` Found ${apikeys.length} API key(s) to restore`)
91+
92+
for (const apikey of apikeys) {
93+
// Check if this apikey already exists (by key value)
94+
const { data: existingKey } = await supabase
95+
.from('apikeys')
96+
.select('id')
97+
.eq('key', apikey.key)
98+
.single()
99+
100+
if (existingKey) {
101+
console.log(` Skipping API key "${apikey.name}" - already exists`)
102+
continue
103+
}
104+
105+
// Insert the API key back
106+
const { error: insertError } = await supabase
107+
.from('apikeys')
108+
.insert({
109+
user_id: apikey.user_id,
110+
key: apikey.key,
111+
mode: apikey.mode,
112+
name: apikey.name,
113+
limited_to_orgs: apikey.limited_to_orgs || [],
114+
limited_to_apps: apikey.limited_to_apps || [],
115+
expires_at: apikey.expires_at,
116+
})
117+
118+
if (insertError) {
119+
console.error(` Error restoring API key "${apikey.name}":`, insertError)
120+
}
121+
else {
122+
console.log(` Restored API key: "${apikey.name}"`)
123+
}
124+
}
125+
}
126+
127+
// Remove the account from to_delete_accounts
128+
const { error: deleteError } = await supabase
129+
.from('to_delete_accounts')
130+
.delete()
131+
.eq('id', account.id)
132+
133+
if (deleteError) {
134+
console.error(` Error removing account from to_delete_accounts:`, deleteError)
135+
}
136+
else {
137+
console.log(` Removed account ${account.account_id} from to_delete_accounts`)
138+
}
139+
}
140+
141+
console.log('\nRestore complete!')
142+
}
143+
144+
await main()

0 commit comments

Comments
 (0)