Last active
September 26, 2025 02:16
-
-
Save yyyyaaa/c6530527b472f6f73d63c7ea71038e89 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| ================================================================================ | |
| LAUNCHQL ADMIN OWNERSHIP TRANSFER SCRIPT | |
| ================================================================================ | |
| PURPOSE: | |
| Promotes an existing user to admin status and transfers comprehensive ownership | |
| of LaunchQL infrastructure resources to them. Includes transaction safety, | |
| rollback mechanisms, and detailed reporting. | |
| USAGE: | |
| 1. Edit the configuration parameters below (lines ~18-27) | |
| 2. Run the script: psql -f grant-admin-ownership.sql | |
| REQUIRED PARAMETERS TO CONFIGURE: | |
| - target_user_id: UUID of the user to promote (get from lql_public.users) | |
| - admin_username: New username for the admin user | |
| - admin_display_name: Display name for the admin user | |
| - excluded_databases: Databases to exclude from ownership transfer | |
| - admin_patterns: Comma-separated list of usernames considered admin | |
| EXAMPLE CONFIGURATION: | |
| \set target_user_id '12345678-1234-1234-1234-123456789abc' | |
| \set admin_username 'mycompany_admin' | |
| \set admin_display_name 'MyCompany Administrator' | |
| \set excluded_databases ('lql','system') | |
| \set admin_patterns 'admin,superadmin,administrator,root' | |
| WHAT THIS SCRIPT DOES: | |
| ✅ Creates backup table for rollback safety | |
| ✅ Starts transaction for automatic rollback on errors | |
| ✅ Updates user credentials to admin status | |
| ✅ Transfers ownership of ALL LaunchQL resources: | |
| - Databases (except excluded ones) | |
| - User data: addresses, emails, phone numbers, crypto addresses | |
| - Authentication: auth accounts, connected accounts | |
| - Secrets: simple secrets, encrypted secrets | |
| - Infrastructure: sites, domains, APIs (via database ownership) | |
| - App data: levels, permissions, memberships | |
| ✅ Provides detailed transfer counts and reporting | |
| ✅ Commits transaction only if everything succeeds | |
| ✅ Shows comprehensive ownership summary | |
| SAFETY FEATURES: | |
| - Transaction rollback on any error | |
| - Backup table (ownership_backup) for manual recovery | |
| - System database exclusion (prevents breaking core LaunchQL) | |
| - Detailed logging of all operations | |
| - User existence check before proceeding | |
| ROLLBACK INSTRUCTIONS (if needed): | |
| If you need to manually rollback changes, the ownership_backup table | |
| contains the original ownership state. You can restore it with: | |
| SELECT * FROM ownership_backup; -- View original state | |
| -- Then manually update tables using the backup data | |
| PREREQUISITES: | |
| - User must already exist in lql_public.users | |
| - Must have admin privileges to modify ownership | |
| - All referenced schemas/tables must exist | |
| ESTIMATED RUNTIME: | |
| Typically completes in under 30 seconds for most deployments. | |
| ================================================================================ | |
| */ | |
| -- Grant Admin Rights to Specific User | |
| -- Configurable script for making a user an admin with ownership of infrastructure | |
| -- CONFIGURATION PARAMETERS (modify these as needed) | |
| -- User ID to promote to admin (can be obtained from lql_public.users) | |
| \set target_user_id '7586472e-fcbb-47f6-f6f7-41b552c515f6' | |
| -- Admin credentials | |
| \set admin_username 'superadmin' | |
| \set admin_display_name 'LaunchQL Super Administrator' | |
| -- System databases to exclude from ownership transfer | |
| \set excluded_databases ('lql') | |
| -- Admin detection patterns (comma-separated usernames to consider as admin) | |
| \set admin_patterns 'admin,superadmin,administrator' | |
| \echo 'Setting up admin user...' | |
| \echo 'Target User ID: ' :'target_user_id' | |
| \echo 'Admin Username: ' :'admin_username' | |
| -- Create backup table for rollback (automatically dropped at end of session) | |
| CREATE TEMP TABLE ownership_backup AS | |
| SELECT 'database' as resource_type, name::text as resource_name, owner_id as original_owner_id | |
| FROM collections_public.database | |
| WHERE name != 'lql' | |
| UNION ALL | |
| SELECT 'user_secrets', name::text, owner_id | |
| FROM lql_simple_secrets.user_secrets | |
| UNION ALL | |
| SELECT 'addresses', (street_address || ' ' || city)::text, owner_id | |
| FROM lql_public.addresses | |
| UNION ALL | |
| SELECT 'emails', email::text, owner_id | |
| FROM lql_public.emails | |
| UNION ALL | |
| SELECT 'phone_numbers', phone_number::text, owner_id | |
| FROM lql_public.phone_numbers | |
| UNION ALL | |
| SELECT 'crypto_addresses', address::text, owner_id | |
| FROM lql_public.crypto_addresses | |
| UNION ALL | |
| SELECT 'connected_accounts', username::text, owner_id | |
| FROM lql_public.connected_accounts | |
| UNION ALL | |
| SELECT 'auth_accounts', email::text, owner_id | |
| FROM lql_roles_public.auth_accounts | |
| UNION ALL | |
| SELECT 'user_encrypted_secrets', name::text, owner_id | |
| FROM lql_encrypted.user_encrypted_secrets | |
| UNION ALL | |
| SELECT 'app_levels', name::text, owner_id | |
| FROM lql_status_public.app_levels; | |
| \echo 'Created backup of current ownership state for rollback safety' | |
| BEGIN; -- Start transaction for rollback safety | |
| DO $$ | |
| DECLARE | |
| target_user_id uuid := :'target_user_id'::uuid; | |
| admin_username text := :'admin_username'; | |
| admin_display_name text := :'admin_display_name'; | |
| user_exists boolean := false; | |
| transferred_count integer := 0; | |
| BEGIN | |
| -- Check if the user exists | |
| SELECT EXISTS(SELECT 1 FROM lql_public.users WHERE id = target_user_id) INTO user_exists; | |
| IF user_exists THEN | |
| -- Update the user to be admin | |
| UPDATE lql_public.users | |
| SET | |
| username = admin_username, | |
| display_name = admin_display_name | |
| WHERE id = target_user_id; | |
| RAISE NOTICE 'Updated user % to admin: % (%)', target_user_id, admin_username, admin_display_name; | |
| -- Grant ownership of all databases (except system database 'lql') | |
| UPDATE collections_public.database | |
| SET owner_id = target_user_id | |
| WHERE name != 'lql'; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % databases to admin user', transferred_count; | |
| -- Grant ownership of user secrets | |
| UPDATE lql_simple_secrets.user_secrets | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % user secrets to admin user', transferred_count; | |
| -- Grant ownership of user addresses | |
| UPDATE lql_public.addresses | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % addresses to admin user', transferred_count; | |
| -- Grant ownership of user emails | |
| UPDATE lql_public.emails | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % emails to admin user', transferred_count; | |
| -- Grant ownership of user phone numbers | |
| UPDATE lql_public.phone_numbers | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % phone numbers to admin user', transferred_count; | |
| -- Grant ownership of user crypto addresses | |
| UPDATE lql_public.crypto_addresses | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % crypto addresses to admin user', transferred_count; | |
| -- Grant ownership of connected accounts | |
| UPDATE lql_public.connected_accounts | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % connected accounts to admin user', transferred_count; | |
| -- Grant ownership of auth accounts | |
| UPDATE lql_roles_public.auth_accounts | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % auth accounts to admin user', transferred_count; | |
| -- Grant ownership of encrypted secrets | |
| UPDATE lql_encrypted.user_encrypted_secrets | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % encrypted secrets to admin user', transferred_count; | |
| -- Grant ownership of app levels | |
| UPDATE lql_status_public.app_levels | |
| SET owner_id = target_user_id; | |
| GET DIAGNOSTICS transferred_count = ROW_COUNT; | |
| RAISE NOTICE 'Transferred % app levels to admin user', transferred_count; | |
| RAISE NOTICE 'SUCCESS: User % is now a super admin with comprehensive ownership!', target_user_id; | |
| ELSE | |
| RAISE WARNING 'ERROR: User % does not exist! Rolling back transaction...', target_user_id; | |
| ROLLBACK; | |
| RETURN; | |
| END IF; | |
| END $$; | |
| -- Commit the transaction if everything succeeded | |
| COMMIT; | |
| \echo '' | |
| \echo '=== ADMIN USERS SUMMARY ===' | |
| SELECT | |
| id as user_id, | |
| username, | |
| display_name, | |
| type, | |
| CASE | |
| WHEN username = ANY(string_to_array(:'admin_patterns', ',')) THEN '✅ ADMIN' | |
| ELSE '👤 Regular' | |
| END as role_status | |
| FROM lql_public.users | |
| ORDER BY | |
| CASE WHEN username = ANY(string_to_array(:'admin_patterns', ',')) THEN 0 ELSE 1 END, | |
| username; | |
| \echo '' | |
| \echo '=== DATABASE OWNERSHIP ===' | |
| SELECT | |
| d.name as database_name, | |
| d.owner_id, | |
| u.username as owner_username, | |
| u.display_name as owner_display_name | |
| FROM collections_public.database d | |
| LEFT JOIN lql_public.users u ON d.owner_id = u.id | |
| ORDER BY d.name; | |
| \echo '' | |
| \echo '=== COMPREHENSIVE OWNERSHIP REPORT ===' | |
| \echo 'Resources owned by user ID: ' :'target_user_id' | |
| SELECT | |
| 'Databases' as resource_type, | |
| COUNT(*)::text as count | |
| FROM collections_public.database d | |
| WHERE d.owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Sites (via databases)' as resource_type, | |
| COUNT(*)::text as count | |
| FROM meta_public.sites s | |
| JOIN collections_public.database d ON s.database_id = d.id | |
| WHERE d.owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Domains (via databases)' as resource_type, | |
| COUNT(*)::text as count | |
| FROM meta_public.domains dom | |
| JOIN collections_public.database d ON dom.database_id = d.id | |
| WHERE d.owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'APIs (via databases)' as resource_type, | |
| COUNT(*)::text as count | |
| FROM meta_public.apis a | |
| JOIN collections_public.database d ON a.database_id = d.id | |
| WHERE d.owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'User Secrets' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_simple_secrets.user_secrets | |
| WHERE owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Addresses' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_public.addresses | |
| WHERE owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Emails' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_public.emails | |
| WHERE owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Phone Numbers' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_public.phone_numbers | |
| WHERE owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Crypto Addresses' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_public.crypto_addresses | |
| WHERE owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Connected Accounts' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_public.connected_accounts | |
| WHERE owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Auth Accounts' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_roles_public.auth_accounts | |
| WHERE owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'Encrypted Secrets' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_encrypted.user_encrypted_secrets | |
| WHERE owner_id = :'target_user_id'::uuid | |
| UNION ALL | |
| SELECT | |
| 'App Levels' as resource_type, | |
| COUNT(*)::text as count | |
| FROM lql_status_public.app_levels | |
| WHERE owner_id = :'target_user_id'::uuid | |
| ORDER BY resource_type; | |
| \echo '' | |
| \echo '✅ Admin setup complete!' | |
| \echo '' | |
| \echo 'CONFIGURATION USED:' | |
| \echo 'Target User ID: ' :'target_user_id' | |
| \echo 'Admin Username: ' :'admin_username' | |
| \echo 'Display Name: ' :'admin_display_name' | |
| \echo 'Excluded Databases: ' :'excluded_databases' | |
| \echo 'Admin Patterns: ' :'admin_patterns' | |
| \echo '' | |
| \echo 'OWNERSHIP TRANSFERRED:' | |
| \echo '✅ All databases (except system database "lql")' | |
| \echo '✅ All sites, domains, and APIs (via database ownership)' | |
| \echo '✅ All user resources: addresses, emails, phone numbers' | |
| \echo '✅ All authentication accounts and connected accounts' | |
| \echo '✅ All secrets (simple and encrypted)' | |
| \echo '✅ All crypto addresses and app levels' | |
| \echo '' | |
| \echo 'SAFETY FEATURES:' | |
| \echo '✅ Transaction rollback on errors' | |
| \echo '✅ Backup table created for manual rollback' | |
| \echo '✅ Excluded system database from transfer' | |
| \echo '✅ Detailed transfer count reporting' | |
| \echo '' | |
| \echo 'The user is now a comprehensive admin with ownership across the entire LaunchQL infrastructure!' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment