From c9a48e3369e3841237f80f31b89d38fa36363d4f Mon Sep 17 00:00:00 2001 From: Matthew Riley MacPherson Date: Thu, 21 Sep 2017 12:59:52 +0100 Subject: [PATCH 1/2] fix: Report Abuse API should use body; not params (see #3197) --- src/core/api/abuse.js | 2 +- tests/unit/core/api/test_abuse.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/api/abuse.js b/src/core/api/abuse.js index 149a3248dfa..f6ef969a5cd 100644 --- a/src/core/api/abuse.js +++ b/src/core/api/abuse.js @@ -16,7 +16,7 @@ export function reportAddon( auth: true, endpoint: 'abuse/report/addon', method: 'POST', - params: { addon: addonSlug, message }, + body: { addon: addonSlug, message }, state: api, }); } diff --git a/tests/unit/core/api/test_abuse.js b/tests/unit/core/api/test_abuse.js index 713846b1c3f..07786cf0c62 100644 --- a/tests/unit/core/api/test_abuse.js +++ b/tests/unit/core/api/test_abuse.js @@ -34,7 +34,7 @@ describe(__filename, () => { auth: true, endpoint: 'abuse/report/addon', method: 'POST', - params: { addon: 'cool-addon', message }, + body: { addon: 'cool-addon', message }, state: apiState, }) .once() From 865800b44599b0ab89e4255d474546b4c19b3c55 Mon Sep 17 00:00:00 2001 From: Matthew Riley MacPherson Date: Thu, 21 Sep 2017 11:31:59 +0100 Subject: [PATCH 2/2] feat: Allow users to report an add-on for abuse fixes #2759 --- package.json | 1 + src/amo/components/AddonMoreInfo/index.js | 5 +- src/amo/components/ReportAbuseButton/index.js | 221 +++++++++++++ .../components/ReportAbuseButton/styles.scss | 62 ++++ src/core/css/inc/mixins.scss | 1 + src/core/reducers/abuse.js | 128 +++++++- src/core/sagas/abuse.js | 3 +- src/ui/components/Button/Button.scss | 6 +- .../amo/components/TestReportAbuseButton.js | 307 ++++++++++++++++++ tests/unit/core/reducers/test_abuse.js | 84 +++++ yarn.lock | 102 +++++- 11 files changed, 900 insertions(+), 20 deletions(-) create mode 100644 src/amo/components/ReportAbuseButton/index.js create mode 100644 src/amo/components/ReportAbuseButton/styles.scss create mode 100644 tests/unit/amo/components/TestReportAbuseButton.js diff --git a/package.json b/package.json index 0cfb383fc71..c1dee9d64a8 100644 --- a/package.json +++ b/package.json @@ -193,6 +193,7 @@ "react-redux-loading-bar": "2.9.2", "react-router": "2.8.1", "react-router-scroll": "0.4.2", + "react-textarea-autosize": "^5.1.0", "redux": "3.7.2", "redux-connect": "4.0.2", "redux-logger": "3.0.6", diff --git a/src/amo/components/AddonMoreInfo/index.js b/src/amo/components/AddonMoreInfo/index.js index 1fe13e98a87..f750b4cd3c5 100644 --- a/src/amo/components/AddonMoreInfo/index.js +++ b/src/amo/components/AddonMoreInfo/index.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { compose } from 'redux'; import Link from 'amo/components/Link'; +import ReportAbuseButton from 'amo/components/ReportAbuseButton'; import translate from 'core/i18n/translate'; import { trimAndAddProtocolToUrl } from 'core/utils'; import Card from 'ui/components/Card'; @@ -151,7 +152,7 @@ export class AddonMoreInfoBase extends React.Component { } render() { - const { i18n } = this.props; + const { addon, i18n } = this.props; return ( {this.listContent()} + + ); } diff --git a/src/amo/components/ReportAbuseButton/index.js b/src/amo/components/ReportAbuseButton/index.js new file mode 100644 index 00000000000..928f6a18459 --- /dev/null +++ b/src/amo/components/ReportAbuseButton/index.js @@ -0,0 +1,221 @@ +import classNames from 'classnames'; +import { oneLine } from 'common-tags'; +import React from 'react'; +import { connect } from 'react-redux'; +import Textarea from 'react-textarea-autosize'; +import { compose } from 'redux'; + +import { withErrorHandler } from 'core/errorHandler'; +import type { ErrorHandlerType } from 'core/errorHandler'; +import translate from 'core/i18n/translate'; +import log from 'core/logger'; +import { + disableAbuseButtonUI, + enableAbuseButtonUI, + hideAddonAbuseReportUI, + sendAddonAbuseReport, + showAddonAbuseReportUI, +} from 'core/reducers/abuse'; +import { sanitizeHTML } from 'core/utils'; +import Button from 'ui/components/Button'; + +import './styles.scss'; + + +type PropTypes = { + abuseReport: {| + message: string, + reporter: Object | null, + |}, + addon: Object | null, + dispatch: Function, + errorHandler: ErrorHandlerType, + loading: bool, + i18n: Object, +}; + +export class ReportAbuseButtonBase extends React.Component { + dismissReportUI = (event) => { + event.preventDefault(); + + const { addon, dispatch, loading } = this.props; + + if (loading) { + log.debug( + "Ignoring dismiss click because we're submitting the abuse report"); + return; + } + + dispatch(hideAddonAbuseReportUI({ addon })); + } + + sendReport = (event) => { + event.preventDefault(); + + // The button isn't clickable if there is no content, but just in case: + // we verify there's a message to send. + if (!this.textarea.value.length) { + log.debug(oneLine`User managed to click submit button while textarea + was empty. Ignoring this onClick/sendReport event.`); + return; + } + + const { addon, dispatch, errorHandler } = this.props; + + dispatch(sendAddonAbuseReport({ + addonSlug: addon.slug, + errorHandlerId: errorHandler.id, + message: this.textarea.value, + })); + } + + showReportUI = (event) => { + event.preventDefault(); + + const { addon, dispatch } = this.props; + + dispatch(showAddonAbuseReportUI({ addon })); + this.textarea.focus(); + } + + textareaChange = () => { + const { abuseReport, addon, dispatch } = this.props; + + // Don't dispatch the UI update if the button is already visible. + // We also test for `value.trim()` so the user can't submit an + // empty report full of spaces. + if (this.textarea.value.trim().length && !abuseReport.buttonEnabled) { + dispatch(enableAbuseButtonUI({ addon })); + } else if (!this.textarea.value.trim().length) { + dispatch(disableAbuseButtonUI({ addon })); + } + } + + props: PropTypes; + + render() { + const { abuseReport, addon, i18n, loading } = this.props; + + if (!addon) { + return null; + } + + if (abuseReport && abuseReport.message) { + return ( +
+

+ {i18n.gettext('You reported this add-on for abuse')} +

+ +

+ {i18n.gettext( + `We have received your report. Thanks for letting us know about + your concerns with this add-on.` + )} +

+ +

+ {i18n.gettext( + `We can't respond to every abuse report but we'll look into + this issue.` + )} +

+
+ ); + } + + const sendButtonIsDisabled = loading || !abuseReport.buttonEnabled; + + const prefaceText = i18n.sprintf(i18n.gettext( + `If you think this add-on violates + %(linkTagStart)sMozilla's add-on policies%(linkTagEnd)s or has + security or privacy issues, please report these issues to Mozilla using + this form.` + ), { + linkTagStart: '', + linkTagEnd: '', + }); + + /* eslint-disable react/no-danger */ + return ( +
+
+ +
+ +
+

+ {i18n.gettext('Report this add-on for abuse')} +

+ +

+ +

{i18n.gettext( + `Please don't use this form to report bugs or request add-on + features; this report will be sent to Mozilla and not to the + add-on developer.` + )}

+