Skip to content
This repository has been archived by the owner. It is now read-only.

fix(avatars): when Undefined an error promise will return #4502

Merged
merged 1 commit into from Dec 16, 2016

Conversation

@divyabiyani
Copy link
Member

@divyabiyani divyabiyani commented Dec 14, 2016

fixes #4386.

@divyabiyani divyabiyani changed the title fix(displayedProfileImage): When Undefined an error promise will return [WIP]:fix(displayedProfileImage): When Undefined an error promise will return Dec 14, 2016
@divyabiyani divyabiyani force-pushed the divyabiyani:issue-4386 branch from 4744c18 to ecacd67 Dec 14, 2016
@divyabiyani divyabiyani changed the title [WIP]:fix(displayedProfileImage): When Undefined an error promise will return fix(displayedProfileImage): When Undefined an error promise will return Dec 14, 2016
Copy link
Member

@shane-tomlinson shane-tomlinson left a comment

Thanks for this PR @divyabiyani! I left a giant comment inline about what I believe the correct fix should be.

@@ -163,6 +163,9 @@ define(function (require, exports, module) {
},

deleteDisplayedAccountProfileImage (account) {
if ( ! this._displayedProfileImage ) {

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Dec 14, 2016
Member

It seems to me this solution sidesteps the problem but does not fix the cause of the problem, which seems to be inconsistent state. deleteDisplayedAccountProfileImage is called from removeAvatar in avatar_change.js. removeAvatar can only be called if we believe the account has a profile image. hasProfileImage is set if the account has a profileImageUrl.

So, we believe the account has a profileImageUrl, but this._displayedProfileImage is undefined, which means the assignment to this._displayedProfileImage has not been made.

This can happen because displayAccountProfileImage is called in avatar_change.js->afterVisible. afterVisible is called after the view is already visible (with the Clear button shown to the user), this means there is a window in which the user can click the Clear button before the profile image is fetched, and before this._displayedProfileImage is set.

This behavior was introduced in #3850 to fix #3543.

We are using the cached data in this._displayedProfileImage to get the profile image ID. The image ID should already be available on the account model, which is passed in to this function.

I believe the correct fix here is to not log and display the error you added here, but rather:

  1. Use the image ID from the account model. If there is no image ID on the account model, THEN log and display an error.

OR

  1. Ensure this._displayedProfileImage is set by calling this.displayAccountProfileImage(account) and then deleting the avatar whenever that function call completes.

We might have to try both approaches to see which works best.

@@ -45,6 +45,10 @@ define(function (require, exports, module) {
UNEXPECTED_ERROR: {
errno: 999,
message: t('Unexpected error')
},
NO_DISPLAYED_PROFILEIMAGE_FOUND: {
errno: 1049,

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Dec 14, 2016
Member

For any error that you add to a module, please use consecutive numbers, so this would be 1000. Errno's in each module are namespaced appropriately in our logs so we can tell the difference between errno 1000 in profile-errors and errno 1000 in auth-errors.

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Dec 14, 2016
Member

Also, I imagine in the end this won't be the error used. Instead it'll be something like NO_PROFILE_IMAGE_ID

},
NO_DISPLAYED_PROFILEIMAGE_FOUND: {
errno: 1049,
message: t('No Displayed Profile Image')

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Dec 14, 2016
Member

Please sentence case any errors, so the only word with a capital letter will be No

This comment has been minimized.

@divyabiyani

divyabiyani Dec 14, 2016
Author Member

Ohk @shane-tomlinson .
I will do the necessary changes.

@divyabiyani divyabiyani changed the title fix(displayedProfileImage): When Undefined an error promise will return [WIP]:fix(displayedProfileImage): When Undefined an error promise will return Dec 14, 2016
@GitCop
Copy link

@GitCop GitCop commented Dec 14, 2016

There were the following issues with your Pull Request

  • Commit: 1c87647
  • Your subject line is longer than 100 characters

Guidelines are available at https://github.com/mozilla/fxa-content-server/blob/master/CONTRIBUTING.md#git-commit-guidelines


This message was auto-generated by https://gitcop.com

@@ -96,7 +97,7 @@ define(function (require, exports, module) {
avatarWrapperEl.addClass('with-default');
},

// Makes sure the account has an up-to-date image cache.
// Makes sure the account has an up-to-date image casche.

This comment has been minimized.

@vladikoff

vladikoff Dec 14, 2016
Contributor

what happened here?

@vladikoff
Copy link
Contributor

@vladikoff vladikoff commented Dec 14, 2016

@divyabiyani if we go with using displayAccountProfileImage, we need to keep in mind that it is async. you need to chain .then see https://github.com/mozilla/fxa-content-server/pull/4502/files#diff-69c1b4c151f87a5c9ad048f78656cf9aR73

Also do we only call it when _displayedProfileImage is undefined?

cc @shane-tomlinson

@divyabiyani divyabiyani force-pushed the divyabiyani:issue-4386 branch from 9d8c3c7 to f6a9344 Dec 14, 2016
@shane-tomlinson
Copy link
Member

@shane-tomlinson shane-tomlinson commented Dec 14, 2016

Also do we only call it when _displayedProfileImage is undefined?

I'd say yes, or rather, a similar approach using the image ID from the account. I'd use the image ID from the account and only fetch the profile image if the account doesn't have an image ID already.

Rationale is - something about storing and relying on _displayedProfileImage seems fishy if the account already has an image ID. The only two places _displayedProfileImage is used is in deleteDisplayedAccountProfileImage which already accepts an account that should have the profile image ID, and in hasDisplayedAccountProfileImage which is not used anywhere:

➜  scripts git:(master) pwd
/Users/stomlinson/development/fxa-content-server/app/scripts
➜  scripts git:(master) rgrep hasDisplayedAccountProfileImage .  
./views/mixins/avatar-mixin.js:    hasDisplayedAccountProfileImage () {
➜  scripts git:(master)

To me it seems the optimal fix/cleanup is:

  1. Remove hasDisplayedAccountProfileImage and any associated tests. It's not used. No use keeping it in the code base.
  2. Use the profile image ID from the account. If the account doesn't have an image ID, then fetch it.
  3. In avatar-mixin.js, remove all references to this._displayedProfileImage, including the assignment. We would be getting the profile image data directly from the account and would not need the local reference. This makes us have 1 source of truth, which is (almost) always better than > 1.
@vladikoff vladikoff changed the title [WIP]:fix(displayedProfileImage): When Undefined an error promise will return [WIP] fix(avatars): when Undefined an error promise will return Dec 14, 2016
@vladikoff
Copy link
Contributor

@vladikoff vladikoff commented Dec 14, 2016

@divyabiyani see comment above ^, let us know if something is not clear.

Try running git rebase origin/master to fetch latest updates of the repository. Let me know if there are issues.

@GitCop
Copy link

@GitCop GitCop commented Dec 15, 2016

There were the following issues with your Pull Request

  • Commit: f6a9344
  • Your subject line is longer than 100 characters
  • Invalid type. Valid types are feat, fix, docs, style, refactor, perf, test, chore, revert

Guidelines are available at https://github.com/mozilla/fxa-content-server/blob/master/CONTRIBUTING.md#git-commit-guidelines


This message was auto-generated by https://gitcop.com

@divyabiyani divyabiyani force-pushed the divyabiyani:issue-4386 branch from e21c18d to a488e5f Dec 15, 2016
@divyabiyani divyabiyani changed the title [WIP] fix(avatars): when Undefined an error promise will return fix(avatars): when Undefined an error promise will return Dec 16, 2016
this.updateProfileImage(new ProfileImage(), account);
});
if ( ! account.get('profileImageId') ) {
return account.fetchCurrentProfileImage()

This comment has been minimized.

@shane-tomlinson

shane-tomlinson Dec 16, 2016
Member

This looks like the proper solution. I'm going to propose a slight simplification that reworks lines 161-182 to use promise chaining and eliminate duplicate code but still Do The Right Thing.

return p().then(() => {
  if (! account.get('profileImageId')) {
    return account.fetchCurrentProfileImage()
      .then((profileImage) => {
        // Cache the result to make sure we don't flash the default
        // image while fetching the latest profile image
        // this should set the profileImageId on the account.
        this._updateCachedProfileImage(profileImage, account);
      });
  }
  // if we reach here, the account has a profile image ID already.
})
// by this point, the account will have an avatar and a profileImageId
.then(() => account.deleteAvatar(account.get('profileImageId')))
.then(() => this.updateProfileImage(new ProfileImage(), account));

Do you have much experience with promises? If not, they are a bit strange to get used to, but once you do, they are pretty great. A good intro is: https://developers.google.com/web/fundamentals/getting-started/primers/promises

This comment has been minimized.

@divyabiyani

divyabiyani Dec 16, 2016
Author Member

@shane-tomlinson Hi, I have been studying about promises from past few days. @vladikoff gave me the intro link. 😄
Also, is the code fine now?

@divyabiyani divyabiyani force-pushed the divyabiyani:issue-4386 branch 2 times, most recently from 70b0bc1 to 8dd2e2c Dec 16, 2016
return account.deleteAvatar(this._displayedProfileImage.get('id'))
return p()
.then(() => {
if ( ! account.get('profileImageId') ) {

This comment has been minimized.

@vladikoff

vladikoff Dec 16, 2016
Contributor

review nit: no space before ! or here account.get('profileImageId') ) .

Remove the space before the last parenthesis.

@pdehaan is there an ESlint rule that can help us track these?

@@ -87,10 +86,6 @@ define(function (require, exports, module) {
});
},

hasDisplayedAccountProfileImage () {
return this._displayedProfileImage && ! this._displayedProfileImage.isDefault();
},

This comment has been minimized.

@vladikoff

vladikoff Dec 16, 2016
Contributor

@divyabiyani nice 👍

@divyabiyani divyabiyani force-pushed the divyabiyani:issue-4386 branch from 15f12fa to 3a8be1d Dec 16, 2016
@vladikoff vladikoff merged commit 3f4ec6f into mozilla:master Dec 16, 2016
3 checks passed
3 checks passed
ci/circleci Your tests passed on CircleCI!
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls Coverage decreased (-0.04%) to 98.599%
Details
@vladikoff
Copy link
Contributor

@vladikoff vladikoff commented Dec 16, 2016

Great work @divyabiyani !

@divyabiyani divyabiyani deleted the divyabiyani:issue-4386 branch Dec 18, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

5 participants