Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HOLD for payment 2024-01-24] Refactor and Fix Attachment Handling in File Download and Carousel #31791

Conversation

kidroca
Copy link
Contributor

@kidroca kidroca commented Nov 23, 2023

Details

Pull Request Description

This pull request introduces several changes aimed at improving the handling of attachments in file download processes and the Attachment Carousel component. The key changes are as follows:

  1. Refactor libs/FileUtils: The function getAttachmentName has been removed. It has been replaced by getFileName, which extracts and sanitizes filenames from URLs for filesystem usage. This new function decodes the URL segment, replaces illegal characters with underscores, and includes logging for cases where the filename cannot be determined.

  2. Fix in libs/fileDownload: Modifications have been made to ensure there is a reachable fallback for filenames. This includes changes in various platform-specific files (index.android.ts, index.ios.ts, index.ts) to utilize getFileName for generating fallback filenames when necessary.

  3. Update in AttachmentCarousel: The CarouselItem component now uses the source URL for fallback file names. This change is reflected in extractAttachmentsFromReport.js, where the source and filename are determined based on either the provided attributes or the fallback logic.

  4. PropTypes Enhancements: In AttachmentCarousel/CarouselItem.js and Attachments/propTypes.js, the file property within the attachment prop types has been updated to be required, ensuring better type safety and clarity in the component's expected data structure.

Technical Details:

  • Files Affected:
    • AttachmentCarousel/CarouselItem.js
    • Attachments/propTypes.js
    • AttachmentCarousel/extractAttachmentsFromReport.js
    • fileDownload/FileUtils.ts
    • fileDownload/index.android.ts
    • fileDownload/index.ios.ts
    • fileDownload/index.ts

The changes aim to enhance the robustness of attachment handling, ensuring filenames are correctly determined and handled across different components and platforms. Additionally, the update in PropTypes enforces stricter type checking, contributing to the overall reliability of the components.

Fixed Issues

$ #30931
PROPOSAL: #30931 (comment)

Tests

Case 1 - Concierge Drag & Drop Attachments

Objective: Ensure attachments added by Concierge through Drag & Drop are downloadable across platforms.

Prerequisites: A chat session with Concierge.

General:
  • Initiate a chat with Concierge.
  • Request Concierge to send inline image attachments using the Drag & Drop method.
On Web / Desktop:
  • Click on any of the received attachments.
  • Click the Download button located in the upper right corner.
    • Note: Since the attachment is sourced directly from Amazon S3 (which is a different origin), it will not directly download but will open in a new browser tab/window.
On iOS / Android (a regression prevents testing this flow in the current PR):
  • Tap on any of the received attachments.
  • Tap the Download button located in the upper right corner.
  • Observation: Unlike web platforms, native apps are unaffected by CORS. As such, the attachment should download directly to the device.

Case 2 - File Names Compliance

Objective: Verify that downloaded file names adhere to the specified naming conventions.

General:
  • Utilize the files downloaded in Case 1 for this test.
Naming Rules Verification:
  1. For files with original names:

    • Ensure the downloaded file's name retains its original name, with the download datetime appended.
    • Example:
      • Original name: sample.pdf.
      • Expected download name: sample-2023-11-29 17_42_33.461.pdf.
    • Note: Replace colons (:) in datetime with underscores (_) as colons are not permitted in filenames.
    • Note: original file name is the name of the file on sender's device at the time they select it for upload
  2. For files without original names (e.g., Concierge Drag & Drop attachments):

    • Confirm that the file name is derived from its URL, with the download datetime appended.
    • Example:
      • URL: https://s3-us-west-1.amazonaws.com/concierge-responses-expensify-com/uploads%2F1676033736079-1676033736079.png.
      • Expected download name: uploads_F1676033736079-1676033736079-2023-11-29 17_44_14.113.png.

Case 3 - Prop-Type Warnings for Attachment Carousel

Objective: Ensure there are no prop-type warnings in the console related to file names when opening attachments in the attachment carousel.

General Procedure:
  1. Interaction with Various Attachments:

    • Engage in different chat scenarios:
      • Chat with Concierge and open attachments that were added through drag and drop.
      • Open attachments in regular or group chats.
    • For each scenario, focus on opening a variety of attachment types.
  2. Observation in Attachment Carousel:

    • After the attachment carousel opens, inspect the browser's console logs.
    • Look specifically for any prop-type warnings related to file names.
