-
Notifications
You must be signed in to change notification settings - Fork 19
added Script to hard - delete organization and related data #778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
nevil-mathew
merged 7 commits into
ELEVATE-Project:develop
from
adithyadinesh0412:org-code-fix
Aug 4, 2025
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
6b551b6
minor fix for QA DB
adithyadinesh0412 19854f6
Merge branch 'develop' of https://github.com/ELEVATE-Project/user int…
adithyadinesh0412 867e222
added Script to hard - delete organization and related data
adithyadinesh0412 7f101d7
added Script to hard - delete organization and related data
adithyadinesh0412 7928702
minod changes
adithyadinesh0412 52b1cfd
minor fixes
adithyadinesh0412 7a3d85d
minor fixes
adithyadinesh0412 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,269 @@ | ||
| const { Sequelize } = require('sequelize') | ||
| let Table = require('cli-table') | ||
| require('dotenv').config({ path: '../../.env' }) | ||
|
|
||
| // Environment setup | ||
| const nodeEnv = process.env.NODE_ENV || 'development' | ||
|
|
||
| let databaseUrl | ||
|
|
||
| switch (nodeEnv) { | ||
| case 'production': | ||
| databaseUrl = process?.env?.PROD_DATABASE_URL || process.env.DEV_DATABASE_URL | ||
| break | ||
| case 'test': | ||
| databaseUrl = process?.env?.TEST_DATABASE_URL || process.env.DEV_DATABASE_URL | ||
| break | ||
| default: | ||
| databaseUrl = process.env.DEV_DATABASE_URL | ||
| } | ||
|
|
||
| // Function to prompt user and get input | ||
| function promptUser(question) { | ||
| return new Promise((resolve) => { | ||
| process.stdout.write(question) | ||
| process.stdin.once('data', (data) => { | ||
| resolve(data.toString().trim()) | ||
| }) | ||
| }) | ||
| } | ||
| // Initialize Sequelize | ||
| const sequelize = new Sequelize(databaseUrl, { | ||
| dialect: 'postgres', | ||
| logging: process.env.NODE_ENV === 'development' ? console.log : false, | ||
| }) | ||
|
|
||
| ;(async () => { | ||
| try { | ||
| const organizationCode = await promptUser( | ||
| '---------> Please enter the organization code to delete (e.g., sot): ' | ||
| ) | ||
adithyadinesh0412 marked this conversation as resolved.
Show resolved
Hide resolved
adithyadinesh0412 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (!organizationCode || organizationCode.trim() === '') { | ||
| console.error('Error: Organization code cannot be empty') | ||
| process.exit(1) | ||
| } | ||
| const tenantCode = await promptUser('---------> Please enter the tenant code to delete (e.g., shikshalokam): ') | ||
| if (!tenantCode || tenantCode.trim() === '') { | ||
| console.error('Error: tenant code cannot be empty') | ||
| process.exit(1) | ||
| } | ||
nevil-mathew marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Test database connection | ||
| await sequelize.authenticate() | ||
| console.log('Database connection established successfully.') | ||
| REPORT_QUERY = `WITH user_org_roles AS ( | ||
| SELECT 'user_organization_roles' AS table_name, | ||
| json_agg(row_to_json(uor)) AS data, | ||
| count(*) AS row_count | ||
| FROM user_organization_roles uor | ||
| WHERE organization_code = '${organizationCode}' AND tenant_code = '${tenantCode}' | ||
| ), | ||
| user_orgs AS ( | ||
| SELECT 'user_organizations' AS table_name, | ||
| json_agg(row_to_json(uo)) AS data, | ||
| count(*) AS row_count | ||
| FROM user_organizations uo | ||
| WHERE organization_code = '${organizationCode}' AND tenant_code = '${tenantCode}' | ||
| ), | ||
| users_to_delete AS ( | ||
| SELECT 'users' AS table_name, | ||
| json_agg(row_to_json(u)) AS data, | ||
| count(*) AS row_count | ||
| FROM users u | ||
| WHERE u.id IN ( | ||
| SELECT user_id | ||
| FROM user_organizations | ||
| WHERE organization_code = '${organizationCode}' AND tenant_code = '${tenantCode}' | ||
| ) | ||
| ), | ||
| orgs AS ( | ||
| SELECT 'organizations' AS table_name, | ||
| json_agg(row_to_json(o)) AS data, | ||
| count(*) AS row_count | ||
| FROM organizations o | ||
| WHERE code = '${organizationCode}' AND tenant_code = '${tenantCode}' | ||
| ), | ||
| invites AS ( | ||
| SELECT 'organization_user_invites' AS table_name, | ||
| json_agg(row_to_json(oui)) AS data, | ||
| count(*) AS row_count | ||
| FROM organization_user_invites oui | ||
| WHERE organization_code = '${organizationCode}' AND tenant_code = '${tenantCode}' | ||
| ), | ||
| notifications AS ( | ||
| SELECT 'notification_templates' AS table_name, | ||
| json_agg(row_to_json(nt)) AS data, | ||
| count(*) AS row_count | ||
| FROM notification_templates nt | ||
| WHERE organization_code = '${organizationCode}' AND tenant_code = '${tenantCode}' | ||
| ), | ||
| features AS ( | ||
| SELECT 'organization_features' AS table_name, | ||
| json_agg(row_to_json(of)) AS data, | ||
| count(*) AS row_count | ||
| FROM organization_features of | ||
| WHERE organization_code = '${organizationCode}' AND tenant_code = '${tenantCode}' | ||
| ), | ||
| reg_codes AS ( | ||
| SELECT 'organization_registration_codes' AS table_name, | ||
| json_agg(row_to_json(orc)) AS data, | ||
| count(*) AS row_count | ||
| FROM organization_registration_codes orc | ||
| WHERE organization_code = '${organizationCode}' AND tenant_code = '${tenantCode}' | ||
| ) | ||
| SELECT table_name, row_count | ||
| FROM user_org_roles | ||
| UNION ALL | ||
| SELECT table_name, row_count | ||
| FROM user_orgs | ||
| UNION ALL | ||
| SELECT table_name, row_count | ||
| FROM users_to_delete | ||
| UNION ALL | ||
| SELECT table_name, row_count | ||
| FROM orgs | ||
| UNION ALL | ||
| SELECT table_name, row_count | ||
| FROM invites | ||
| UNION ALL | ||
| SELECT table_name, row_count | ||
| FROM notifications | ||
| UNION ALL | ||
| SELECT table_name, row_count | ||
| FROM features | ||
| UNION ALL | ||
| SELECT table_name, row_count | ||
| FROM reg_codes;` | ||
| const report = await sequelize.query(REPORT_QUERY, { | ||
| type: Sequelize.QueryTypes.RAW, | ||
| raw: true, | ||
| }) | ||
|
|
||
| let table = new Table({ | ||
| head: ['Table Name', 'Row Count'], | ||
| colWidths: [30, 15], | ||
| }) | ||
| let countChecker = 0 | ||
| // Populate the table with data | ||
| report[0].forEach((item) => { | ||
| countChecker += item.row_count | ||
| table.push([item.table_name, item.row_count]) | ||
| }) | ||
|
|
||
| // Print the table | ||
| console.log('\n\n\nBelow is number of rows attached to the organization code: ', organizationCode) | ||
| console.log(table.toString()) | ||
|
|
||
| const confirmation = | ||
| countChecker > 0 | ||
| ? await promptUser( | ||
| '---------> Are you sure you want to delete all data related to this organization? (yes/no): ' | ||
| ) | ||
| : 'no' | ||
| // Start transaction | ||
| if (confirmation.toLowerCase() == 'yes') { | ||
| await sequelize.transaction(async (t) => { | ||
nevil-mathew marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Delete from user_organization_roles | ||
| const DELETE_USER_ORG_ROLES_QUERY = | ||
| 'DELETE FROM user_organization_roles WHERE organization_code = :organizationCode AND tenant_code = :tenantCode RETURNING *' | ||
| const deletedUserOrgRoles = await sequelize.query(DELETE_USER_ORG_ROLES_QUERY, { | ||
| replacements: { organizationCode, tenantCode }, | ||
| type: Sequelize.QueryTypes.DELETE, | ||
| raw: true, | ||
| transaction: t, | ||
| }) | ||
| console.info('Deleted user_organization_roles: ', deletedUserOrgRoles) | ||
|
|
||
| // Delete from user_organizations and capture user_ids | ||
| const DELETE_USER_ORGS_QUERY = | ||
| 'DELETE FROM user_organizations WHERE organization_code = :organizationCode AND tenant_code = :tenantCode RETURNING user_id' | ||
| const deletedUserOrgs = await sequelize.query(DELETE_USER_ORGS_QUERY, { | ||
| replacements: { organizationCode, tenantCode }, | ||
| type: Sequelize.QueryTypes.DELETE, | ||
| raw: true, | ||
| transaction: t, | ||
| }) | ||
| const userIdsToDelete = deletedUserOrgs.map((row) => row.user_id) | ||
| console.info('Deleted user_organizations, user_ids: ', userIdsToDelete) | ||
|
|
||
| // Delete from users | ||
| if (userIdsToDelete.length > 0) { | ||
| const DELETE_USERS_QUERY = | ||
| 'DELETE FROM users WHERE id IN (:userIdsToDelete) AND NOT EXISTS (SELECT 1 FROM user_organizations WHERE user_organizations.user_id = users.id ) RETURNING *' | ||
| const deletedUsers = await sequelize.query(DELETE_USERS_QUERY, { | ||
| replacements: { userIdsToDelete }, | ||
| type: Sequelize.QueryTypes.DELETE, | ||
| raw: true, | ||
| transaction: t, | ||
| }) | ||
| console.info('Deleted users: ', deletedUsers) | ||
| } | ||
|
|
||
| // Delete from organizations | ||
| const DELETE_ORGS_QUERY = | ||
| 'DELETE FROM organizations WHERE code = :organizationCode AND tenant_code = :tenantCode RETURNING *' | ||
| const deletedOrgs = await sequelize.query(DELETE_ORGS_QUERY, { | ||
| replacements: { organizationCode, tenantCode }, | ||
| type: Sequelize.QueryTypes.DELETE, | ||
| raw: true, | ||
| transaction: t, | ||
| }) | ||
| console.info('Deleted organizations: ', deletedOrgs) | ||
|
|
||
| // Delete from organization_user_invites | ||
| const DELETE_INVITES_QUERY = | ||
| 'DELETE FROM organization_user_invites WHERE organization_code = :organizationCode AND tenant_code = :tenantCode RETURNING *' | ||
| const deletedInvites = await sequelize.query(DELETE_INVITES_QUERY, { | ||
| replacements: { organizationCode, tenantCode }, | ||
| type: Sequelize.QueryTypes.DELETE, | ||
| raw: true, | ||
| transaction: t, | ||
| }) | ||
| console.info('Deleted organization_user_invites: ', deletedInvites) | ||
|
|
||
| // Delete from notification_templates | ||
| const DELETE_NOTIFICATIONS_QUERY = | ||
| 'DELETE FROM notification_templates WHERE organization_code = :organizationCode AND tenant_code = :tenantCode RETURNING *' | ||
| const deletedNotifications = await sequelize.query(DELETE_NOTIFICATIONS_QUERY, { | ||
| replacements: { organizationCode, tenantCode }, | ||
| type: Sequelize.QueryTypes.DELETE, | ||
| raw: true, | ||
| transaction: t, | ||
| }) | ||
| console.info('Deleted notification_templates: ', deletedNotifications) | ||
|
|
||
| // Delete from organization_features | ||
| const DELETE_FEATURES_QUERY = | ||
| 'DELETE FROM organization_features WHERE organization_code = :organizationCode AND tenant_code = :tenantCode RETURNING *' | ||
| const deletedFeatures = await sequelize.query(DELETE_FEATURES_QUERY, { | ||
| replacements: { organizationCode, tenantCode }, | ||
| type: Sequelize.QueryTypes.DELETE, | ||
| raw: true, | ||
| transaction: t, | ||
| }) | ||
| console.info('Deleted organization_features: ', deletedFeatures) | ||
|
|
||
| // Delete from organization_registration_codes | ||
| const DELETE_REG_CODES_QUERY = | ||
| 'DELETE FROM organization_registration_codes WHERE organization_code = :organizationCode AND tenant_code = :tenantCode RETURNING *' | ||
| const deletedRegCodes = await sequelize.query(DELETE_REG_CODES_QUERY, { | ||
| replacements: { organizationCode, tenantCode }, | ||
| type: Sequelize.QueryTypes.DELETE, | ||
| raw: true, | ||
| transaction: t, | ||
| }) | ||
| console.info('Deleted organization_registration_codes: ', deletedRegCodes) | ||
| // await t.commit(); | ||
| }) | ||
|
|
||
| console.log('Transaction completed successfully.') | ||
| } else { | ||
| console.log(`Transaction aborted${countChecker == 0 ? '! No records to delete.' : ' by the user'} `) | ||
| } | ||
| } catch (error) { | ||
| console.error(`Error executing transaction: ${error}`) | ||
| } finally { | ||
| sequelize.close() | ||
| process.exit() | ||
| } | ||
| })() | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.