Index: trunk/extensions/ArticleFeedbackv5/ArticleFeedbackv5.i18n.php |
— | — | @@ -33,6 +33,9 @@ |
34 | 34 | 'articlefeedbackv5-error' => 'An error has occured. Please try again later.', |
35 | 35 | 'articlefeedbackv5-error-email' => 'That e-mail address is not valid.', |
36 | 36 | 'articlefeedbackv5-error-validation' => 'Validation error.', |
| 37 | + 'articlefeedbackv5-error-abuse' => 'Your comment violates the $1. Please revise it.', |
| 38 | + 'articlefeedbackv5-error-abuse-linktext' => 'feedback abuse policy', |
| 39 | + 'articlefeedbackv5-error-abuse-link' => '#', // TODO: Build page and set link here |
37 | 40 | 'articlefeedbackv5-error-unknown' => 'Unknown error.', |
38 | 41 | 'articlefeedbackv5-error-submit' => 'Form submission error.', |
39 | 42 | 'articlefeedbackv5-error-nofeedback' => 'Please enter your feedback.', |
— | — | @@ -304,6 +307,9 @@ |
305 | 308 | 'articlefeedbackv5-cta2-button-text' => 'The text for the button on the learn more CTA', |
306 | 309 | 'articlefeedbackv5-error' => 'This error message will be displayed in a grey box replacing the form if there was an unrecoverable error.', |
307 | 310 | 'articlefeedbackv5-error-nofeedback' => 'This error message will be displayed above the form (but below the title) if the user has attempted to submit a blank form.', |
| 311 | + 'articlefeedbackv5-error-abuse' => 'This error message will be displayed above the form if the comment matched the spam or abuse filters. $1 is the link to the abuse policy.', |
| 312 | + 'articlefeedbackv5-error-abuse-linktext' => 'The text for the abuse policy link.', |
| 313 | + 'articlefeedbackv5-error-abuse-link' => 'The abuse policy link.', |
308 | 314 | 'articlefeedbackv5-form-tools-label' => '{{Identical|Tools}}', |
309 | 315 | 'articlefeedbackv5-special-filter-all' => '{{Identical|All}}', |
310 | 316 | 'articlefeedbackv5-special-more' => '{{Identical|More}}', |
Index: trunk/extensions/ArticleFeedbackv5/modules/jquery.articleFeedbackv5/jquery.articleFeedbackv5.js |
— | — | @@ -2571,6 +2571,12 @@ |
2572 | 2572 | if ( 'error' in data ) { |
2573 | 2573 | if ( typeof( data.error ) == 'object' ) { |
2574 | 2574 | msg = data.error; |
| 2575 | + } else if ( 'articlefeedbackv5-error-abuse' == data.error ) { |
| 2576 | + msg = $.articleFeedbackv5.buildLink( data.error, { |
| 2577 | + href: mw.msg( 'articleFeedbackv5-error-abuse-link' ), |
| 2578 | + text: 'articleFeedbackv5-error-abuse-linktext', |
| 2579 | + target: '_blank' |
| 2580 | + }); |
2575 | 2581 | } else { |
2576 | 2582 | msg = mw.msg( data.error ); |
2577 | 2583 | } |
Index: trunk/extensions/ArticleFeedbackv5/api/ApiArticleFeedbackv5.php |
— | — | @@ -54,6 +54,7 @@ |
55 | 55 | 'bucketId' => $bucket |
56 | 56 | ); |
57 | 57 | |
| 58 | + // Validate the response data |
58 | 59 | foreach ( $fields as $field ) { |
59 | 60 | $field_name = $field['afi_name']; |
60 | 61 | if ( $field['afi_bucket_id'] != $bucket ) { |
— | — | @@ -65,34 +66,35 @@ |
66 | 67 | if ( $value === '' ) { |
67 | 68 | continue; |
68 | 69 | } |
69 | | - if ( $this->validateParam( $value, $type, $field['afi_id'], $pageId ) ) { |
70 | | - $data = array( |
71 | | - 'aa_field_id' => $field['afi_id'], |
72 | | - ); |
73 | | - foreach ( array( 'rating', 'text', 'boolean', 'option_id' ) as $t ) { |
74 | | - $data["aa_response_$t"] = $t == $type ? $value : null; |
75 | | - } |
76 | | - $user_answers[] = $data; |
77 | | - $email_data['ratingData'][$field_name] = $value; |
78 | | - } else { |
| 70 | + if ( !$this->validateParam( $value, $type, $field['afi_id'], $pageId ) ) { |
79 | 71 | $error = 'articlefeedbackv5-error-validation'; |
| 72 | + break; |
80 | 73 | } |
| 74 | + if ( 'text' == $type && $this->findAbuse( $value, $pageId ) ) { |
| 75 | + $error = 'articlefeedbackv5-error-abuse'; |
| 76 | + break; |
| 77 | + } |
| 78 | + $data = array( 'aa_field_id' => $field['afi_id'] ); |
| 79 | + foreach ( array( 'rating', 'text', 'boolean', 'option_id' ) as $t ) { |
| 80 | + $data["aa_response_$t"] = $t == $type ? $value : null; |
| 81 | + } |
| 82 | + $user_answers[] = $data; |
| 83 | + $email_data['ratingData'][$field_name] = $value; |
81 | 84 | } |
82 | 85 | } |
83 | | - |
84 | 86 | if ( $error ) { |
85 | | - $this->getResult()->addValue( |
86 | | - null, 'error', $error |
87 | | - ); |
| 87 | + $this->getResult()->addValue( null, 'error', $error ); |
88 | 88 | return; |
89 | 89 | } |
| 90 | + |
| 91 | + // Save the response data |
90 | 92 | $ratingIds = $this->saveUserRatings( $user_answers, $bucket, $params ); |
91 | 93 | $ctaId = $ratingIds['cta_id']; |
92 | 94 | $feedbackId = $ratingIds['feedback_id']; |
93 | | - |
94 | 95 | $this->saveUserProperties( $feedbackId ); |
95 | 96 | $this->updateRollupTables( $pageId, $revisionId, $user_answers ); |
96 | 97 | |
| 98 | + // If we have an email address, capture it |
97 | 99 | if ( $params['email'] ) { |
98 | 100 | $this->captureEmail ( $params['email'], FormatJson::encode( |
99 | 101 | $email_data |
— | — | @@ -124,6 +126,12 @@ |
125 | 127 | ); |
126 | 128 | } |
127 | 129 | |
| 130 | + /** |
| 131 | + * Option 5 only: Capture the user's email address |
| 132 | + * |
| 133 | + * @param $email string the email address |
| 134 | + * @param $json string the info to send with it, as JSON |
| 135 | + */ |
128 | 136 | protected function captureEmail( $email, $json ) { |
129 | 137 | # http://www.mediawiki.org/wiki/API:Calling_internally |
130 | 138 | $params = new FauxRequest( array( |
— | — | @@ -174,7 +182,15 @@ |
175 | 183 | } |
176 | 184 | break; |
177 | 185 | case 'text': |
178 | | - return $this->validateText( $value, $pageId ); |
| 186 | + # Not actually a requirement, but I can see this being a thing, |
| 187 | + # not letting people post the entire text of 1984 in a comment |
| 188 | + # or something like that. |
| 189 | + global $wgArticleFeedbackv5MaxCommentLength; |
| 190 | + if ( $wgArticleFeedbackv5MaxCommentLength > 0 |
| 191 | + && strlen( $value ) > $wgArticleFeedbackv5MaxCommentLength ) { |
| 192 | + return false; |
| 193 | + } |
| 194 | + return true; |
179 | 195 | default: |
180 | 196 | return false; |
181 | 197 | } |
— | — | @@ -182,38 +198,51 @@ |
183 | 199 | } |
184 | 200 | |
185 | 201 | /** |
186 | | - * Run the text through the AbuseFilter and SpamBlacklist extensions. |
187 | | - * Should we check length as well? What's a reasonable max length? |
| 202 | + * Check for abusive or spammy content |
188 | 203 | * |
| 204 | + * Check the following in sequence (cheapest processing to most expensive, |
| 205 | + * returning if we get a hit): |
| 206 | + * 1) Respect $wgSpamRegex |
| 207 | + * 2) Check SpamBlacklist |
| 208 | + * 3) Check AbuseFilter |
| 209 | + * |
| 210 | + * @param $value string the text to check |
| 211 | + * @param $pageId int the page ID |
189 | 212 | */ |
190 | | - private function validateText( &$value, $pageId ) { |
191 | | - global $wgArticleFeedbackv5MaxCommentLength; |
192 | | - $title = Title::newFromID( $pageId ); |
193 | | - $filter_error = 0; # TODO |
194 | | - $spam_error = 0; # TODO |
195 | | - $length_error = 0; |
| 213 | + private function findAbuse( &$value, $pageId ) { |
| 214 | + // Respect $wgSpamRegex |
| 215 | + global $wgSpamRegex; |
| 216 | + // In older versions, $wgSpamRegex may be a single string rather than |
| 217 | + // an array of regexes, so make it compatible. |
| 218 | + $regexes = ( array ) $wgSpamRegex; |
| 219 | + foreach ( $regexes as $regex ) { |
| 220 | + if ( preg_match( $regex, $value ) ) { |
| 221 | + return true; |
| 222 | + } |
| 223 | + } |
196 | 224 | |
197 | | - # Apparently this returns either true or an error message? |
198 | | - # http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/AbuseFilter/AbuseFilter.class.php?view=markup |
199 | | - # (line 715-721). So normalize this. |
200 | | - $vars = array( |
201 | | - ); |
202 | | -# $filter_error = AbuseFilter::filterAction( $vars, $title ); |
203 | | -# $filter_error = ( $filter_error === true ? 1 : 0 ); |
| 225 | + // Create a fake title so we can pretend this is an article edit |
| 226 | + $title = Title::newFromText( '__article_feedback_5__' ); |
204 | 227 | |
205 | | - # SpamBlacklist filtering goes here. (TODO) |
206 | | - |
207 | | - # Not actually a requirement, but I can see this being a thing, |
208 | | - # not letting people post the entire text of 1984 in a comment |
209 | | - # or something like that. |
210 | | - if ( $wgArticleFeedbackv5MaxCommentLength > 0 |
211 | | - && strlen( $value ) > $wgArticleFeedbackv5MaxCommentLength ) { |
212 | | - $length_error = 1; |
| 228 | + // Check SpamBlacklist |
| 229 | + $spam = wfSpamBlacklistObject(); |
| 230 | + $ret = $spam->filter( $title, $value, '' ); |
| 231 | + if ( $ret !== false ) { |
| 232 | + return true; |
213 | 233 | } |
214 | 234 | |
215 | | - $has_error = $filter_error + $spam_error + $length_error; |
216 | | - |
217 | | - return $has_error ? false : true; |
| 235 | + // Check the abuse filter |
| 236 | + global $wgUser; |
| 237 | + $vars = new AbuseFilterVariableHolder; |
| 238 | + $vars->addHolder( AbuseFilter::generateUserVars( $wgUser ) ); |
| 239 | + $vars->addHolder( AbuseFilter::generateTitleVars( $title, 'FEEDBACK' ) ); |
| 240 | + $vars->setVar( 'SUMMARY', 'Article Feedback 5' ); |
| 241 | + $vars->setVar( 'ACTION', 'feedback' ); |
| 242 | + $vars->setVar( 'old_wikitext', '' ); |
| 243 | + $vars->setVar( 'new_wikitext', $value ); |
| 244 | + $vars->addHolder( AbuseFilter::getEditVars( $title ) ); |
| 245 | + $filter_result = AbuseFilter::filterAction( $vars, $title ); |
| 246 | + return $filter_result != '' && $filter_result !== true; |
218 | 247 | } |
219 | 248 | |
220 | 249 | /** |
Index: trunk/extensions/ArticleFeedbackv5/ArticleFeedbackv5.hooks.php |
— | — | @@ -62,6 +62,9 @@ |
63 | 63 | 'articlefeedbackv5-error-unknown', |
64 | 64 | 'articlefeedbackv5-error-submit', |
65 | 65 | 'articlefeedbackv5-cta-thanks', |
| 66 | + 'articlefeedbackv5-error-abuse', |
| 67 | + 'articleFeedbackv5-error-abuse-link', |
| 68 | + 'articleFeedbackv5-error-abuse-linktext', |
66 | 69 | 'articlefeedbackv5-cta-confirmation-followup', |
67 | 70 | 'articlefeedbackv5-cta1-confirmation-title', |
68 | 71 | 'articlefeedbackv5-cta1-confirmation-call', |