Expected Outcome:
  • There should be no warnings in the console regarding missing or incorrect file names for any attachments opened in the carousel.
  • Ensure that the test covers a diverse set of attachment types to verify the robustness of the implementation.

Offline tests

N/A - attachments cannot be downloaded while offline

QA Steps

The following tests are applicable to both staging and production

Case 1 - Concierge Drag & Drop Attachments

Objective: Ensure attachments added by Concierge through Drag & Drop are downloadable across platforms.

Prerequisites: A chat session with Concierge.

General:
  • Initiate a chat with Concierge.
  • Request Concierge to send inline image attachments using the Drag & Drop method.
On Web / Desktop:
  • Click on any of the received attachments.
  • Click the Download button located in the upper right corner.
    • Note: Since the attachment is sourced directly from Amazon S3 (which is a different origin), it will not directly download but will open in a new browser tab/window.
On iOS / Android (a regression prevents testing this flow in the current PR):
  • Tap on any of the received attachments.
  • Tap the Download button located in the upper right corner.
  • Observation: Unlike web platforms, native apps are unaffected by CORS. As such, the attachment should download directly to the device.

Case 2 - File Names Compliance

Objective: Verify that downloaded file names adhere to the specified naming conventions.

General:
  • Utilize the files downloaded in Case 1 for this test.
Naming Rules Verification:
  1. For files with original names:

    • Ensure the downloaded file's name retains its original name, with the download datetime appended.
    • Example:
      • Original name: sample.pdf.
      • Expected download name: sample-2023-11-29 17_42_33.461.pdf.
    • Note: Replace colons (:) in datetime with underscores (_) as colons are not permitted in filenames.
    • Note: original file name is the name of the file on sender's device at the time they select it for upload
  2. For files without original names (e.g., Concierge Drag & Drop attachments):

    • Confirm that the file name is derived from its URL, with the download datetime appended.
    • Example:
      • URL: https://s3-us-west-1.amazonaws.com/concierge-responses-expensify-com/uploads%2F1676033736079-1676033736079.png.
      • Expected download name: uploads_F1676033736079-1676033736079-2023-11-29 17_44_14.113.png.

Case 3 - Prop-Type Warnings for Attachment Carousel

Objective: Ensure there are no prop-type warnings in the console related to file names when opening attachments in the attachment carousel.

General Procedure:
  1. Interaction with Various Attachments:

    • Engage in different chat scenarios:
      • Chat with Concierge and open attachments that were added through drag and drop.
      • Open attachments in regular or group chats.
    • For each scenario, focus on opening a variety of attachment types.
  2. Observation in Attachment Carousel:

    • After the attachment carousel opens, inspect the browser's console logs.
    • Look specifically for any prop-type warnings related to file names.
Expected Outcome:
  • There should be no warnings in the console regarding missing or incorrect file names for any attachments opened in the carousel.
  • Ensure that the test covers a diverse set of attachment types to verify the robustness of the implementation.

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that the left part of a conditional rendering a React component is a boolean and NOT a string, e.g. myBool && <MyComponent />.
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I verified the translation was requested/reviewed in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG))
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native

image

Android: mWeb Chrome

image

iOS: Native Screenshot 2023-12-01 at 22 09 47
iOS: mWeb Safari Screenshot 2023-12-01 at 22 18 15
MacOS: Chrome / Safari Screenshot 2023-12-01 at 22 08 32
MacOS: Desktop Screenshot 2023-12-01 at 16 46 37

Some bugs can be caught earlier if we're warned when `file` or `file.name` is missing
@kidroca kidroca marked this pull request as ready for review November 23, 2023 19:15
@kidroca kidroca requested a review from a team as a code owner November 23, 2023 19:15
@melvin-bot melvin-bot bot requested review from aimane-chnaif and removed request for a team November 23, 2023 19:15
Copy link

melvin-bot bot commented Nov 23, 2023

@aimane-chnaif Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

Introduce getFileName in FileUtils to generate fallback names for attachments lacking original file names. This function extracts and sanitizes filenames from URLs, ensuring attachments in AttachmentCarousel have meaningful names even when original names are missing.

Updated AttachmentCarousel to utilize this new utility function.

