From 17d7c7063500a9106f1cf94adc3de1b667c33d12 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Mon, 28 Jul 2025 13:53:11 +0530 Subject: [PATCH 1/8] fix organization code --- src/scripts/correct-org-code/fix-org-code.js | 220 +++++++++++++++++++ src/validators/v1/organization.js | 7 +- 2 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 src/scripts/correct-org-code/fix-org-code.js diff --git a/src/scripts/correct-org-code/fix-org-code.js b/src/scripts/correct-org-code/fix-org-code.js new file mode 100644 index 00000000..7b4a8a64 --- /dev/null +++ b/src/scripts/correct-org-code/fix-org-code.js @@ -0,0 +1,220 @@ +const { Sequelize } = require('sequelize') +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 +} + +console.info('Database selected: ', databaseUrl.split('/').at(-1)) + +// Initialize Sequelize +const sequelize = new Sequelize(databaseUrl, { + dialect: 'postgres', + logging: process.env.NODE_ENV === 'development' ? console.log : false, +}) + +;(async () => { + let transaction + try { + // Start a transaction + transaction = await sequelize.transaction() + + const DISABLE_FK_QUERY = 'SET CONSTRAINTS ALL DEFERRED' // temporarily remove constraint checks till the transaction is completed + + const ORG_UPDATE_QUERY = `UPDATE organizations SET code = REGEXP_REPLACE(code, '\s+', '', 'g') WHERE code ~ '\s+';` + const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\s+';` + + // Test database connection + await sequelize.authenticate() + console.log('Database connection established successfully.') + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + // Execute the query with replacements + const updateOrgs = await sequelize.query(ORG_UPDATE_QUERY, { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + // Execute the query with replacements + const fetchOrgs = await sequelize.query(ORG_FETCH_QUERY, { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + console.log(fetchOrgs) + if (transaction) await transaction.rollback() + /* + const orgsToRemove = fetchOrgs + .filter((orgs) => orgs.code !== process.env.DEFAULT_ORGANISATION_CODE) + .map((orgs) => orgs.id) + const orgsCodesToRemove = fetchOrgs + .map((orgs) => orgs.code) + .filter((code) => code !== process.env.DEFAULT_ORGANISATION_CODE) + console.info('Organizations to remove: ', fetchOrgs) + + // Fetch system admin and org admin roles + const allowedRoles = ['admin', 'org_admin'] + const ROLES_FETCH_QUERY = + 'SELECT id FROM user_roles WHERE tenant_code IN (:allowedTenants) AND title IN (:allowedRoles)' + const fetchRoles = await sequelize.query(ROLES_FETCH_QUERY, { + replacements: { allowedTenants: allowed_tenants, allowedRoles }, + type: Sequelize.QueryTypes.SELECT, + raw: true, + transaction + }) + + const systemRoles = fetchRoles.map((role) => role.id) + console.log('System Role ids: ', systemRoles) + + const FETCH_USERID_QUERY = 'SELECT user_id FROM user_organization_roles WHERE role_id IN (:systemRoles)' + const fetchUserIds = await sequelize.query(FETCH_USERID_QUERY, { + replacements: { orgsCodesToRemove, systemRoles, allowedTenants: allowed_tenants }, + type: Sequelize.QueryTypes.SELECT, + raw: true, + transaction + }) + + const adminRoles = fetchUserIds.map((user) => user.user_id) + + const REFETCH_USERID_QUERY = + 'SELECT user_id FROM user_organization_roles WHERE user_id NOT IN (:adminRoles) OR organization_code IN (:orgsCodesToRemove)' + const reFetchUserIds = await sequelize.query(REFETCH_USERID_QUERY, { + replacements: { adminRoles, orgsCodesToRemove }, + type: Sequelize.QueryTypes.SELECT, + raw: true, + transaction + }) + + const userIdsToDelete = reFetchUserIds.map((user) => user.user_id) + console.log('User ids to delete: ', userIdsToDelete) + + // Delete user org roles + const DELETE_USER_ORG_ROLES_QUERY = 'DELETE FROM user_organization_roles WHERE user_id IN (:userIdsToDelete)' + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + const deleteOrgUserRoles = await sequelize.query(DELETE_USER_ORG_ROLES_QUERY, { + replacements: { userIdsToDelete }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Delete user organizations + const DELETE_USER_ORGS_QUERY = 'DELETE FROM user_organizations WHERE user_id IN (:userIdsToDelete)' + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + const deleteOrgUsers = await sequelize.query(DELETE_USER_ORGS_QUERY, { + replacements: { userIdsToDelete }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Delete users + const DELETE_USERS_QUERY = 'DELETE FROM users WHERE id IN (:userIdsToDelete)' + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + const deleteUsers = await sequelize.query(DELETE_USERS_QUERY, { + replacements: { userIdsToDelete }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Truncate uploads + const TRUNCATE_UPLOADS_QUERY = 'TRUNCATE TABLE file_uploads RESTART IDENTITY' + const truncateUploads = await sequelize.query(TRUNCATE_UPLOADS_QUERY, { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction + }) + + // Truncate invites + const TRUNCATE_INVITES_QUERY = 'TRUNCATE TABLE organization_user_invites RESTART IDENTITY' + const truncateInvites = await sequelize.query(TRUNCATE_INVITES_QUERY, { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction + }) + + // Delete organization features + const DELETE_ORG_FEATURES_QUERY = + 'DELETE FROM organization_features WHERE organization_code IN (:orgsCodesToRemove)' + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + const deleteOrganizationFeatures = await sequelize.query(DELETE_ORG_FEATURES_QUERY, { + replacements: { orgsCodesToRemove }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Delete organization domains + const DELETE_ORG_DOMAINS_QUERY = + 'DELETE FROM organization_email_domains WHERE organization_id IN (:orgsToRemove)' + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + const deleteOrganizationDomains = await sequelize.query(DELETE_ORG_DOMAINS_QUERY, { + replacements: { orgsToRemove }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Delete organization role requests + const DELETE_ORG_ROLE_REQUEST_QUERY = + 'DELETE FROM organization_role_requests WHERE organization_id IN (:orgsToRemove)' + const deleteOrganizatioRoleRequest = await sequelize.query(DELETE_ORG_ROLE_REQUEST_QUERY, { + replacements: { orgsToRemove }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Delete organizations + const DELETE_ORGS_QUERY = 'DELETE FROM organizations WHERE id IN (:orgsToRemove)' + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + const deleteOrganizations = await sequelize.query(DELETE_ORGS_QUERY, { + replacements: { orgsToRemove }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Delete tenant domains + const DELETE_TENANT_DOMAINS_QUERY = 'DELETE FROM tenant_domains WHERE tenant_code NOT IN (:allowed_tenants)' + const deleteTenantDomains = await sequelize.query(DELETE_TENANT_DOMAINS_QUERY, { + replacements: { allowed_tenants }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Delete tenants + const DELETE_TENANTS_QUERY = 'DELETE FROM tenants WHERE code NOT IN (:allowed_tenants)' + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + const deleteTenants = await sequelize.query(DELETE_TENANTS_QUERY, { + replacements: { allowed_tenants }, + type: Sequelize.QueryTypes.DELETE, + raw: true, + transaction + }) + + // Commit the transaction + await transaction.commit(); */ + console.log('Transaction committed successfully.') + } catch (error) { + // Rollback transaction on error + if (transaction) await transaction.rollback() + console.error(`Error during transaction: ${error}`) + } finally { + sequelize.close() + } +})() diff --git a/src/validators/v1/organization.js b/src/validators/v1/organization.js index fe4beece..fd80a170 100644 --- a/src/validators/v1/organization.js +++ b/src/validators/v1/organization.js @@ -12,7 +12,12 @@ const common = require('@constants/common') module.exports = { create: (req) => { req.body = filterRequestBody(req.body, organization.create) - req.checkBody('code').trim().notEmpty().withMessage('code field is empty') + req.checkBody('code') + .trim() + .notEmpty() + .withMessage('code field is empty') + .matches(/^[a-z0-9]+$/) + .withMessage('code is invalid. Only lowercase alphanumeric characters allowed') req.checkBody('tenant_code').trim().notEmpty().withMessage('tenant_code field is empty') req.checkBody('registration_codes') .optional({ checkFalsy: true }) From 42126ecf6ca22007672780ba36fafe4dbdbf974c Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Mon, 28 Jul 2025 18:51:19 +0530 Subject: [PATCH 2/8] final --- src/scripts/correct-org-code/fix-org-code.js | 272 ++++++++----------- 1 file changed, 114 insertions(+), 158 deletions(-) diff --git a/src/scripts/correct-org-code/fix-org-code.js b/src/scripts/correct-org-code/fix-org-code.js index 7b4a8a64..49730462 100644 --- a/src/scripts/correct-org-code/fix-org-code.js +++ b/src/scripts/correct-org-code/fix-org-code.js @@ -4,6 +4,8 @@ require('dotenv').config({ path: '../../.env' }) // Environment setup const nodeEnv = process.env.NODE_ENV || 'development' +let fk_retainer = [] +let table, fk_name, fkey, refTable, refKey let databaseUrl switch (nodeEnv) { @@ -33,182 +35,136 @@ const sequelize = new Sequelize(databaseUrl, { const DISABLE_FK_QUERY = 'SET CONSTRAINTS ALL DEFERRED' // temporarily remove constraint checks till the transaction is completed - const ORG_UPDATE_QUERY = `UPDATE organizations SET code = REGEXP_REPLACE(code, '\s+', '', 'g') WHERE code ~ '\s+';` const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\s+';` + const disableFK = (table, fk_name) => `ALTER TABLE ${table} DROP CONSTRAINT IF EXISTS ${fk_name};` + const enableFK = (table, fk_name, fkey, refTable, refKey) => + `ALTER TABLE ${table} ADD CONSTRAINT ${fk_name} FOREIGN KEY ${fkey} REFERENCES ${refTable} ${refKey} ON UPDATE NO ACTION ON DELETE CASCADE;` + const updateQuery = (table, key) => + `UPDATE ${table} SET ${key} = REGEXP_REPLACE(${key}, '\\s+', '', 'g') WHERE ${key} ~ '\\s+';` + // Execute the query with replacements + const fetchOrg = await sequelize.query(ORG_FETCH_QUERY, { + type: Sequelize.QueryTypes.SELECT, + raw: true, + transaction, + }) + + console.log(fetchOrg) // Test database connection await sequelize.authenticate() console.log('Database connection established successfully.') + + table = 'organization_registration_codes' + fk_name = 'fk_organization_code_tenant_code_in_org_reg_code' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + + table = 'user_organizations' + fk_name = 'fk_user_organizations_organizations' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'organization_user_invites' + fk_name = 'fk_org_user_invites_org_code' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'organization_user_invites' + fk_name = 'fk_org_user_invites_organization_id' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'user_organization_roles' + fk_name = 'fk_user_org_roles_user_organizations' + fkey = '(user_id, organization_code, tenant_code)' + refTable = 'user_organizations' + refKey = '(user_id, organization_code, tenant_code)' + await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + let updateTable = 'organizations' + let key = 'code' // Execute the query with replacements - const updateOrgs = await sequelize.query(ORG_UPDATE_QUERY, { + const updateOrgs = await sequelize.query(updateQuery(updateTable, key), { type: Sequelize.QueryTypes.UPDATE, raw: true, transaction, }) + console.log('------------>>', updateOrgs) + updateTable = 'organization_registration_codes' + key = 'organization_code' // Execute the query with replacements - const fetchOrgs = await sequelize.query(ORG_FETCH_QUERY, { + await sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'organization_user_invites' + key = 'organization_code' + // Execute the query with replacements + await sequelize.query(updateQuery(updateTable, key), { type: Sequelize.QueryTypes.UPDATE, raw: true, transaction, }) + updateTable = 'user_organizations' + key = 'organization_code' + // Execute the query with replacements + await sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + updateTable = 'user_organization_roles' + key = 'organization_code' + // Execute the query with replacements + await sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + // Execute the query with replacements + const fetchOrgs = await sequelize.query(ORG_FETCH_QUERY, { + type: Sequelize.QueryTypes.SELECT, + raw: true, + transaction, + }) + console.log(fetchOrgs) - if (transaction) await transaction.rollback() - /* - const orgsToRemove = fetchOrgs - .filter((orgs) => orgs.code !== process.env.DEFAULT_ORGANISATION_CODE) - .map((orgs) => orgs.id) - const orgsCodesToRemove = fetchOrgs - .map((orgs) => orgs.code) - .filter((code) => code !== process.env.DEFAULT_ORGANISATION_CODE) - console.info('Organizations to remove: ', fetchOrgs) - - // Fetch system admin and org admin roles - const allowedRoles = ['admin', 'org_admin'] - const ROLES_FETCH_QUERY = - 'SELECT id FROM user_roles WHERE tenant_code IN (:allowedTenants) AND title IN (:allowedRoles)' - const fetchRoles = await sequelize.query(ROLES_FETCH_QUERY, { - replacements: { allowedTenants: allowed_tenants, allowedRoles }, - type: Sequelize.QueryTypes.SELECT, - raw: true, - transaction - }) - - const systemRoles = fetchRoles.map((role) => role.id) - console.log('System Role ids: ', systemRoles) - - const FETCH_USERID_QUERY = 'SELECT user_id FROM user_organization_roles WHERE role_id IN (:systemRoles)' - const fetchUserIds = await sequelize.query(FETCH_USERID_QUERY, { - replacements: { orgsCodesToRemove, systemRoles, allowedTenants: allowed_tenants }, - type: Sequelize.QueryTypes.SELECT, - raw: true, - transaction - }) - - const adminRoles = fetchUserIds.map((user) => user.user_id) - - const REFETCH_USERID_QUERY = - 'SELECT user_id FROM user_organization_roles WHERE user_id NOT IN (:adminRoles) OR organization_code IN (:orgsCodesToRemove)' - const reFetchUserIds = await sequelize.query(REFETCH_USERID_QUERY, { - replacements: { adminRoles, orgsCodesToRemove }, - type: Sequelize.QueryTypes.SELECT, - raw: true, - transaction - }) - - const userIdsToDelete = reFetchUserIds.map((user) => user.user_id) - console.log('User ids to delete: ', userIdsToDelete) - - // Delete user org roles - const DELETE_USER_ORG_ROLES_QUERY = 'DELETE FROM user_organization_roles WHERE user_id IN (:userIdsToDelete)' - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - const deleteOrgUserRoles = await sequelize.query(DELETE_USER_ORG_ROLES_QUERY, { - replacements: { userIdsToDelete }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Delete user organizations - const DELETE_USER_ORGS_QUERY = 'DELETE FROM user_organizations WHERE user_id IN (:userIdsToDelete)' - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - const deleteOrgUsers = await sequelize.query(DELETE_USER_ORGS_QUERY, { - replacements: { userIdsToDelete }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Delete users - const DELETE_USERS_QUERY = 'DELETE FROM users WHERE id IN (:userIdsToDelete)' - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - const deleteUsers = await sequelize.query(DELETE_USERS_QUERY, { - replacements: { userIdsToDelete }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Truncate uploads - const TRUNCATE_UPLOADS_QUERY = 'TRUNCATE TABLE file_uploads RESTART IDENTITY' - const truncateUploads = await sequelize.query(TRUNCATE_UPLOADS_QUERY, { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction - }) - - // Truncate invites - const TRUNCATE_INVITES_QUERY = 'TRUNCATE TABLE organization_user_invites RESTART IDENTITY' - const truncateInvites = await sequelize.query(TRUNCATE_INVITES_QUERY, { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction - }) - - // Delete organization features - const DELETE_ORG_FEATURES_QUERY = - 'DELETE FROM organization_features WHERE organization_code IN (:orgsCodesToRemove)' - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - const deleteOrganizationFeatures = await sequelize.query(DELETE_ORG_FEATURES_QUERY, { - replacements: { orgsCodesToRemove }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Delete organization domains - const DELETE_ORG_DOMAINS_QUERY = - 'DELETE FROM organization_email_domains WHERE organization_id IN (:orgsToRemove)' - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - const deleteOrganizationDomains = await sequelize.query(DELETE_ORG_DOMAINS_QUERY, { - replacements: { orgsToRemove }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Delete organization role requests - const DELETE_ORG_ROLE_REQUEST_QUERY = - 'DELETE FROM organization_role_requests WHERE organization_id IN (:orgsToRemove)' - const deleteOrganizatioRoleRequest = await sequelize.query(DELETE_ORG_ROLE_REQUEST_QUERY, { - replacements: { orgsToRemove }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Delete organizations - const DELETE_ORGS_QUERY = 'DELETE FROM organizations WHERE id IN (:orgsToRemove)' - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - const deleteOrganizations = await sequelize.query(DELETE_ORGS_QUERY, { - replacements: { orgsToRemove }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Delete tenant domains - const DELETE_TENANT_DOMAINS_QUERY = 'DELETE FROM tenant_domains WHERE tenant_code NOT IN (:allowed_tenants)' - const deleteTenantDomains = await sequelize.query(DELETE_TENANT_DOMAINS_QUERY, { - replacements: { allowed_tenants }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Delete tenants - const DELETE_TENANTS_QUERY = 'DELETE FROM tenants WHERE code NOT IN (:allowed_tenants)' - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - const deleteTenants = await sequelize.query(DELETE_TENANTS_QUERY, { - replacements: { allowed_tenants }, - type: Sequelize.QueryTypes.DELETE, - raw: true, - transaction - }) - - // Commit the transaction - await transaction.commit(); */ + let fk_retainerPromise = [] + for (let i = 0; i < fk_retainer.length; i++) { + fk_retainerPromise.push( + sequelize.query(fk_retainer[i], { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + ) + } + + await Promise.all(fk_retainerPromise) + + if (transaction) await transaction.commit() + console.log('Transaction committed successfully.') } catch (error) { // Rollback transaction on error From d7d1fd592118b20e370b30fbf4a143f6e008781f Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 29 Jul 2025 12:34:02 +0530 Subject: [PATCH 3/8] Converted file to migration --- .../migrations/20250729064710-org-code-fix.js | 168 +++++++++++++++++ src/scripts/correct-org-code/fix-org-code.js | 176 ------------------ 2 files changed, 168 insertions(+), 176 deletions(-) create mode 100644 src/database/migrations/20250729064710-org-code-fix.js delete mode 100644 src/scripts/correct-org-code/fix-org-code.js diff --git a/src/database/migrations/20250729064710-org-code-fix.js b/src/database/migrations/20250729064710-org-code-fix.js new file mode 100644 index 00000000..6b6217f2 --- /dev/null +++ b/src/database/migrations/20250729064710-org-code-fix.js @@ -0,0 +1,168 @@ +const { Sequelize } = require('sequelize') + +module.exports = { + async up(queryInterface, Sequelize) { + let transaction + let fk_retainer = [] + let table, fk_name, fkey, refTable, refKey + + try { + // Start a transaction + transaction = await queryInterface.sequelize.transaction() + + const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\s+';` + const disableFK = (table, fk_name) => `ALTER TABLE ${table} DROP CONSTRAINT IF EXISTS ${fk_name};` + const enableFK = (table, fk_name, fkey, refTable, refKey) => + `ALTER TABLE ${table} ADD CONSTRAINT ${fk_name} FOREIGN KEY ${fkey} REFERENCES ${refTable} ${refKey} ON UPDATE NO ACTION ON DELETE CASCADE;` + const updateQuery = (table, key) => + `UPDATE ${table} SET ${key} = REGEXP_REPLACE(${key}, '\\s+', '', 'g') WHERE ${key} ~ '\\s+';` + + // Execute the query to fetch organizations with whitespace + const fetchOrg = await queryInterface.sequelize.query(ORG_FETCH_QUERY, { + type: Sequelize.QueryTypes.SELECT, + raw: true, + transaction, + }) + console.log(fetchOrg) + + // Disable foreign key constraints and store enable queries + table = 'organization_registration_codes' + fk_name = 'fk_organization_code_tenant_code_in_org_reg_code' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + + table = 'user_organizations' + fk_name = 'fk_user_organizations_organizations' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'organization_user_invites' + fk_name = 'fk_org_user_invites_org_code' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'organization_user_invites' + fk_name = 'fk_org_user_invites_organization_id' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'user_organization_roles' + fk_name = 'fk_user_org_roles_user_organizations' + fkey = '(user_id, organization_code, tenant_code)' + refTable = 'user_organizations' + refKey = '(user_id, organization_code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + // Update tables to remove whitespace + let updateTable = 'organizations' + let key = 'code' + const updateOrgs = await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'organization_registration_codes' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'organization_user_invites' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'user_organizations' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'user_organization_roles' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + // Verify the update + const fetchOrgs = await queryInterface.sequelize.query(ORG_FETCH_QUERY, { + type: Sequelize.QueryTypes.SELECT, + raw: true, + transaction, + }) + console.log(fetchOrgs) + + // Re-enable foreign key constraints + let fk_retainerPromise = [] + for (let i = 0; i < fk_retainer.length; i++) { + fk_retainerPromise.push( + queryInterface.sequelize.query(fk_retainer[i], { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + ) + } + + await Promise.all(fk_retainerPromise) + + // Commit the transaction + await transaction.commit() + console.log('Transaction committed successfully.') + } catch (error) { + // Rollback transaction on error + if (transaction) await transaction.rollback() + console.error(`Error during transaction: ${error}`) + throw error + } + }, + + async down(queryInterface, Sequelize) { + console.warn( + 'Down migration not implemented: Cannot reliably restore original whitespace in organization codes.' + ) + }, +} diff --git a/src/scripts/correct-org-code/fix-org-code.js b/src/scripts/correct-org-code/fix-org-code.js deleted file mode 100644 index 49730462..00000000 --- a/src/scripts/correct-org-code/fix-org-code.js +++ /dev/null @@ -1,176 +0,0 @@ -const { Sequelize } = require('sequelize') -require('dotenv').config({ path: '../../.env' }) - -// Environment setup -const nodeEnv = process.env.NODE_ENV || 'development' - -let fk_retainer = [] -let table, fk_name, fkey, refTable, refKey -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 -} - -console.info('Database selected: ', databaseUrl.split('/').at(-1)) - -// Initialize Sequelize -const sequelize = new Sequelize(databaseUrl, { - dialect: 'postgres', - logging: process.env.NODE_ENV === 'development' ? console.log : false, -}) - -;(async () => { - let transaction - try { - // Start a transaction - transaction = await sequelize.transaction() - - const DISABLE_FK_QUERY = 'SET CONSTRAINTS ALL DEFERRED' // temporarily remove constraint checks till the transaction is completed - - const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\s+';` - const disableFK = (table, fk_name) => `ALTER TABLE ${table} DROP CONSTRAINT IF EXISTS ${fk_name};` - const enableFK = (table, fk_name, fkey, refTable, refKey) => - `ALTER TABLE ${table} ADD CONSTRAINT ${fk_name} FOREIGN KEY ${fkey} REFERENCES ${refTable} ${refKey} ON UPDATE NO ACTION ON DELETE CASCADE;` - const updateQuery = (table, key) => - `UPDATE ${table} SET ${key} = REGEXP_REPLACE(${key}, '\\s+', '', 'g') WHERE ${key} ~ '\\s+';` - - // Execute the query with replacements - const fetchOrg = await sequelize.query(ORG_FETCH_QUERY, { - type: Sequelize.QueryTypes.SELECT, - raw: true, - transaction, - }) - - console.log(fetchOrg) - // Test database connection - await sequelize.authenticate() - console.log('Database connection established successfully.') - - table = 'organization_registration_codes' - fk_name = 'fk_organization_code_tenant_code_in_org_reg_code' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - - table = 'user_organizations' - fk_name = 'fk_user_organizations_organizations' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - - table = 'organization_user_invites' - fk_name = 'fk_org_user_invites_org_code' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - - table = 'organization_user_invites' - fk_name = 'fk_org_user_invites_organization_id' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - - table = 'user_organization_roles' - fk_name = 'fk_user_org_roles_user_organizations' - fkey = '(user_id, organization_code, tenant_code)' - refTable = 'user_organizations' - refKey = '(user_id, organization_code, tenant_code)' - await sequelize.query(disableFK(table, fk_name), { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - await sequelize.query(DISABLE_FK_QUERY, { type: Sequelize.QueryTypes.RAW, raw: true, transaction }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - - let updateTable = 'organizations' - let key = 'code' - // Execute the query with replacements - const updateOrgs = await sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - console.log('------------>>', updateOrgs) - updateTable = 'organization_registration_codes' - key = 'organization_code' - // Execute the query with replacements - await sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - - updateTable = 'organization_user_invites' - key = 'organization_code' - // Execute the query with replacements - await sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - - updateTable = 'user_organizations' - key = 'organization_code' - // Execute the query with replacements - await sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - updateTable = 'user_organization_roles' - key = 'organization_code' - // Execute the query with replacements - await sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - - // Execute the query with replacements - const fetchOrgs = await sequelize.query(ORG_FETCH_QUERY, { - type: Sequelize.QueryTypes.SELECT, - raw: true, - transaction, - }) - - console.log(fetchOrgs) - let fk_retainerPromise = [] - for (let i = 0; i < fk_retainer.length; i++) { - fk_retainerPromise.push( - sequelize.query(fk_retainer[i], { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - ) - } - - await Promise.all(fk_retainerPromise) - - if (transaction) await transaction.commit() - - console.log('Transaction committed successfully.') - } catch (error) { - // Rollback transaction on error - if (transaction) await transaction.rollback() - console.error(`Error during transaction: ${error}`) - } finally { - sequelize.close() - } -})() From 2b3a44d43584871377ace754d04ebf28cd6dc32d Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 29 Jul 2025 12:42:04 +0530 Subject: [PATCH 4/8] minor fixes --- .../migrations/20250729064710-org-code-fix.js | 257 +++++++++--------- 1 file changed, 129 insertions(+), 128 deletions(-) diff --git a/src/database/migrations/20250729064710-org-code-fix.js b/src/database/migrations/20250729064710-org-code-fix.js index 6b6217f2..72a5a390 100644 --- a/src/database/migrations/20250729064710-org-code-fix.js +++ b/src/database/migrations/20250729064710-org-code-fix.js @@ -10,7 +10,7 @@ module.exports = { // Start a transaction transaction = await queryInterface.sequelize.transaction() - const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\s+';` + const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\\s+';` const disableFK = (table, fk_name) => `ALTER TABLE ${table} DROP CONSTRAINT IF EXISTS ${fk_name};` const enableFK = (table, fk_name, fkey, refTable, refKey) => `ALTER TABLE ${table} ADD CONSTRAINT ${fk_name} FOREIGN KEY ${fkey} REFERENCES ${refTable} ${refKey} ON UPDATE NO ACTION ON DELETE CASCADE;` @@ -23,135 +23,136 @@ module.exports = { raw: true, transaction, }) - console.log(fetchOrg) - - // Disable foreign key constraints and store enable queries - table = 'organization_registration_codes' - fk_name = 'fk_organization_code_tenant_code_in_org_reg_code' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - await queryInterface.sequelize.query(disableFK(table, fk_name), { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction, - }) - - table = 'user_organizations' - fk_name = 'fk_user_organizations_organizations' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - await queryInterface.sequelize.query(disableFK(table, fk_name), { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction, - }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - - table = 'organization_user_invites' - fk_name = 'fk_org_user_invites_org_code' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - await queryInterface.sequelize.query(disableFK(table, fk_name), { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction, - }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - - table = 'organization_user_invites' - fk_name = 'fk_org_user_invites_organization_id' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - await queryInterface.sequelize.query(disableFK(table, fk_name), { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction, - }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - - table = 'user_organization_roles' - fk_name = 'fk_user_org_roles_user_organizations' - fkey = '(user_id, organization_code, tenant_code)' - refTable = 'user_organizations' - refKey = '(user_id, organization_code, tenant_code)' - await queryInterface.sequelize.query(disableFK(table, fk_name), { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction, - }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - - // Update tables to remove whitespace - let updateTable = 'organizations' - let key = 'code' - const updateOrgs = await queryInterface.sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - - updateTable = 'organization_registration_codes' - key = 'organization_code' - await queryInterface.sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - - updateTable = 'organization_user_invites' - key = 'organization_code' - await queryInterface.sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - - updateTable = 'user_organizations' - key = 'organization_code' - await queryInterface.sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - updateTable = 'user_organization_roles' - key = 'organization_code' - await queryInterface.sequelize.query(updateQuery(updateTable, key), { - type: Sequelize.QueryTypes.UPDATE, - raw: true, - transaction, - }) - - // Verify the update - const fetchOrgs = await queryInterface.sequelize.query(ORG_FETCH_QUERY, { - type: Sequelize.QueryTypes.SELECT, - raw: true, - transaction, - }) - console.log(fetchOrgs) - - // Re-enable foreign key constraints - let fk_retainerPromise = [] - for (let i = 0; i < fk_retainer.length; i++) { - fk_retainerPromise.push( - queryInterface.sequelize.query(fk_retainer[i], { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction, - }) - ) + if (fetchOrg.length > 0) { + // Disable foreign key constraints and store enable queries + table = 'organization_registration_codes' + fk_name = 'fk_organization_code_tenant_code_in_org_reg_code' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + + table = 'user_organizations' + fk_name = 'fk_user_organizations_organizations' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'organization_user_invites' + fk_name = 'fk_org_user_invites_org_code' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'organization_user_invites' + fk_name = 'fk_org_user_invites_organization_id' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + table = 'user_organization_roles' + fk_name = 'fk_user_org_roles_user_organizations' + fkey = '(user_id, organization_code, tenant_code)' + refTable = 'user_organizations' + refKey = '(user_id, organization_code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + + // Update tables to remove whitespace + let updateTable = 'organizations' + let key = 'code' + const updateOrgs = await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'organization_registration_codes' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'organization_user_invites' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'user_organizations' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + updateTable = 'user_organization_roles' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) + + // Verify the update + const fetchOrgs = await queryInterface.sequelize.query(ORG_FETCH_QUERY, { + type: Sequelize.QueryTypes.SELECT, + raw: true, + transaction, + }) + console.log(fetchOrgs) + + // Re-enable foreign key constraints + let fk_retainerPromise = [] + for (let i = 0; i < fk_retainer.length; i++) { + fk_retainerPromise.push( + queryInterface.sequelize.query(fk_retainer[i], { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + ) + } + + await Promise.all(fk_retainerPromise) + + // Commit the transaction + await transaction.commit() + console.log('Transaction committed successfully.') } - - await Promise.all(fk_retainerPromise) - - // Commit the transaction - await transaction.commit() - console.log('Transaction committed successfully.') } catch (error) { // Rollback transaction on error if (transaction) await transaction.rollback() From 9d1494e83adbafb646c67347126c1bfc3f197558 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 29 Jul 2025 17:49:54 +0530 Subject: [PATCH 5/8] review comments addressed --- src/database/migrations/20250729064710-org-code-fix.js | 4 ++-- src/routes/index.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database/migrations/20250729064710-org-code-fix.js b/src/database/migrations/20250729064710-org-code-fix.js index 72a5a390..a1b623b3 100644 --- a/src/database/migrations/20250729064710-org-code-fix.js +++ b/src/database/migrations/20250729064710-org-code-fix.js @@ -10,12 +10,12 @@ module.exports = { // Start a transaction transaction = await queryInterface.sequelize.transaction() - const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\\s+';` + const ORG_FETCH_QUERY = `SELECT id, name, code FROM organizations WHERE code ~ '\\s+' OR code ~ '[A-Z]';` const disableFK = (table, fk_name) => `ALTER TABLE ${table} DROP CONSTRAINT IF EXISTS ${fk_name};` const enableFK = (table, fk_name, fkey, refTable, refKey) => `ALTER TABLE ${table} ADD CONSTRAINT ${fk_name} FOREIGN KEY ${fkey} REFERENCES ${refTable} ${refKey} ON UPDATE NO ACTION ON DELETE CASCADE;` const updateQuery = (table, key) => - `UPDATE ${table} SET ${key} = REGEXP_REPLACE(${key}, '\\s+', '', 'g') WHERE ${key} ~ '\\s+';` + `UPDATE ${table} SET ${key} = LOWER(REGEXP_REPLACE(${key}, '\\s+', '_', 'g')) WHERE ${key} ~ '[A-Z|\\s+]';` // Execute the query to fetch organizations with whitespace const fetchOrg = await queryInterface.sequelize.query(ORG_FETCH_QUERY, { diff --git a/src/routes/index.js b/src/routes/index.js index ab0e329f..552a20b5 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -70,7 +70,7 @@ module.exports = (app) => { const version = (req.params.version.match(/^v\d+$/) || [])[0] // Match version like v1, v2, etc. const controllerName = (req.params.controller.match(/^[a-zA-Z0-9_-]+$/) || [])[0] // Allow only alphanumeric characters, underscore, and hyphen const file = req.params.file ? (req.params.file.match(/^[a-zA-Z0-9_-]+$/) || [])[0] : null // Same validation as controller, or null if file is not provided - const method = (req.params.method.match(/^[a-zA-Z0-9]+$/) || [])[0] // Allow only alphanumeric characters + const method = (req.params.method.match(/^[a-zA-Z0-9_-]+$/) || [])[0] // Allow only alphanumeric characters try { if (!version || !controllerName || !method || (req.params.file && !file)) { // Invalid input, return an error response From 0317a0bda2d6648f29121319519d049d71436ab2 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 29 Jul 2025 17:54:55 +0530 Subject: [PATCH 6/8] review comments addressed --- src/database/migrations/20250729064710-org-code-fix.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/database/migrations/20250729064710-org-code-fix.js b/src/database/migrations/20250729064710-org-code-fix.js index a1b623b3..008365c8 100644 --- a/src/database/migrations/20250729064710-org-code-fix.js +++ b/src/database/migrations/20250729064710-org-code-fix.js @@ -72,7 +72,6 @@ module.exports = { raw: true, transaction, }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) table = 'user_organization_roles' fk_name = 'fk_user_org_roles_user_organizations' From 57084411b6fa2095aa5ff56118c5407f407aa72f Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 29 Jul 2025 17:59:15 +0530 Subject: [PATCH 7/8] review comments addressed --- .../migrations/20250729064710-org-code-fix.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/database/migrations/20250729064710-org-code-fix.js b/src/database/migrations/20250729064710-org-code-fix.js index 008365c8..29ee0042 100644 --- a/src/database/migrations/20250729064710-org-code-fix.js +++ b/src/database/migrations/20250729064710-org-code-fix.js @@ -85,6 +85,18 @@ module.exports = { }) fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + table = 'organization_features' + fk_name = 'fk_org_features_organization' + fkey = '(organization_code, tenant_code)' + refTable = 'organizations' + refKey = '(code, tenant_code)' + await queryInterface.sequelize.query(disableFK(table, fk_name), { + type: Sequelize.QueryTypes.RAW, + raw: true, + transaction, + }) + fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) + // Update tables to remove whitespace let updateTable = 'organizations' let key = 'code' @@ -125,6 +137,13 @@ module.exports = { raw: true, transaction, }) + updateTable = 'organization_features' + key = 'organization_code' + await queryInterface.sequelize.query(updateQuery(updateTable, key), { + type: Sequelize.QueryTypes.UPDATE, + raw: true, + transaction, + }) // Verify the update const fetchOrgs = await queryInterface.sequelize.query(ORG_FETCH_QUERY, { From 1c9708ecb694fcf44ecf56688627f15ed4af20ac Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Wed, 30 Jul 2025 14:31:23 +0530 Subject: [PATCH 8/8] coderabit review comments addressed --- .../migrations/20250729064710-org-code-fix.js | 14 -------------- src/validators/v1/organization.js | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/database/migrations/20250729064710-org-code-fix.js b/src/database/migrations/20250729064710-org-code-fix.js index 29ee0042..8b155916 100644 --- a/src/database/migrations/20250729064710-org-code-fix.js +++ b/src/database/migrations/20250729064710-org-code-fix.js @@ -50,18 +50,6 @@ module.exports = { }) fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - table = 'organization_user_invites' - fk_name = 'fk_org_user_invites_org_code' - fkey = '(organization_code, tenant_code)' - refTable = 'organizations' - refKey = '(code, tenant_code)' - await queryInterface.sequelize.query(disableFK(table, fk_name), { - type: Sequelize.QueryTypes.RAW, - raw: true, - transaction, - }) - fk_retainer.push(enableFK(table, fk_name, fkey, refTable, refKey)) - table = 'organization_user_invites' fk_name = 'fk_org_user_invites_organization_id' fkey = '(organization_code, tenant_code)' @@ -151,7 +139,6 @@ module.exports = { raw: true, transaction, }) - console.log(fetchOrgs) // Re-enable foreign key constraints let fk_retainerPromise = [] @@ -169,7 +156,6 @@ module.exports = { // Commit the transaction await transaction.commit() - console.log('Transaction committed successfully.') } } catch (error) { // Rollback transaction on error diff --git a/src/validators/v1/organization.js b/src/validators/v1/organization.js index fd80a170..f81a6d42 100644 --- a/src/validators/v1/organization.js +++ b/src/validators/v1/organization.js @@ -16,7 +16,7 @@ module.exports = { .trim() .notEmpty() .withMessage('code field is empty') - .matches(/^[a-z0-9]+$/) + .matches(/^[a-z0-9_]+$/) .withMessage('code is invalid. Only lowercase alphanumeric characters allowed') req.checkBody('tenant_code').trim().notEmpty().withMessage('tenant_code field is empty') req.checkBody('registration_codes')