diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index b04687967dfc..823ad7028a94 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -122,6 +122,9 @@ export default { REPORT_USER_IS_TYPING: 'reportUserIsTyping_', SECURITY_GROUP: 'securityGroup_', TRANSACTION: 'transactions_', + + // This is deprecated, but needed for a migration, so we still need to include it here so that it will be initialized in Onyx.init + DEPRECATED_POLICY_MEMBER_LIST: 'policyMemberList_', }, // Indicates which locale should be used diff --git a/src/libs/migrations/PersonalDetailsByAccountID.js b/src/libs/migrations/PersonalDetailsByAccountID.js index 8716f063357e..2872e0ed1afe 100644 --- a/src/libs/migrations/PersonalDetailsByAccountID.js +++ b/src/libs/migrations/PersonalDetailsByAccountID.js @@ -43,6 +43,22 @@ function getDeprecatedPersonalDetailsFromOnyx() { }); } +/** + * @returns {Promise} + */ +function getDeprecatedPolicyMemberListFromOnyx() { + return new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST, + waitForCollectionCallback: true, + callback: (allPolicyMembers) => { + Onyx.disconnect(connectionID); + return resolve(allPolicyMembers); + }, + }); + }); +} + /** * Migrate Onyx data for the email to accountID migration. * @@ -59,155 +75,157 @@ function getDeprecatedPersonalDetailsFromOnyx() { * @returns {Promise} */ export default function () { - return Promise.all([getReportActionsFromOnyx(), getDeprecatedPersonalDetailsFromOnyx()]).then(([oldReportActions, oldPersonalDetails]) => { - const onyxData = {}; - - if (!oldReportActions) { - Log.info('[Migrate Onyx] Skipped migration PersonalDetailsByAccountID because there were no reportActions'); - return; - } - - // We migrate reportActions to have the new accountID-based data if they don't already. - // If we are not able to get the accountID from personalDetails for some reason, we will just clear the reportAction - // and let it be fetched from the API next time they open the report and scroll to that action. - // We do this because we know the reportAction from the API will include the needed accountID data. - _.each(oldReportActions, (reportActionsForReport, onyxKey) => { - if (_.isEmpty(reportActionsForReport)) { - Log.info(`[Migrate Onyx] Skipped migration PersonalDetailsByAccountID for ${onyxKey} because there were no reportActions`); - return; - } - - const newReportActionsForReport = {}; - let reportActionsWereModified = false; - _.each(reportActionsForReport, (reportAction, reportActionID) => { - if (_.isEmpty(reportAction)) { - reportActionsWereModified = true; - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because the reportAction was empty`); + return Promise.all([getReportActionsFromOnyx(), getDeprecatedPersonalDetailsFromOnyx(), getDeprecatedPolicyMemberListFromOnyx()]).then( + ([oldReportActions, oldPersonalDetails, oldPolicyMemberList]) => { + const onyxData = {}; + + // The policyMemberList_ collection has been replaced by policyMembers_ + // So if we find any instances of policyMemberList_ we will clear them out + _.each(oldPolicyMemberList, (_policyMembersForPolicy, policyKey) => { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing policyMemberList ${policyKey}`); + onyxData[policyKey] = null; + }); + + // We migrate reportActions to have the new accountID-based data if they don't already. + // If we are not able to get the accountID from personalDetails for some reason, we will just clear the reportAction + // and let it be fetched from the API next time they open the report and scroll to that action. + // We do this because we know the reportAction from the API will include the needed accountID data. + _.each(oldReportActions, (reportActionsForReport, onyxKey) => { + if (_.isEmpty(reportActionsForReport)) { + Log.info(`[Migrate Onyx] Skipped migration PersonalDetailsByAccountID for ${onyxKey} because there were no reportActions`); return; } - - const newReportAction = reportAction; - - if (lodashHas(reportAction, ['originalMessage', 'oldLogin']) && !lodashHas(reportAction, ['originalMessage', 'oldAccountID'])) { - reportActionsWereModified = true; - const oldAccountID = _.get(oldPersonalDetails, [reportAction.originalMessage.oldLogin, 'accountID']); - if (oldAccountID) { - newReportAction.originalMessage.oldAccountID = oldAccountID; - } else { - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because originalMessage.oldAccountID not found`); + const newReportActionsForReport = {}; + let reportActionsWereModified = false; + _.each(reportActionsForReport, (reportAction, reportActionID) => { + if (_.isEmpty(reportAction)) { + reportActionsWereModified = true; + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because the reportAction was empty`); return; } - } - - if (lodashHas(reportAction, ['originalMessage', 'newLogin']) && !lodashHas(reportAction, ['originalMessage', 'newAccountID'])) { - reportActionsWereModified = true; - const newAccountID = _.get(oldPersonalDetails, [reportAction.originalMessage.newLogin, 'accountID']); - if (newAccountID) { - newReportAction.originalMessage.newAccountID = newAccountID; - } else { - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because originalMessage.newAccountID not found`); - return; + const newReportAction = reportAction; + + if (lodashHas(reportAction, ['originalMessage', 'oldLogin']) && !lodashHas(reportAction, ['originalMessage', 'oldAccountID'])) { + reportActionsWereModified = true; + const oldAccountID = _.get(oldPersonalDetails, [reportAction.originalMessage.oldLogin, 'accountID']); + if (oldAccountID) { + newReportAction.originalMessage.oldAccountID = oldAccountID; + } else { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because originalMessage.oldAccountID not found`); + return; + } } - } - if (lodashHas(reportAction, ['accountEmail']) && !lodashHas(reportAction, ['accountID'])) { - reportActionsWereModified = true; - const accountID = _.get(oldPersonalDetails, [reportAction.accountEmail, 'accountID']); - if (accountID) { - newReportAction.accountID = accountID; - } else { - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because accountID not found`); - return; + if (lodashHas(reportAction, ['originalMessage', 'newLogin']) && !lodashHas(reportAction, ['originalMessage', 'newAccountID'])) { + reportActionsWereModified = true; + const newAccountID = _.get(oldPersonalDetails, [reportAction.originalMessage.newLogin, 'accountID']); + if (newAccountID) { + newReportAction.originalMessage.newAccountID = newAccountID; + } else { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because originalMessage.newAccountID not found`); + return; + } } - } - if (lodashHas(reportAction, ['actorEmail']) && !lodashHas(reportAction, ['actorAccountID'])) { - reportActionsWereModified = true; - const actorAccountID = _.get(oldPersonalDetails, [reportAction.actorEmail, 'accountID']); - if (actorAccountID) { - newReportAction.actorAccountID = actorAccountID; - } else { - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because actorAccountID not found`); - return; + if (lodashHas(reportAction, ['accountEmail']) && !lodashHas(reportAction, ['accountID'])) { + reportActionsWereModified = true; + const accountID = _.get(oldPersonalDetails, [reportAction.accountEmail, 'accountID']); + if (accountID) { + newReportAction.accountID = accountID; + } else { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because accountID not found`); + return; + } } - } - if (lodashHas(reportAction, ['childManagerEmail']) && !lodashHas(reportAction, ['childManagerAccountID'])) { - reportActionsWereModified = true; - const childManagerAccountID = _.get(oldPersonalDetails, [reportAction.childManagerEmail, 'accountID']); - if (childManagerAccountID) { - newReportAction.childManagerAccountID = childManagerAccountID; - } else { - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because childManagerAccountID not found`); - return; + if (lodashHas(reportAction, ['actorEmail']) && !lodashHas(reportAction, ['actorAccountID'])) { + reportActionsWereModified = true; + const actorAccountID = _.get(oldPersonalDetails, [reportAction.actorEmail, 'accountID']); + if (actorAccountID) { + newReportAction.actorAccountID = actorAccountID; + } else { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because actorAccountID not found`); + return; + } } - } - if (lodashHas(reportAction, ['whisperedTo']) && !lodashHas(reportAction, ['whisperedToAccountIDs'])) { - reportActionsWereModified = true; - const whisperedToAccountIDs = []; - _.each(reportAction.whisperedTo, (whisperedToLogin) => { - const whisperedToAccountID = _.get(oldPersonalDetails, [whisperedToLogin, 'accountID']); - if (whisperedToAccountID) { - whisperedToAccountIDs.push(whisperedToAccountID); + if (lodashHas(reportAction, ['childManagerEmail']) && !lodashHas(reportAction, ['childManagerAccountID'])) { + reportActionsWereModified = true; + const childManagerAccountID = _.get(oldPersonalDetails, [reportAction.childManagerEmail, 'accountID']); + if (childManagerAccountID) { + newReportAction.childManagerAccountID = childManagerAccountID; + } else { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because childManagerAccountID not found`); + return; } - }); - - if (whisperedToAccountIDs.length === reportAction.whisperedTo.length) { - newReportAction.whisperedToAccountIDs = whisperedToAccountIDs; - } else { - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because whisperedToAccountIDs not found`); - return; } - } - if (lodashHas(reportAction, ['childOldestFourEmails']) && !lodashHas(reportAction, ['childOldestFourAccountIDs'])) { - reportActionsWereModified = true; - const childOldestFourEmails = reportAction.childOldestFourEmails.split(','); - const childOldestFourAccountIDs = []; - _.each(childOldestFourEmails, (login) => { - const accountID = _.get(oldPersonalDetails, [login.trim(), 'accountID']); - if (accountID) { - childOldestFourAccountIDs.push(accountID); + if (lodashHas(reportAction, ['whisperedTo']) && !lodashHas(reportAction, ['whisperedToAccountIDs'])) { + reportActionsWereModified = true; + const whisperedToAccountIDs = []; + _.each(reportAction.whisperedTo, (whisperedToLogin) => { + const whisperedToAccountID = _.get(oldPersonalDetails, [whisperedToLogin, 'accountID']); + if (whisperedToAccountID) { + whisperedToAccountIDs.push(whisperedToAccountID); + } + }); + + if (whisperedToAccountIDs.length === reportAction.whisperedTo.length) { + newReportAction.whisperedToAccountIDs = whisperedToAccountIDs; + } else { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because whisperedToAccountIDs not found`); + return; } - }); - - if (childOldestFourAccountIDs.length === childOldestFourEmails.length) { - newReportAction.childOldestFourAccountIDs = childOldestFourAccountIDs.join(','); - } else { - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because childOldestFourAccountIDs not found`); - return; } - } - if (lodashHas(reportAction, ['originalMessage', 'participants']) && !lodashHas(reportAction, ['originalMessage', 'participantAccountIDs'])) { - reportActionsWereModified = true; - const participantAccountIDs = []; - _.each(reportAction.originalMessage.participants, (participant) => { - const participantAccountID = _.get(oldPersonalDetails, [participant, 'accountID']); - if (participantAccountID) { - participantAccountIDs.push(participantAccountID); + if (lodashHas(reportAction, ['childOldestFourEmails']) && !lodashHas(reportAction, ['childOldestFourAccountIDs'])) { + reportActionsWereModified = true; + const childOldestFourEmails = reportAction.childOldestFourEmails.split(','); + const childOldestFourAccountIDs = []; + _.each(childOldestFourEmails, (login) => { + const accountID = _.get(oldPersonalDetails, [login.trim(), 'accountID']); + if (accountID) { + childOldestFourAccountIDs.push(accountID); + } + }); + + if (childOldestFourAccountIDs.length === childOldestFourEmails.length) { + newReportAction.childOldestFourAccountIDs = childOldestFourAccountIDs.join(','); + } else { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because childOldestFourAccountIDs not found`); + return; } - }); + } - if (participantAccountIDs.length === reportAction.originalMessage.participants.length) { - newReportAction.originalMessage.participantAccountIDs = participantAccountIDs; - } else { - Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because originalMessage.participantAccountIDs not found`); - return; + if (lodashHas(reportAction, ['originalMessage', 'participants']) && !lodashHas(reportAction, ['originalMessage', 'participantAccountIDs'])) { + reportActionsWereModified = true; + const participantAccountIDs = []; + _.each(reportAction.originalMessage.participants, (participant) => { + const participantAccountID = _.get(oldPersonalDetails, [participant, 'accountID']); + if (participantAccountID) { + participantAccountIDs.push(participantAccountID); + } + }); + + if (participantAccountIDs.length === reportAction.originalMessage.participants.length) { + newReportAction.originalMessage.participantAccountIDs = participantAccountIDs; + } else { + Log.info(`[Migrate Onyx] PersonalDetailsByAccountID migration: removing reportAction ${reportActionID} because originalMessage.participantAccountIDs not found`); + return; + } } - } - newReportActionsForReport[reportActionID] = newReportAction; - }); + newReportActionsForReport[reportActionID] = newReportAction; + }); - // Only include the reportActions from this report if at least one reportAction in this report - // was modified in any way. - if (reportActionsWereModified) { - onyxData[onyxKey] = newReportActionsForReport; - } - }); + // Only include the reportActions from this report if at least one reportAction in this report + // was modified in any way. + if (reportActionsWereModified) { + onyxData[onyxKey] = newReportActionsForReport; + } + }); - return Onyx.multiSet(onyxData); - }); + return Onyx.multiSet(onyxData); + }, + ); } diff --git a/tests/unit/MigrationTest.js b/tests/unit/MigrationTest.js index e9f605699e43..6162bded793b 100644 --- a/tests/unit/MigrationTest.js +++ b/tests/unit/MigrationTest.js @@ -261,10 +261,6 @@ describe('Migrations', () => { PERSONAL_DETAILS: 'personalDetails', }; - // Warning: this test has to come before the others in this suite because Onyx.clear leaves traces and keys with null values aren't cleared out between tests - it("Should skip the migration if there's no reportAction data in Onyx", () => - PersonalDetailsByAccountID().then(() => expect(LogSpy).toHaveBeenCalledWith('[Migrate Onyx] Skipped migration PersonalDetailsByAccountID because there were no reportActions'))); - it('Should skip any zombie reportAction collections that have no reportAction data in Onyx', () => Onyx.multiSet({ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: null, @@ -811,5 +807,43 @@ describe('Migrations', () => { }, }); })); + + it('Should succeed in removing any policyMemberList objects it finds in Onyx', () => + Onyx.multiSet({ + [`${ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST}1`]: { + 'admin@company1.com': { + role: 'admin', + }, + 'employee@company1.com': { + role: 'user', + }, + }, + [`${ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST}2`]: { + 'admin@company2.com': { + role: 'admin', + }, + 'employee@company2.com': { + role: 'user', + }, + }, + }) + .then(PersonalDetailsByAccountID) + .then(() => { + expect(LogSpy).toHaveBeenCalledWith( + `[Migrate Onyx] PersonalDetailsByAccountID migration: removing policyMemberList ${ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST}1`, + ); + expect(LogSpy).toHaveBeenCalledWith( + `[Migrate Onyx] PersonalDetailsByAccountID migration: removing policyMemberList ${ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST}2`, + ); + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST, + waitForCollectionCallback: true, + callback: (allPolicyMemberLists) => { + Onyx.disconnect(connectionID); + expect(allPolicyMemberLists[`${ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST}1`]).toBeNull(); + expect(allPolicyMemberLists[`${ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST}2`]).toBeNull(); + }, + }); + })); }); });