At this time, the only know case is embedded attachments shared by the Concierge account via drag and drop
Addressed a bug in libs/fileDownload where the intended fallback for filenames was never reached due to `FileUtils.appendTimeToFileName` always providing a return value. This fix refines the filename determination logic, ensuring effective use of fallback mechanisms across various components including AttachmentCarousel, particularly for cases like attachments shared by the Concierge account.
@kidroca kidroca force-pushed the kidroca/fix/regressions-related-to-file-downloads branch from 3c65733 to 1b58d05 Compare November 23, 2023 19:20
@kidroca
Copy link
Contributor Author

kidroca commented Nov 29, 2023

Update: added specific test steps

@aimane-chnaif
Copy link
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified tests pass on all platforms & I tested again on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that the left part of a conditional rendering a React component is a boolean and NOT a string, e.g. myBool && <MyComponent />.
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: Native
android.mov
Android: mWeb Chrome
mchrome.mov
iOS: Native
ios.mov
iOS: mWeb Safari
msafari.mov
MacOS: Chrome / Safari
web.mov
MacOS: Desktop
desktop.mov

@aimane-chnaif
Copy link
Contributor

@kidroca please complete author checklist. Some platform screenshots are still missing

@kidroca
Copy link
Contributor Author

kidroca commented Dec 1, 2023

@kidroca please complete author checklist. Some platform screenshots are still missing

✔️ Done

Copy link
Contributor

@aimane-chnaif aimane-chnaif left a comment

Choose a reason for hiding this comment

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

LGTM 🎉

@melvin-bot melvin-bot bot requested a review from NikkiWines December 1, 2023 20:22
@NikkiWines
Copy link
Contributor

@kidroca you've got conflicts

NikkiWines
NikkiWines previously approved these changes Dec 4, 2023
Copy link
Contributor

@NikkiWines NikkiWines left a comment

Choose a reason for hiding this comment

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

looks good aside from conflicts!

…loads

# Conflicts:
#	src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js
@kidroca
Copy link
Contributor Author

kidroca commented Dec 5, 2023

@kidroca you've got conflicts

  • ✔️ Conflicts resolved - synced with main
  • ✔️ Retested after syncing with main - All tests and checks have passed without any issues.

Copy link
Contributor

@NikkiWines NikkiWines left a comment

Choose a reason for hiding this comment

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

:shipit:

@NikkiWines NikkiWines merged commit 3915fb2 into Expensify:main Dec 5, 2023
16 checks passed
@kidroca kidroca deleted the kidroca/fix/regressions-related-to-file-downloads branch December 5, 2023 19:56
OSBotify pushed a commit that referenced this pull request Dec 6, 2023
…d-to-file-downloads

Refactor and Fix Attachment Handling in File Download and Carousel

(cherry picked from commit 3915fb2)
yuwenmemon added a commit that referenced this pull request Dec 6, 2023
…ng-31791-2

🍒 Cherry pick PR #31791 to staging 🍒
@OSBotify
Copy link
Contributor

OSBotify commented Dec 6, 2023

🚀 Deployed to staging by https://github.com/NikkiWines in version: 1.4.8-2 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

OSBotify commented Dec 6, 2023

🚀 Deployed to production by https://github.com/yuwenmemon in version: 1.4.8-3 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 failure ❌
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

OSBotify commented Dec 6, 2023

🚀 Deployed to production by https://github.com/yuwenmemon in version: 1.4.8-3 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@melvin-bot melvin-bot bot added Reviewing Has a PR in review Weekly KSv2 labels Jan 2, 2024
@melvin-bot melvin-bot bot added Weekly KSv2 Awaiting Payment Auto-added when associated PR is deployed to production and removed Weekly KSv2 labels Jan 17, 2024
@melvin-bot melvin-bot bot changed the title Refactor and Fix Attachment Handling in File Download and Carousel [HOLD for payment 2024-01-24] Refactor and Fix Attachment Handling in File Download and Carousel Jan 17, 2024
@melvin-bot melvin-bot bot removed the Reviewing Has a PR in review label Jan 17, 2024
Copy link

melvin-bot bot commented Jan 17, 2024

Reviewing label has been removed, please complete the "BugZero Checklist".

Copy link

melvin-bot bot commented Jan 17, 2024

The solution for this issue has been 🚀 deployed to production 🚀 in version 1.4.25-10 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

If no regressions arise, payment will be issued on 2024-01-24. 🎊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Weekly KSv2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants