-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Immediately remove messages flagged as assault or harassment #20223
Conversation
I did notice a small issue which should probably be fixed. Although I'm successfully hiding the message in the chat, it's still showing up in the LHN from the report.lastMessageText, as you can see in the offline test video. It would also show up on the search or new chat page. I'll leave it up to you guys whether we need to fix that before merging this. I could write some hacky code here in App to use the previous action message if the latest action is pendingRemove, or I could fix it in Web-Expensify. I'm not sure what's best but I would like to do it in a follow up so we can get the majority of this feature done in time. |
@abdulrahuman5196 @roryabraham One of you needs to 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] |
@neil-marcellini I don't have access to auth PR mentioned in the tests, Do we need to wait for it to merge for testing this PR? |
@abdulrahuman5196 Yeah, you won't be able to do the full tests until the auth PR is deployed (happening later today), but this should work locally/offline. Like if you flag a message as assault it should be hidden |
I just realized we don't need to hold this on the Auth deploy. It won't break anything without the Auth changes, but it won't work until the Auth changes are deployed. |
Ok @thienlnam @dangrous @roryabraham this is ready for review now. The Auth PR is merged but isn't on production quite yet. It should be soon and I'll try to comment here once it's deployed. |
const allReportActions = {}; | ||
const allSortedReportActions = {}; | ||
Onyx.connect({ | ||
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, | ||
callback: (actions, key) => { | ||
if (!key || !actions) { | ||
return; | ||
} | ||
allReportActions[key] = actions; | ||
const sortedReportActions = ReportActionUtils.getSortedReportActions(_.toArray(actions), true); | ||
const reportID = CollectionUtils.extractCollectionItemID(key); | ||
lastReportActions[reportID] = _.last(_.toArray(actions)); | ||
allSortedReportActions[reportID] = sortedReportActions; | ||
lastReportActions[reportID] = _.first(sortedReportActions); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised this doesn't impact any other methods here, there isn't any place that uses allReportActions???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also how come the change to lastReportActions? It doesn't seem like it is used in any of your changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah a couple things were surprising when I started looking at this, as you mentioned.
- allReportActions was unused (idk why lint didn't catch that)
- lastReportActions were not actually the "last" report actions for each report. They don't come pre-sorted in the object, they need to be sorted as we do on the ReportScreen with getSortedReportActions. I figured I should fix that while I'm making changes.
src/libs/OptionsListUtils.js
Outdated
|
||
// Yeah this is a bit ugly. If the latest report action that is not a whisper has been moderated as pending remove, then set the last message text to the text of the latest visible action that is not a whisper. | ||
const lastNonWhisper = | ||
_.find(allSortedReportActions[report.reportID], (action) => { | ||
const isWhisper = (action.whisperedTo || []).length > 0; | ||
return !isWhisper; | ||
}) || {}; | ||
if (lodashGet(lastNonWhisper, 'message[0].moderationDecisions[0].decision') === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE) { | ||
const latestVisibleAction = | ||
_.find(allSortedReportActions[report.reportID], (action) => { | ||
const isWhisper = (action.whisperedTo || []).length > 0; | ||
return ReportActionUtils.shouldReportActionBeVisible(action, action.reportActionID) && !isWhisper; | ||
}) || {}; | ||
lastMessageTextFromReport = lodashGet(latestVisibleAction, 'message[0].text', ''); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now, we're doing this for every report.
Since this flow is not the main flow can we update the logic so that by default, we don't look for the last non whisper unless we have to?
So basically
Check the last action had a moderation decision
If not, proceed as normal
Otherwise, find the last visible reportAction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to check the last action that is not a whisper, because otherwise we're looking to see if the whisper is moderated which will always be false.
_.find will stop as soon as it finds a non whisper action, so it's only going to look through n actions where n is the number of whispers in a row from the latest action moving back in time. I think that's ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yeah, I guess there isn't a great way to avoid this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one last comment, but rest looks good
src/libs/OptionsListUtils.js
Outdated
|
||
// Yeah this is a bit ugly. If the latest report action that is not a whisper has been moderated as pending remove, then set the last message text to the text of the latest visible action that is not a whisper. | ||
const lastNonWhisper = | ||
_.find(allSortedReportActions[report.reportID], (action) => { | ||
const isWhisper = (action.whisperedTo || []).length > 0; | ||
return !isWhisper; | ||
}) || {}; | ||
if (lodashGet(lastNonWhisper, 'message[0].moderationDecisions[0].decision') === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE) { | ||
const latestVisibleAction = | ||
_.find(allSortedReportActions[report.reportID], (action) => { | ||
const isWhisper = (action.whisperedTo || []).length > 0; | ||
return ReportActionUtils.shouldReportActionBeVisible(action, action.reportActionID) && !isWhisper; | ||
}) || {}; | ||
lastMessageTextFromReport = lodashGet(latestVisibleAction, 'message[0].text', ''); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yeah, I guess there isn't a great way to avoid this
const whisperedTo = lodashGet(props.action, 'whisperedTo', []); | ||
const whisperedTo = props.action.whisperedTo || []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lodash get is unnecessary here and this is faster and just as safe. Tim taught me that.
@thienlnam looks like this was merged without a test passing. Please add a note explaining why this was done and remove the |
My bad, forgot the checklist as I was on mobile but I did test this PR locally. @neil-marcellini could you please remove the label as I can't on mobile 🥲 |
I'm un-assigning @abdulrahuman5196 because we had to get this done quickly and so he wasn't able to test or review. |
Thank you for notifying. Good to have priority changed merged sooner. I was actually under the impression auth PR was going to be merged yesterday and I planned to test this PR today. Apologies if any delay from my end. |
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by https://github.com/thienlnam in version: 1.3.29-0 🚀
|
@neil-marcellini I think this may be causing this deploy blocker: #20940 |
Do you think we should implement a similar filter for the last report action in Auth: https://github.com/Expensify/Auth/blob/58d8c605f8d820bf6283fb98101798e05287aa26/auth/lib/Report.cpp#L4385-L4416 Right now it doesn't ignore the report action if it has been reported. |
Oh yeah, I think that's correct - we should mirror the change there. Let me know if you agree @neil-marcellini |
Yeah I think that would be better. @thienlnam discussed something like that previously but we decided to do the quick and dirty version on the front end. What problem is solved by doing the filtering on the backend? |
I'm not 100% sure, but it feels like the backend now calculates an incorrect version of the "last message" of a report which we use for LHN, and the front end has to correct it with the code front end code added. It just sounds dirtier to me, and harder to maintain because the last message in the report coming from the backend is not reliable anymore. |
Great explanation, I agree! |
I think this #20223 (comment) may be also causing that the I'll try to fix it in the backend. |
🚀 Deployed to production by https://github.com/luacmartins in version: 1.3.29-11 🚀
|
if (lodashGet(reportAction, 'message[0].moderationDecisions[0].decision') === CONST.MODERATION.MODERATOR_DECISION_PENDING_REMOVE) { | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we are hiding report actions that are pending remove. But didn't handle the same for threads. A report action can be threaded and if that report action is hidden so should the thread report. (Coming from #21497)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah nice catch!
const reportID = CollectionUtils.extractCollectionItemID(key); | ||
lastReportActions[reportID] = _.last(_.toArray(actions)); | ||
allSortedReportActions[reportID] = sortedReportActions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We never clean up allSortedReportActions
so it keeps gathering garbage between sessions. This confused me a lot since I was able to find reportActions that were not in Onyx. This is also a memory leak.
@neil-marcellini 🙏 fix
cc @thienlnam
Details
Now when you flag a message as assault or harassment it will be immediately removed from view. The message won't show in the chat, LHN, or on the search page.
Fixed Issues
$ https://github.com/Expensify/Expensify/issues/289225
PROPOSAL: N/A
Tests
First check out the corresponding Auth PR https://github.com/Expensify/Auth/pull/8058, build Auth and restart it.
Thanks for flagging that comment for the Expensify team to review. You will no longer see that message and the Expensify team will take the necessary steps to resolve the situation.
One of your messages has been flagged. I’ve hidden the message as a potential violation of Rule #2 (Don’t Ruin It For Everyone Else), and it will be reviewed. I will contact you when I have completed my review.
Offline tests
Same as the tests above, but go offline, flag the comment, then go back online.
Note: This doesn't match the normal offline behavior where the pending "delete" has a strikethrough style, but I think it's best to make an exception for this case because it's not exactly a delete, and more importantly if someone says something awful you want it gone right away, even if you're offline.
QA Steps
Same as tests.
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.src/languages/*
files and using the translation methodWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
I'm only testing on web because these changes are platform independent.
Web
Online
online.mov
Offline
offline.mov
Mobile Web - Chrome
Mobile Web - Safari
Desktop
iOS
Android