From 0039710f5c6e8a981d7d9035376af40965ba327a Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Sat, 6 Nov 2021 21:46:20 -0400 Subject: [PATCH 01/10] Fix circular dependencies by moving Log out of HttpUtils and handling Network logs in API.js --- src/libs/API.js | 77 +++++++++++++---------------------- src/libs/HttpUtils.js | 30 +------------- src/libs/Log.js | 33 +++++++++------ src/libs/Network.js | 10 +++++ src/libs/NetworkConnection.js | 18 +++----- src/libs/requireParameters.js | 30 ++++++++++++++ 6 files changed, 94 insertions(+), 104 deletions(-) create mode 100644 src/libs/requireParameters.js diff --git a/src/libs/API.js b/src/libs/API.js index f7a51a777900..2d94f31912bf 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -6,9 +6,8 @@ import ONYXKEYS from '../ONYXKEYS'; import redirectToSignIn from './actions/SignInRedirect'; import * as Network from './Network'; import isViaExpensifyCashNative from './isViaExpensifyCashNative'; - -// eslint-disable-next-line import/no-cycle -import LogUtil from './Log'; +import requireParameters from './requireParameters'; +import Log from './Log'; let isAuthenticating; let credentials; @@ -60,7 +59,7 @@ function addDefaultValuesToParameters(command, parameters) { if (!authToken) { redirectToSignIn(); - LogUtil.info('A request was made without an authToken', false, {command, parameters}); + Log.info('A request was made without an authToken', false, {command, parameters}); Network.pauseRequestQueue(); Network.clearRequestQueue(); Network.unpauseRequestQueue(); @@ -82,33 +81,6 @@ function addDefaultValuesToParameters(command, parameters) { // Tie into the network layer to add auth token to the parameters of all requests Network.registerParameterEnhancer(addDefaultValuesToParameters); -/** - * @throws {Error} If the "parameters" object has a null or undefined value for any of the given parameterNames - * - * @param {String[]} parameterNames Array of the required parameter names - * @param {Object} parameters A map from available parameter names to their values - * @param {String} commandName The name of the API command - */ -function requireParameters(parameterNames, parameters, commandName) { - parameterNames.forEach((parameterName) => { - if (!_(parameters).has(parameterName) - || parameters[parameterName] === null - || parameters[parameterName] === undefined - ) { - const propertiesToRedact = ['authToken', 'password', 'partnerUserSecret', 'twoFactorAuthCode']; - const parametersCopy = _.chain(parameters) - .clone() - .mapObject((val, key) => (_.contains(propertiesToRedact, key) ? '' : val)) - .value(); - const keys = _(parametersCopy).keys().join(', ') || 'none'; - - let error = `Parameter ${parameterName} is required for "${commandName}". `; - error += `Supplied parameters: ${keys}`; - throw new Error(error); - } - }); -} - /** * Function used to handle expired auth tokens. It re-authenticates with the API and * then replays the original request @@ -144,7 +116,30 @@ function handleExpiredAuthToken(originalCommand, originalParameters, originalTyp )); } +Network.registerRequestHandler((queuedRequest, finalParameters) => { + if (queuedRequest.command === 'Log') { + return; + } + + Log.info('Making API request', false, { + command: queuedRequest.command, + type: queuedRequest.type, + shouldUseSecure: queuedRequest.type, + rvl: finalParameters.returnValueList, + }); +}); + Network.registerResponseHandler((queuedRequest, response) => { + if (queuedRequest.command !== 'Log') { + Log.info('Finished API request', false, { + command: queuedRequest.command, + type: queuedRequest.type, + shouldUseSecure: queuedRequest.shouldUseSecure, + jsonCode: response.jsonCode, + requestID: response.requestID, + }); + } + if (response.jsonCode === 407) { // Credentials haven't been initialized. We will not be able to re-authenticates with the API const unableToReauthenticate = (!credentials || !credentials.autoGeneratedLogin @@ -176,7 +171,7 @@ Network.registerResponseHandler((queuedRequest, response) => { Network.registerErrorHandler((queuedRequest, error) => { if (queuedRequest.command !== 'Log') { - LogUtil.hmmm('[API] Handled error when making request', error); + Log.hmmm('[API] Handled error when making request', error); } else { console.debug('[API] There was an error in the Log API command, unable to log to server!', error); } @@ -310,7 +305,7 @@ function reauthenticate(command = '') { // If we experience something other than a network error then redirect the user to sign in redirectToSignIn(error.message); - LogUtil.hmmm('Redirecting to Sign In because we failed to reauthenticate', { + Log.hmmm('Redirecting to Sign In because we failed to reauthenticate', { command, error: error.message, }); @@ -508,21 +503,6 @@ function GetRequestCountryCode() { return Network.post(commandName); } -/** - * @param {Object} parameters - * @param {String} parameters.expensifyCashAppVersion - * @param {Object[]} parameters.logPacket - * @returns {Promise} - */ -function Log(parameters) { - const commandName = 'Log'; - requireParameters(['logPacket', 'expensifyCashAppVersion'], - parameters, commandName); - - // Note: We are forcing Log to run since it requires no authToken and should only be queued when we are offline. - return Network.post(commandName, {...parameters, forceNetworkRequest: true}); -} - /** * @param {Object} parameters * @param {String} parameters.name @@ -1134,7 +1114,6 @@ export { GetRequestCountryCode, Graphite_Timer, Inbox_CallUser, - Log, PayIOU, PayWithWallet, PersonalDetails_GetForEmails, diff --git a/src/libs/HttpUtils.js b/src/libs/HttpUtils.js index 531146c41236..f9a33ea4be05 100644 --- a/src/libs/HttpUtils.js +++ b/src/libs/HttpUtils.js @@ -4,9 +4,6 @@ import CONFIG from '../CONFIG'; import CONST from '../CONST'; import ONYXKEYS from '../ONYXKEYS'; -// To avoid a circular dependency, we can't include Log here, so instead, we define an empty logging method and expose the setLogger method to set the logger from outside this file -let info = () => {}; - let shouldUseSecureStaging = false; Onyx.connect({ key: ONYXKEYS.USER, @@ -39,14 +36,6 @@ function processHTTPRequest(url, method = 'get', body = null) { * @returns {Promise} */ function xhr(command, data, type = CONST.NETWORK.METHOD.POST, shouldUseSecure = false) { - if (command !== 'Log') { - info('Making API request', false, { - command, - type, - shouldUseSecure, - rvl: data.returnValueList, - }); - } const formData = new FormData(); _.each(data, (val, key) => formData.append(key, val)); let apiRoot = shouldUseSecure ? CONFIG.EXPENSIFY.URL_EXPENSIFY_SECURE : CONFIG.EXPENSIFY.URL_API_ROOT; @@ -55,19 +44,7 @@ function xhr(command, data, type = CONST.NETWORK.METHOD.POST, shouldUseSecure = apiRoot = CONST.STAGING_SECURE_URL; } - return processHTTPRequest(`${apiRoot}api?command=${command}`, type, formData) - .then((response) => { - if (command !== 'Log') { - info('Finished API request', false, { - command, - type, - shouldUseSecure, - jsonCode: response.jsonCode, - requestID: response.requestID, - }); - } - return response; - }); + return processHTTPRequest(`${apiRoot}api?command=${command}`, type, formData); } /** @@ -87,12 +64,7 @@ function download(relativePath) { return processHTTPRequest(`${siteRoot}${strippedRelativePath}`); } -function setLogger(logger) { - info = logger.info; -} - export default { - setLogger, download, xhr, }; diff --git a/src/libs/Log.js b/src/libs/Log.js index 14a32f198651..aa1019f3da30 100644 --- a/src/libs/Log.js +++ b/src/libs/Log.js @@ -2,14 +2,26 @@ import Logger from 'expensify-common/lib/Logger'; import CONFIG from '../CONFIG'; import getPlatform from './getPlatform'; import {version} from '../../package.json'; -import NetworkConnection from './NetworkConnection'; -import HttpUtils from './HttpUtils'; - -// eslint-disable-next-line import/no-cycle -import * as API from './API'; +import requireParameters from './requireParameters'; +import * as Network from './Network'; let timeout = null; +/** + * @param {Object} parameters + * @param {String} parameters.expensifyCashAppVersion + * @param {Object[]} parameters.logPacket + * @returns {Promise} + */ +function LogCommand(parameters) { + const commandName = 'Log'; + requireParameters(['logPacket', 'expensifyCashAppVersion'], + parameters, commandName); + + // Note: We are forcing Log to run since it requires no authToken and should only be queued when we are offline. + return Network.post(commandName, {...parameters, forceNetworkRequest: true}); +} + /** * Network interface for logger. * @@ -28,13 +40,11 @@ function serverLoggingCallback(logger, params) { } clearTimeout(timeout); timeout = setTimeout(() => logger.info('Flushing logs older than 10 minutes', true, {}, true), 10 * 60 * 1000); - return API.Log(requestParams); + return LogCommand(requestParams); } -// Note: We are importing Logger from expensify-common because it is -// used by other platforms. The server and client logging -// callback methods are passed in here so we can decouple -// the logging library from the logging methods. +// Note: We are importing Logger from expensify-common because it is used by other platforms. The server and client logging +// callback methods are passed in here so we can decouple the logging library from the logging methods. const Log = new Logger({ serverLoggingCallback, clientLoggingCallback: (message) => { @@ -44,7 +54,4 @@ const Log = new Logger({ }); timeout = setTimeout(() => Log.info('Flushing logs older than 10 minutes', true, {}, true), 10 * 60 * 1000); -NetworkConnection.registerLogInfoCallback(Log.info); -HttpUtils.setLogger(Log); - export default Log; diff --git a/src/libs/Network.js b/src/libs/Network.js index aa1fd853ae82..4479723edfd6 100644 --- a/src/libs/Network.js +++ b/src/libs/Network.js @@ -20,6 +20,7 @@ let enhanceParameters; // The first argument passed will be the queuedRequest object and the second will be either the response or error. let onResponse = () => {}; let onError = () => {}; +let onRequest = () => {}; let didLoadPersistedRequests; let isOffline; @@ -207,6 +208,7 @@ function processNetworkRequestQueue() { return; } + onRequest(queuedRequest, finalParameters); HttpUtils.xhr(queuedRequest.command, finalParameters, queuedRequest.type, queuedRequest.shouldUseSecure) .then(response => onResponse(queuedRequest, response)) .catch(error => onError(queuedRequest, error)); @@ -312,6 +314,13 @@ function registerResponseHandler(callback) { onResponse = callback; } +/** + * @param {Function} callback + */ +function registerRequestHandler(callback) { + onRequest = callback; +} + /** * The error handler will handle fetch() errors. Not used for successful responses that might send expected error codes * e.g. jsonCode: 407. @@ -329,4 +338,5 @@ export { clearRequestQueue, registerResponseHandler, registerErrorHandler, + registerRequestHandler, }; diff --git a/src/libs/NetworkConnection.js b/src/libs/NetworkConnection.js index 4e83f5a6d96c..e63b92693429 100644 --- a/src/libs/NetworkConnection.js +++ b/src/libs/NetworkConnection.js @@ -4,13 +4,13 @@ import NetInfo from './NetInfo'; import ONYXKEYS from '../ONYXKEYS'; import AppStateMonitor from './AppStateMonitor'; import promiseAllSettled from './promiseAllSettled'; +import Log from './Log'; // NetInfo.addEventListener() returns a function used to unsubscribe the // listener so we must create a reference to it and call it in stopListeningForReconnect() let unsubscribeFromNetInfo; let unsubscribeFromAppState; let isOffline = false; -let logInfo = () => {}; // Holds all of the callbacks that need to be triggered when the network reconnects const reconnectionCallbacks = []; @@ -19,7 +19,7 @@ const reconnectionCallbacks = []; * Loop over all reconnection callbacks and fire each one */ const triggerReconnectionCallbacks = _.throttle((reason) => { - logInfo(`[NetworkConnection] Firing reconnection callbacks because ${reason}`); + Log.info(`[NetworkConnection] Firing reconnection callbacks because ${reason}`); Onyx.set(ONYXKEYS.IS_LOADING_AFTER_RECONNECT, true); promiseAllSettled(_.map(reconnectionCallbacks, callback => callback())) .then(() => Onyx.set(ONYXKEYS.IS_LOADING_AFTER_RECONNECT, false)); @@ -49,7 +49,7 @@ function setOfflineStatus(isCurrentlyOffline) { * `disconnected` event which takes about 10-15 seconds to emit. */ function listenForReconnect() { - logInfo('[NetworkConnection] listenForReconnect called'); + Log.info('[NetworkConnection] listenForReconnect called'); unsubscribeFromAppState = AppStateMonitor.addBecameActiveListener(() => { triggerReconnectionCallbacks('app became active'); @@ -58,7 +58,7 @@ function listenForReconnect() { // Subscribe to the state change event via NetInfo so we can update // whether a user has internet connectivity or not. unsubscribeFromNetInfo = NetInfo.addEventListener((state) => { - logInfo(`[NetworkConnection] NetInfo isConnected: ${state && state.isConnected}`); + Log.info(`[NetworkConnection] NetInfo isConnected: ${state && state.isConnected}`); setOfflineStatus(!state.isConnected); }); } @@ -67,7 +67,7 @@ function listenForReconnect() { * Tear down the event listeners when we are finished with them. */ function stopListeningForReconnect() { - logInfo('[NetworkConnection] stopListeningForReconnect called'); + Log.info('[NetworkConnection] stopListeningForReconnect called'); if (unsubscribeFromNetInfo) { unsubscribeFromNetInfo(); unsubscribeFromNetInfo = undefined; @@ -87,18 +87,10 @@ function onReconnect(callback) { reconnectionCallbacks.push(callback); } -/** - * @param {Function} callback - */ -function registerLogInfoCallback(callback) { - logInfo = callback; -} - export default { setOfflineStatus, listenForReconnect, stopListeningForReconnect, onReconnect, triggerReconnectionCallbacks, - registerLogInfoCallback, }; diff --git a/src/libs/requireParameters.js b/src/libs/requireParameters.js new file mode 100644 index 000000000000..a40d8417cd2d --- /dev/null +++ b/src/libs/requireParameters.js @@ -0,0 +1,30 @@ +import _ from 'underscore'; + +/** + * @throws {Error} If the "parameters" object has a null or undefined value for any of the given parameterNames + * + * @param {String[]} parameterNames Array of the required parameter names + * @param {Object} parameters A map from available parameter names to their values + * @param {String} commandName The name of the API command + */ +export default function requireParameters(parameterNames, parameters, commandName) { + parameterNames.forEach((parameterName) => { + if (_(parameters).has(parameterName) + && parameters[parameterName] !== null + && parameters[parameterName] !== undefined + ) { + return; + } + + const propertiesToRedact = ['authToken', 'password', 'partnerUserSecret', 'twoFactorAuthCode']; + const parametersCopy = _.chain(parameters) + .clone() + .mapObject((val, key) => (_.contains(propertiesToRedact, key) ? '' : val)) + .value(); + const keys = _(parametersCopy).keys().join(', ') || 'none'; + + let error = `Parameter ${parameterName} is required for "${commandName}". `; + error += `Supplied parameters: ${keys}`; + throw new Error(error); + }); +} From 9c992b5395f8fa17108d3a4b71d15690c68009dd Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Sat, 6 Nov 2021 21:56:23 -0400 Subject: [PATCH 02/10] add createCallback --- src/libs/createCallback.js | 36 ++++++++++++++++++++++++++++++++ tests/unit/createCallbackTest.js | 25 ++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/libs/createCallback.js create mode 100644 tests/unit/createCallbackTest.js diff --git a/src/libs/createCallback.js b/src/libs/createCallback.js new file mode 100644 index 000000000000..61402a6edc33 --- /dev/null +++ b/src/libs/createCallback.js @@ -0,0 +1,36 @@ +import _ from 'underscore'; + +/** + * Utility for registering a single callback. Use to inject dependencies in places where you would normally "register" a method + * that you want to call later. Can be overwritten or cleared and returns value to caller. This is intented to be used with array + * destructuring. + * + * @example + * + * const [onResponse, handleResponse, clearHandler] = createCallback(); + * + * @returns {Array} + */ +function createCallback() { + let callback = null; + + function clear() { + callback = null; + } + + function set(newCallback) { + callback = newCallback; + } + + function run(...args) { + if (!_.isFunction(callback)) { + return; + } + + return callback(...args); + } + + return [run, set, clear]; +} + +export default createCallback; diff --git a/tests/unit/createCallbackTest.js b/tests/unit/createCallbackTest.js new file mode 100644 index 000000000000..7180452bf9f7 --- /dev/null +++ b/tests/unit/createCallbackTest.js @@ -0,0 +1,25 @@ +import createCallback from '../../src/libs/createCallback'; + +test('Callback utility works', () => { + // GIVEN a generic callback setup + const [doSomething, registerDoSomething, clear] = createCallback(); + const mockCallback = jest.fn(); + + // WHEN we register a callback + registerDoSomething(mockCallback); + + // THEN call the callback + doSomething(); + + // THEN our callback will be called + expect(mockCallback).toHaveBeenCalledTimes(1); + + // WHEN we clear the callback + clear(); + + // and call again + doSomething(); + + // THEN expect mock callback to not have been called again + expect(mockCallback).toHaveBeenCalledTimes(1); +}); From 19acbb81873cdf99980ad10e26eec1dca1c9d8fe Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Sat, 6 Nov 2021 21:58:59 -0400 Subject: [PATCH 03/10] use callback utility --- src/libs/Network.js | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/src/libs/Network.js b/src/libs/Network.js index 4479723edfd6..052b71078a11 100644 --- a/src/libs/Network.js +++ b/src/libs/Network.js @@ -5,6 +5,7 @@ import HttpUtils from './HttpUtils'; import ONYXKEYS from '../ONYXKEYS'; import * as ActiveClientManager from './ActiveClientManager'; import CONST from '../CONST'; +import createCallback from './createCallback'; let isQueuePaused = false; @@ -16,11 +17,11 @@ let networkRequestQueue = []; // parameters such as authTokens or CSRF tokens, etc. let enhanceParameters; -// These handlers must be registered in order to process the response or network errors returned from the queue. -// The first argument passed will be the queuedRequest object and the second will be either the response or error. -let onResponse = () => {}; -let onError = () => {}; -let onRequest = () => {}; +// These handlers must be registered so we can process the request, response, and errors returned from the queue. +// The first argument passed will be the queuedRequest object and the second will be either the parameters, response, or error. +const [onRequest, registerRequestHandler] = createCallback(); +const [onResponse, registerResponseHandler] = createCallback(); +const [onError, registerErrorHandler] = createCallback(); let didLoadPersistedRequests; let isOffline; @@ -306,30 +307,6 @@ function clearRequestQueue() { networkRequestQueue = []; } -/** - * Register a method to call when the authToken expires - * @param {Function} callback - */ -function registerResponseHandler(callback) { - onResponse = callback; -} - -/** - * @param {Function} callback - */ -function registerRequestHandler(callback) { - onRequest = callback; -} - -/** - * The error handler will handle fetch() errors. Not used for successful responses that might send expected error codes - * e.g. jsonCode: 407. - * @param {Function} callback - */ -function registerErrorHandler(callback) { - onError = callback; -} - export { post, pauseRequestQueue, From a49acd08013e81690da5b49bfdd05e76ee9e6570 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 8 Nov 2021 11:25:38 -0500 Subject: [PATCH 04/10] remove import/no-cycle created by Log depdendency cycle --- src/libs/API.js | 1 - src/libs/Navigation/Navigation.js | 1 - src/libs/Pusher/pusher.js | 1 - src/libs/actions/NameValuePair.js | 1 - src/libs/actions/Timing.js | 1 - src/libs/actions/User.js | 1 - src/libs/translate.js | 1 - 7 files changed, 7 deletions(-) diff --git a/src/libs/API.js b/src/libs/API.js index 9c796746094d..2fbc7c3515c7 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -4,7 +4,6 @@ import Onyx from 'react-native-onyx'; import CONST from '../CONST'; import CONFIG from '../CONFIG'; import ONYXKEYS from '../ONYXKEYS'; -// eslint-disable-next-line import/no-cycle import redirectToSignIn from './actions/SignInRedirect'; import * as Network from './Network'; import isViaExpensifyCashNative from './isViaExpensifyCashNative'; diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js index 85bfb3fa2daa..344d448eef80 100644 --- a/src/libs/Navigation/Navigation.js +++ b/src/libs/Navigation/Navigation.js @@ -9,7 +9,6 @@ import { } from '@react-navigation/native'; import PropTypes from 'prop-types'; import Onyx from 'react-native-onyx'; -// eslint-disable-next-line import/no-cycle import Log from '../Log'; import linkTo from './linkTo'; import ROUTES from '../../ROUTES'; diff --git a/src/libs/Pusher/pusher.js b/src/libs/Pusher/pusher.js index b4f1a4fa1a42..88e3c8943400 100644 --- a/src/libs/Pusher/pusher.js +++ b/src/libs/Pusher/pusher.js @@ -1,7 +1,6 @@ import _ from 'underscore'; import Pusher from './library'; import TYPE from './EventType'; -// eslint-disable-next-line import/no-cycle import Log from '../Log'; let socket; diff --git a/src/libs/actions/NameValuePair.js b/src/libs/actions/NameValuePair.js index b62b217199e1..2b0740558311 100644 --- a/src/libs/actions/NameValuePair.js +++ b/src/libs/actions/NameValuePair.js @@ -1,7 +1,6 @@ import _ from 'underscore'; import Onyx from 'react-native-onyx'; import lodashGet from 'lodash/get'; -// eslint-disable-next-line import/no-cycle import * as API from '../API'; /** diff --git a/src/libs/actions/Timing.js b/src/libs/actions/Timing.js index c7ee5a679c7e..a3a4567f2dfa 100644 --- a/src/libs/actions/Timing.js +++ b/src/libs/actions/Timing.js @@ -1,5 +1,4 @@ import getPlatform from '../getPlatform'; -// eslint-disable-next-line import/no-cycle import {Graphite_Timer} from '../API'; import {isDevelopment} from '../Environment/Environment'; import Firebase from '../Firebase'; diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 4a5d60e4badd..32c6cf906601 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import _ from 'underscore'; import lodashGet from 'lodash/get'; import Onyx from 'react-native-onyx'; diff --git a/src/libs/translate.js b/src/libs/translate.js index a024e7e59444..3fd7ca2253f5 100644 --- a/src/libs/translate.js +++ b/src/libs/translate.js @@ -2,7 +2,6 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; import Str from 'expensify-common/lib/str'; import Onyx from 'react-native-onyx'; -// eslint-disable-next-line import/no-cycle import Log from './Log'; import Config from '../CONFIG'; import translations from '../languages/translations'; From d02fdb91c5866ad4bedcaa19b90a85a661de69e7 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 8 Nov 2021 11:30:50 -0500 Subject: [PATCH 05/10] Remove dependency cycles --- src/libs/SignoutManager.js | 18 ++++++------------ src/libs/actions/Session.js | 9 --------- src/libs/actions/SignInRedirect.js | 1 - src/libs/actions/setShouldSignOut.js | 9 +++++++++ 4 files changed, 15 insertions(+), 22 deletions(-) create mode 100644 src/libs/actions/setShouldSignOut.js diff --git a/src/libs/SignoutManager.js b/src/libs/SignoutManager.js index 9588a3f969b4..71d9a0168b00 100644 --- a/src/libs/SignoutManager.js +++ b/src/libs/SignoutManager.js @@ -1,9 +1,10 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; -// eslint-disable-next-line import/no-cycle -import * as Session from './actions/Session'; +import createCallback from './createCallback'; +import setShouldSignOut from './actions/setShouldSignOut'; + +const [signoutCallback, registerSignoutCallback] = createCallback(); -let signoutCallback = () => {}; let errorMessage = ''; let shouldSignOut = false; Onyx.connect({ @@ -12,26 +13,19 @@ Onyx.connect({ if (!shouldSignOut && val) { signoutCallback(errorMessage); errorMessage = ''; - Session.setShouldSignOut(false); + setShouldSignOut(false); } shouldSignOut = val; }, }); -/** - * @param {Function} callback - */ -function registerSignoutCallback(callback) { - signoutCallback = callback; -} - /** * @param {String} message */ function signOut(message) { errorMessage = message; - Session.setShouldSignOut(true); + setShouldSignOut(true); } export default { diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index b0d40358dd6a..6b332777c5d0 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import Onyx from 'react-native-onyx'; import Str from 'expensify-common/lib/str'; import _ from 'underscore'; @@ -492,13 +491,6 @@ function authenticatePusher(socketID, channelName, callback) { }); } -/** - * @param {Boolean} shouldSignOut - */ -function setShouldSignOut(shouldSignOut) { - Onyx.set(ONYXKEYS.SHOULD_SIGN_OUT, shouldSignOut); -} - /** * @param {Boolean} shouldShowComposeInput */ @@ -524,6 +516,5 @@ export { validateEmail, authenticatePusher, reauthenticatePusher, - setShouldSignOut, setShouldShowComposeInput, }; diff --git a/src/libs/actions/SignInRedirect.js b/src/libs/actions/SignInRedirect.js index 9b4b43ee1566..95e8b862d8bc 100644 --- a/src/libs/actions/SignInRedirect.js +++ b/src/libs/actions/SignInRedirect.js @@ -1,5 +1,4 @@ import Onyx from 'react-native-onyx'; -// eslint-disable-next-line import/no-cycle import SignoutManager from '../SignoutManager'; import ONYXKEYS from '../../ONYXKEYS'; diff --git a/src/libs/actions/setShouldSignOut.js b/src/libs/actions/setShouldSignOut.js new file mode 100644 index 000000000000..ca3855b3b024 --- /dev/null +++ b/src/libs/actions/setShouldSignOut.js @@ -0,0 +1,9 @@ +import Onyx from 'react-native-onyx'; +import ONYXKEYS from '../../ONYXKEYS'; + +/** + * @param {Boolean} shouldSignOut + */ +export default function setShouldSignOut(shouldSignOut) { + Onyx.set(ONYXKEYS.SHOULD_SIGN_OUT, shouldSignOut); +} From 969c75147a47b573bb758442ef8452642c92bb5b Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 8 Nov 2021 11:40:03 -0500 Subject: [PATCH 06/10] fix bad merge --- src/libs/API.js | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/libs/API.js b/src/libs/API.js index 2fbc7c3515c7..29e74bfbdf9b 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -84,38 +84,6 @@ function addDefaultValuesToParameters(command, parameters) { Network.registerParameterEnhancer(addDefaultValuesToParameters); /** -<<<<<<< HEAD -======= - * @throws {Error} If the "parameters" object has a null or undefined value for any of the given parameterNames - * - * @param {String[]} parameterNames Array of the required parameter names - * @param {Object} parameters A map from available parameter names to their values - * @param {String} commandName The name of the API command - */ -function requireParameters(parameterNames, parameters, commandName) { - parameterNames.forEach((parameterName) => { - if (_(parameters).has(parameterName) - && parameters[parameterName] !== null - && parameters[parameterName] !== undefined - ) { - return; - } - - const propertiesToRedact = ['authToken', 'password', 'partnerUserSecret', 'twoFactorAuthCode']; - const parametersCopy = _.chain(parameters) - .clone() - .mapObject((val, key) => (_.contains(propertiesToRedact, key) ? '' : val)) - .value(); - const keys = _(parametersCopy).keys().join(', ') || 'none'; - - let error = `Parameter ${parameterName} is required for "${commandName}". `; - error += `Supplied parameters: ${keys}`; - throw new Error(error); - }); -} - -/** ->>>>>>> origin * Function used to handle expired auth tokens. It re-authenticates with the API and * then replays the original request * From a45e94899d6688fe866ff99233a793c64a72bb24 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 8 Nov 2021 12:04:36 -0500 Subject: [PATCH 07/10] Fix dependency cycle --- src/libs/API.js | 7 ++++--- src/libs/actions/Session.js | 18 ------------------ src/libs/actions/setSessionLoadingAndError.js | 10 ++++++++++ src/libs/actions/updateSessionAuthTokens.js | 10 ++++++++++ 4 files changed, 24 insertions(+), 21 deletions(-) create mode 100644 src/libs/actions/setSessionLoadingAndError.js create mode 100644 src/libs/actions/updateSessionAuthTokens.js diff --git a/src/libs/API.js b/src/libs/API.js index c94b21b5939b..8ffda9496829 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -9,7 +9,8 @@ import isViaExpensifyCashNative from './isViaExpensifyCashNative'; import requireParameters from './requireParameters'; import Log from './Log'; import * as Network from './Network'; -import * as Session from './actions/Session'; +import updateSessionAuthTokens from './actions/updateSessionAuthTokens'; +import setSessionLoadingAndError from './actions/setSessionLoadingAndError'; let isAuthenticating; let credentials; @@ -187,7 +188,7 @@ Network.registerErrorHandler((queuedRequest, error) => { } // Set an error state and signify we are done loading - Session.setSessionLoadingAndError(false, 'Cannot connect to server'); + setSessionLoadingAndError(false, 'Cannot connect to server'); // Reject the queued request with an API offline error so that the original caller can handle it. queuedRequest.reject(new Error(CONST.ERROR.API_OFFLINE)); @@ -288,7 +289,7 @@ function reauthenticate(command = '') { // Update authToken in Onyx and in our local variables so that API requests will use the // new authToken - Session.updateSessionAuthTokens(response.authToken, response.encryptedAuthToken); + updateSessionAuthTokens(response.authToken, response.encryptedAuthToken); authToken = response.authToken; // The authentication process is finished so the network can be unpaused to continue diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index 6b332777c5d0..e08dac6c61f7 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -375,22 +375,6 @@ function clearAccountMessages() { Onyx.merge(ONYXKEYS.ACCOUNT, {error: '', success: ''}); } -/** - * @param {Boolean} loading - * @param {String} error - */ -function setSessionLoadingAndError(loading, error) { - Onyx.merge(ONYXKEYS.SESSION, {loading, error}); -} - -/** - * @param {String} authToken - * @param {String} encryptedAuthToken - */ -function updateSessionAuthTokens(authToken, encryptedAuthToken) { - Onyx.merge(ONYXKEYS.SESSION, {authToken, encryptedAuthToken}); -} - /** * @param {String} authToken * @param {String} password @@ -511,8 +495,6 @@ export { clearSignInData, cleanupSession, clearAccountMessages, - setSessionLoadingAndError, - updateSessionAuthTokens, validateEmail, authenticatePusher, reauthenticatePusher, diff --git a/src/libs/actions/setSessionLoadingAndError.js b/src/libs/actions/setSessionLoadingAndError.js new file mode 100644 index 000000000000..38da93c58830 --- /dev/null +++ b/src/libs/actions/setSessionLoadingAndError.js @@ -0,0 +1,10 @@ +import Onyx from 'react-native-onyx'; +import ONYXKEYS from '../../ONYXKEYS'; + +/** + * @param {Boolean} loading + * @param {String} error + */ +export default function setSessionLoadingAndError(loading, error) { + Onyx.merge(ONYXKEYS.SESSION, {loading, error}); +} diff --git a/src/libs/actions/updateSessionAuthTokens.js b/src/libs/actions/updateSessionAuthTokens.js new file mode 100644 index 000000000000..4e49878be1ce --- /dev/null +++ b/src/libs/actions/updateSessionAuthTokens.js @@ -0,0 +1,10 @@ +import Onyx from 'react-native-onyx'; +import ONYXKEYS from '../../ONYXKEYS'; + +/** + * @param {String} authToken + * @param {String} encryptedAuthToken + */ +export default function updateSessionAuthTokens(authToken, encryptedAuthToken) { + Onyx.merge(ONYXKEYS.SESSION, {authToken, encryptedAuthToken}); +} From 4338b3007924d2f4512e71f710d1d5a662691b89 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 8 Nov 2021 12:42:17 -0500 Subject: [PATCH 08/10] update extensions --- .../actions/{Session.js => Session/index.js} | 36 +++++++++---------- .../setSessionLoadingAndError.js | 0 .../actions/{ => Session}/setShouldSignOut.js | 0 .../{ => Session}/updateSessionAuthTokens.js | 0 4 files changed, 18 insertions(+), 18 deletions(-) rename src/libs/actions/{Session.js => Session/index.js} (95%) rename src/libs/actions/{ => Session}/setSessionLoadingAndError.js (100%) rename src/libs/actions/{ => Session}/setShouldSignOut.js (100%) rename src/libs/actions/{ => Session}/updateSessionAuthTokens.js (100%) diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session/index.js similarity index 95% rename from src/libs/actions/Session.js rename to src/libs/actions/Session/index.js index e08dac6c61f7..0c16afb3b74a 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session/index.js @@ -2,24 +2,24 @@ import Onyx from 'react-native-onyx'; import Str from 'expensify-common/lib/str'; import _ from 'underscore'; import lodashGet from 'lodash/get'; -import ONYXKEYS from '../../ONYXKEYS'; -import redirectToSignIn from './SignInRedirect'; -import * as API from '../API'; -import CONFIG from '../../CONFIG'; -import Log from '../Log'; -import PushNotification from '../Notification/PushNotification'; -import Timing from './Timing'; -import CONST from '../../CONST'; -import Navigation from '../Navigation/Navigation'; -import ROUTES from '../../ROUTES'; -import {translateLocal} from '../translate'; -import * as Network from '../Network'; -import UnreadIndicatorUpdater from '../UnreadIndicatorUpdater'; -import Timers from '../Timers'; -import * as Pusher from '../Pusher/pusher'; -import NetworkConnection from '../NetworkConnection'; -import {getUserDetails} from './User'; -import {isNumericWithSpecialChars} from '../ValidationUtils'; +import ONYXKEYS from '../../../ONYXKEYS'; +import redirectToSignIn from '../SignInRedirect'; +import * as API from '../../API'; +import CONFIG from '../../../CONFIG'; +import Log from '../../Log'; +import PushNotification from '../../Notification/PushNotification'; +import Timing from '../Timing'; +import CONST from '../../../CONST'; +import Navigation from '../../Navigation/Navigation'; +import ROUTES from '../../../ROUTES'; +import {translateLocal} from '../../translate'; +import * as Network from '../../Network'; +import UnreadIndicatorUpdater from '../../UnreadIndicatorUpdater'; +import Timers from '../../Timers'; +import * as Pusher from '../../Pusher/pusher'; +import NetworkConnection from '../../NetworkConnection'; +import {getUserDetails} from '../User'; +import {isNumericWithSpecialChars} from '../../ValidationUtils'; let credentials = {}; Onyx.connect({ diff --git a/src/libs/actions/setSessionLoadingAndError.js b/src/libs/actions/Session/setSessionLoadingAndError.js similarity index 100% rename from src/libs/actions/setSessionLoadingAndError.js rename to src/libs/actions/Session/setSessionLoadingAndError.js diff --git a/src/libs/actions/setShouldSignOut.js b/src/libs/actions/Session/setShouldSignOut.js similarity index 100% rename from src/libs/actions/setShouldSignOut.js rename to src/libs/actions/Session/setShouldSignOut.js diff --git a/src/libs/actions/updateSessionAuthTokens.js b/src/libs/actions/Session/updateSessionAuthTokens.js similarity index 100% rename from src/libs/actions/updateSessionAuthTokens.js rename to src/libs/actions/Session/updateSessionAuthTokens.js From 4982731aca8e2295cd69ee73805a228fd5d26f2b Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 8 Nov 2021 12:46:58 -0500 Subject: [PATCH 09/10] fix more bad import statements --- src/libs/API.js | 4 ++-- src/libs/SignoutManager.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/API.js b/src/libs/API.js index 8ffda9496829..f0cce0e94fc2 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -9,8 +9,8 @@ import isViaExpensifyCashNative from './isViaExpensifyCashNative'; import requireParameters from './requireParameters'; import Log from './Log'; import * as Network from './Network'; -import updateSessionAuthTokens from './actions/updateSessionAuthTokens'; -import setSessionLoadingAndError from './actions/setSessionLoadingAndError'; +import updateSessionAuthTokens from './actions/Session/updateSessionAuthTokens'; +import setSessionLoadingAndError from './actions/Session/setSessionLoadingAndError'; let isAuthenticating; let credentials; diff --git a/src/libs/SignoutManager.js b/src/libs/SignoutManager.js index 71d9a0168b00..65c07e07c29a 100644 --- a/src/libs/SignoutManager.js +++ b/src/libs/SignoutManager.js @@ -1,7 +1,7 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; import createCallback from './createCallback'; -import setShouldSignOut from './actions/setShouldSignOut'; +import setShouldSignOut from './actions/Session/setShouldSignOut'; const [signoutCallback, registerSignoutCallback] = createCallback(); From 13e72e58681c3c27801cd01f15096c9b965fd347 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 8 Nov 2021 12:48:46 -0500 Subject: [PATCH 10/10] fix more imports --- src/libs/actions/Session/setSessionLoadingAndError.js | 2 +- src/libs/actions/Session/setShouldSignOut.js | 2 +- src/libs/actions/Session/updateSessionAuthTokens.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Session/setSessionLoadingAndError.js b/src/libs/actions/Session/setSessionLoadingAndError.js index 38da93c58830..e28b7613994c 100644 --- a/src/libs/actions/Session/setSessionLoadingAndError.js +++ b/src/libs/actions/Session/setSessionLoadingAndError.js @@ -1,5 +1,5 @@ import Onyx from 'react-native-onyx'; -import ONYXKEYS from '../../ONYXKEYS'; +import ONYXKEYS from '../../../ONYXKEYS'; /** * @param {Boolean} loading diff --git a/src/libs/actions/Session/setShouldSignOut.js b/src/libs/actions/Session/setShouldSignOut.js index ca3855b3b024..75acc853e873 100644 --- a/src/libs/actions/Session/setShouldSignOut.js +++ b/src/libs/actions/Session/setShouldSignOut.js @@ -1,5 +1,5 @@ import Onyx from 'react-native-onyx'; -import ONYXKEYS from '../../ONYXKEYS'; +import ONYXKEYS from '../../../ONYXKEYS'; /** * @param {Boolean} shouldSignOut diff --git a/src/libs/actions/Session/updateSessionAuthTokens.js b/src/libs/actions/Session/updateSessionAuthTokens.js index 4e49878be1ce..5be53c77a92c 100644 --- a/src/libs/actions/Session/updateSessionAuthTokens.js +++ b/src/libs/actions/Session/updateSessionAuthTokens.js @@ -1,5 +1,5 @@ import Onyx from 'react-native-onyx'; -import ONYXKEYS from '../../ONYXKEYS'; +import ONYXKEYS from '../../../ONYXKEYS'; /** * @param {String} authToken