Skip to content

Added Permission check before setting Preferred Language#5943

Closed
parasharrajat wants to merge 5 commits into
Expensify:mainfrom
parasharrajat:language-beta
Closed

Added Permission check before setting Preferred Language#5943
parasharrajat wants to merge 5 commits into
Expensify:mainfrom
parasharrajat:language-beta

Conversation

@parasharrajat

Copy link
Copy Markdown
Member

Details

Fixed Issues

$ #5286

Tests | QA Steps

  1. Launch the app
  2. Log in with an account which is Spanish (expensifail domain account)
  3. Log out from account
  4. Log in with an account which is English (Expensifail or gmail account)
  5. Go to Settings
  6. Check the language of the app

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Screenshots

Web

Mobile Web

Desktop

iOS

Android

@parasharrajat parasharrajat marked this pull request as ready for review October 19, 2021 15:04
@parasharrajat parasharrajat requested a review from a team as a code owner October 19, 2021 15:04
@MelvinBot MelvinBot removed the request for review from a team October 19, 2021 15:04
@botify botify requested a review from marcaaron October 19, 2021 15:04
@parasharrajat parasharrajat changed the title Added Permission check before setting Preferred Language [WIP] Added Permission check before setting Preferred Language Oct 19, 2021
.then(() => {
if (preferredLocale) {
// Betas are only present when user is Logined
if (Permissions.canUseInternationalization([]) && preferredLocale) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to review early. I wanted to have feedback on this piece of the code.

In reality, we don't have beta access when the user is logged out but I used this check instead of isDevelopment as it seems more meaningful.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah hmm not sure how isDevelopment relates here. I think if we are logging out it maybe makes sense to just clear the preferredLocale? Why are we trying to persist it? Maybe @iwiznia knows.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I have selected spanish locale and log out (or get logged out), then I want to see the login screen in spanish, not english. In any case it's fine to only check for the betas in the UI, if a user not on the beta sets the locale manually via developer console or something, then it's ok if the localization feature works for them,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Permissions.canUseInternationalization([]) internally also checks for isDevelopment.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can check for isDevelopment if we want, but I don't think it's necessary

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's needed. Otherwise, the user will be locked in one language. If we are not showing a LocalePicker on the login page in staging then the language should not change to Spanish at all after logout, if the logged-in user was using spanish.

We determine whether the locale picker is shown or not, is via beta permissions check so I have used the same here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this check is confusing. Calling canUseInternationalization passing an empty betas list is just a confusing way to check isDevelopment() in this case? I think we should completely remove this check from here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. It can be. I will test this way.

Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);
}
});
if (Permissions.canUseInternationalization(this.props.betas)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a race condition for a fresh login. How can we guarantee that this.props.betas is set? We are calling User.getBetas() after so surely this won't work.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here, we don't need to check for the betas here, let's only check when presenting the UI to change the language.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But, we need to check that. For example,

  • a user with beta access login, changed the language to Spanish.
  • He logs out.
  • Page is still in Spanish.
  • Now he logs in with another normal user without beta.
  • Langauge is set to Spanish but there is no option to change and this user speaks English.

This is the issue we are trying to solve with PR.

Well, yeah there is a race condition here. I look into it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an edge case we don't really care about in any scenario other than us testing things, so I think it's fine.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait, are you saying the issue we are fixing is an edge case? 😕

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes..... 🤭

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checked the issue (should've done it before) and yes, I think so. But not sure if that will be a problem for QA... I guess not because they can still log in to an account with the beta, change the language to english then log out and log in with the gmail account which is not in the beta.

.then(() => {
if (preferredLocale) {
// Betas are only present when user is Logined
if (Permissions.canUseInternationalization([]) && preferredLocale) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah hmm not sure how isDevelopment relates here. I think if we are logging out it maybe makes sense to just clear the preferredLocale? Why are we trying to persist it? Maybe @iwiznia knows.

Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);
}
});
if (Permissions.canUseInternationalization(this.props.betas)) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking to get some help in choosing the right technique for removing the race condition.

  1. Create a key ONYXKEYS.IS_LOADING_BETAS set to false when beta is loaded.
  2. When this is set to true, run the above logic.

Subscribing to Onyx.beta here seems unnecessary to me as we only want to run one thing once. so I can abstract this code to a separate function and use Onyx.connect in the local scope.

What do you say? @marcaaron

@parasharrajat parasharrajat changed the title [WIP] Added Permission check before setting Preferred Language Added Permission check before setting Preferred Language Oct 30, 2021
@parasharrajat

parasharrajat commented Oct 30, 2021

Copy link
Copy Markdown
Member Author

This is ready for review.

Currently, I have used the Onyx approach for unlocking the race conditions as we are following a rule that actions should not have then chains #6093.

But I will argue that using a then on User.getBetas() will be optimal here. Thus I can create an action getBetasAndSetPreferredLocale which handles both things getting betas and then setting the locale. Please let me know how do we want it to be?

@parasharrajat

Copy link
Copy Markdown
Member Author

I think the getBetasAndSetPreferredLocale approach is better thus I have updated the code with that approach.

If you want to see the Onyx approach, then see the second last commit d8d4417 (#5943) .

@iwiznia iwiznia left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I got lost on what we are trying to do on this PR... 😕

.then(() => {
if (preferredLocale) {
// Betas are only present when user is Logined
if (Permissions.canUseInternationalization([]) && preferredLocale) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this check is confusing. Calling canUseInternationalization passing an empty betas list is just a confusing way to check isDevelopment() in this case? I think we should completely remove this check from here

PersonalDetails.fetchPersonalDetails();
User.getUserDetails();
User.getBetas();
User.fetchBetasAndSetPreferredLocale(this.props.preferredLocale);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get why we are setting the preferredLocale here, the user is logging in, their locale can't change in this flow.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify this for me? I didn't get it.

I think, if the user does not have access to betas then we don't want the language to be changed from En as the locale is a beta feature.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify this for me? I didn't get it.

I don't get why we need to set a locale here nor where the value from the locale will come. The only place where the user can set the locale is from the preferences page, no?

I think, if the user does not have access to betas then we don't want the language to be changed from En as the locale is a beta feature.

The way I see it, regardless of the beta, the locale should be what's in preferred locale or english if nothing is set in preferred locale.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, the locale is picked from Onyx if the user has set a locale from the login page picker.
image

I am following the existing code. Just added a check for beta so that we can break the loop if the user does not have localization beta access.

The way I see it, regardless of the beta, the locale should be what's in preferred locale or english if nothing is set in the preferred locale.

Yup, it does but with one exception that it also picks the locale preference from the login page.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we kill the login page language selection , would that mean we can remove this?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we will have to remove the extra code.

Comment thread src/libs/actions/User.js
* Fetches betas and User's preferred Locale, then set the app locale.
* @param {String} currentPreferredLocale
*/
function fetchBetasAndSetPreferredLocale(currentPreferredLocale) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having trouble figuring out why we are combining these. It's not obvious from looking at the code so I don't think it's the right solution to the problem.

If I'm understanding correctly, there is some race condition where we want to "set preferred locale" but only if we are on the beta and the betas have not loaded yet...?

This seems very easy to fix at the API layer by just returning the preferred locale if the user is on the beta and do the check in the server. So basically have something like API.User_GetPreferredLocale() and then this would become:

API.User_GetPreferredLocale()
    .then(({preferredLocale}) => {
        Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);    
    });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another POV is that we should never prevent getting or setting this NVP depending on the beta.
But in order to use it we should have the correct beta.

Comment thread src/libs/actions/User.js
) {
setLocale(currentPreferredLocale);
} else {
Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between setLocale() and Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, value) 🤔 ?

@marcaaron marcaaron left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe it would be better handle some things at the API layer than combine "get betas" and "get preferred locale" into one synchronous check. That will set up a weird practice where anything that requires the beta to load first will need be put into the "wait for the betas" method.

@marcaaron

Copy link
Copy Markdown
Contributor

unlocking the race conditions as we are following a rule that actions should not have then chains

Heh I'm not sure this is the right interpretation of that rule. We still do not want to encourage promise chains or time dependent code. Anything that can happen in parallel should happen in parallel.

What is the race condition? I've seen it mentioned a few times, but don't have a good understanding of what it is.

@parasharrajat

Copy link
Copy Markdown
Member Author

I will follow up on each comment one by one shortly. But looking at the comments I think we need to discuss a solution before jumping on the implementation.

@parasharrajat

Copy link
Copy Markdown
Member Author

Ok, things are moving fast #6177 is also trying to fix this. But looks like in a good way.

@parasharrajat

Copy link
Copy Markdown
Member Author

Now, I think we don't need the changes hereafter https://github.com/Expensify/App/pull/6177/files.
Please let me know what should I do next?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants