Index: trunk/extensions/MoodBar/include/MoodBarUtil.php |
— | — | @@ -6,6 +6,67 @@ |
7 | 7 | class MoodBarUtil { |
8 | 8 | |
9 | 9 | /** |
| 10 | + * Check for abusive or spammy content |
| 11 | + * |
| 12 | + * Check the following in sequence (cheapest processing to most expensive, |
| 13 | + * returning if we get a hit): |
| 14 | + * 1) Respect $wgSpamRegex |
| 15 | + * 2) Check SpamBlacklist |
| 16 | + * 3) Check AbuseFilter |
| 17 | + * |
| 18 | + * @param $value string the text to check |
| 19 | + */ |
| 20 | + public static function findAbuse( &$value ) { |
| 21 | + |
| 22 | + // Respect $wgSpamRegex |
| 23 | + global $wgSpamRegex; |
| 24 | + if ( ( is_array( $wgSpamRegex ) && count( $wgSpamRegex ) > 0 ) |
| 25 | + || ( is_string( $wgSpamRegex ) && strlen( $wgSpamRegex ) > 0 ) ) { |
| 26 | + // In older versions, $wgSpamRegex may be a single string rather than |
| 27 | + // an array of regexes, so make it compatible. |
| 28 | + $regexes = ( array ) $wgSpamRegex; |
| 29 | + foreach ( $regexes as $regex ) { |
| 30 | + if ( preg_match( $regex, $value ) ) { |
| 31 | + return true; |
| 32 | + } |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + // Create a fake title so we can pretend this is an article edit |
| 37 | + $title = Title::newFromText( '__moodbar__' ); |
| 38 | + |
| 39 | + // Check SpamBlacklist, if installed |
| 40 | + if ( function_exists( 'wfSpamBlacklistObject' ) ) { |
| 41 | + $spam = wfSpamBlacklistObject(); |
| 42 | + } elseif ( class_exists( 'BaseBlacklist' ) ) { |
| 43 | + $spam = BaseBlacklist::getInstance( 'spam' ); |
| 44 | + } |
| 45 | + if ( $spam ) { |
| 46 | + $ret = $spam->filter( $title, $value, '' ); |
| 47 | + if ( $ret !== false ) { |
| 48 | + return true; |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + // Check AbuseFilter, if installed |
| 53 | + if ( class_exists( 'AbuseFilter' ) ) { |
| 54 | + global $wgUser; |
| 55 | + $vars = new AbuseFilterVariableHolder; |
| 56 | + $vars->addHolder( AbuseFilter::generateUserVars( $wgUser ) ); |
| 57 | + $vars->addHolder( AbuseFilter::generateTitleVars( $title, 'MOODBAR' ) ); |
| 58 | + $vars->setVar( 'SUMMARY', 'moodbar' ); |
| 59 | + $vars->setVar( 'ACTION', 'moodbar' ); |
| 60 | + $vars->setVar( 'old_wikitext', '' ); |
| 61 | + $vars->setVar( 'new_wikitext', $value ); |
| 62 | + $vars->addHolder( AbuseFilter::getEditVars( $title ) ); |
| 63 | + $filter_result = AbuseFilter::filterAction( $vars, $title ); |
| 64 | + return $filter_result != '' && $filter_result !== true; |
| 65 | + } |
| 66 | + |
| 67 | + return false; |
| 68 | + } |
| 69 | + |
| 70 | + /** |
10 | 71 | * Calculate the time diff between $time and now, format the time diff to have the largest time block |
11 | 72 | * or 'less than 1 minute' if the time diff is less than 1 minute |
12 | 73 | * @param $time string - the UNIX time stamp |
Index: trunk/extensions/MoodBar/MoodBar.i18n.php |
— | — | @@ -66,6 +66,10 @@ |
67 | 67 | 'moodbar-error-subtitle' => 'Something went wrong! Please try sharing your feedback again later.', |
68 | 68 | 'moodbar-blocked-title' => 'Oops!', |
69 | 69 | 'moodbar-blocked-subtitle' => 'You have been blocked from editing.', |
| 70 | + 'moodbar-ratelimited-title' => 'Oops!', |
| 71 | + 'moodbar-ratelimited-subtitle' => 'You have exceeded moodbar rate limit. Please wait some time and try again', |
| 72 | + 'moodbar-abuse-title' => 'Oops!', |
| 73 | + 'moodbar-abuse-subtitle' => 'Your feedback violates moodbar rules.', |
70 | 74 | 'moodbar-email-title' => 'Add e-mail', |
71 | 75 | 'moodbar-email-input' => 'Your e-mail address', |
72 | 76 | 'moodbar-email-desc' => 'We will send you an e-mail if someone responds to your feedback.', |
— | — | @@ -272,6 +276,10 @@ |
273 | 277 | 'moodbar-error-subtitle' => 'Subtitle of screen when an error occurred. $1 is the SITENAME', |
274 | 278 | 'moodbar-blocked-title' => 'Title of the screen after blocked user attempts to post feedback.', |
275 | 279 | 'moodbar-blocked-subtitle' => 'Subtitle of screen after blocked user attempts to post feedback.', |
| 280 | + 'moodbar-ratelimited-title' => 'Title of the screen after users have exceeded rate limit and attempt to post feedback.', |
| 281 | + 'moodbar-ratelimited-subtitle' => 'Subtitle of screen after users have exceeded rate limit and attempt to post feedback.', |
| 282 | + 'moodbar-abuse-title' => 'Title of the screen after user attempts to post bad feedback.', |
| 283 | + 'moodbar-abuse-subtitle' => 'Subtitle of the screen after user attempts to post bad feedback.', |
276 | 284 | 'moodbar-email-title' => 'Title of MoodBar when user has no email addresss', |
277 | 285 | 'moodbar-email-input' => 'Field label for Email address', |
278 | 286 | 'moodbar-email-desc' => 'Message prompting user to enter their email address.', |
Index: trunk/extensions/MoodBar/ApiFeedbackDashboardResponse.php |
— | — | @@ -6,7 +6,7 @@ |
7 | 7 | private $EnotifWatchlist; |
8 | 8 | |
9 | 9 | public function execute() { |
10 | | - global $wgRequest, $wgUser; |
| 10 | + global $wgRequest, $wgUser, $wgMoodBarAbuseFiltering; |
11 | 11 | |
12 | 12 | if ( $wgUser->isAnon() ) { |
13 | 13 | $this->dieUsage( "You don't have permission to do that", 'permission-denied' ); |
— | — | @@ -14,12 +14,20 @@ |
15 | 15 | if ( $wgUser->isBlocked( false ) ) { |
16 | 16 | $this->dieUsageMsg( array( 'blockedtext' ) ); |
17 | 17 | } |
| 18 | + if ( $wgUser->pingLimiter( 'moodbar-response' ) ) { |
| 19 | + $this->dieUsageMsg( array( 'actionthrottledtext' ) ); |
| 20 | + } |
18 | 21 | |
19 | 22 | $params = $this->extractRequestParams(); |
20 | 23 | |
| 24 | + if ( $wgMoodBarAbuseFiltering && MoodBarUtil::findAbuse( $params['response'] ) ) { |
| 25 | + $this->getResult()->addValue( null, 'error', array( 'code' => 'abuse' ) ); |
| 26 | + return; |
| 27 | + } |
| 28 | + |
21 | 29 | //Response Object |
22 | 30 | $item = MBFeedbackResponseItem::create( array() ); |
23 | | - |
| 31 | + |
24 | 32 | $setParams = array(); |
25 | 33 | foreach( $params as $key => $value ) { |
26 | 34 | if ( $item->isValidKey( $key ) ) { |
Index: trunk/extensions/MoodBar/ApiMoodBar.php |
— | — | @@ -2,14 +2,25 @@ |
3 | 3 | |
4 | 4 | class ApiMoodBar extends ApiBase { |
5 | 5 | public function execute() { |
6 | | - global $wgUser; |
| 6 | + global $wgUser, $wgMoodBarAbuseFiltering; |
7 | 7 | |
| 8 | + if ( $wgUser->isAnon() ) { |
| 9 | + $this->dieUsage( "You don't have permission to do that", 'permission-denied' ); |
| 10 | + } |
8 | 11 | if ( $wgUser->isBlocked( false ) ) { |
9 | 12 | $this->dieUsageMsg( array( 'blockedtext' ) ); |
10 | 13 | } |
| 14 | + if ( $wgUser->pingLimiter( 'moodbar-feedback' ) ) { |
| 15 | + $this->dieUsageMsg( array( 'actionthrottledtext' ) ); |
| 16 | + } |
11 | 17 | |
12 | 18 | $params = $this->extractRequestParams(); |
13 | 19 | |
| 20 | + if ( $wgMoodBarAbuseFiltering && MoodBarUtil::findAbuse( $params['comment'] ) ) { |
| 21 | + $this->getResult()->addValue( null, 'error', array( 'code' => 'abuse' ) ); |
| 22 | + return; |
| 23 | + } |
| 24 | + |
14 | 25 | $params['page'] = Title::newFromText( $params['page'] ); |
15 | 26 | |
16 | 27 | // Params are deliberately named the same as the properties, |
Index: trunk/extensions/MoodBar/modules/ext.moodBar/ext.moodBar.core.js |
— | — | @@ -94,6 +94,16 @@ |
95 | 95 | <div class="mw-moodBar-state mw-moodBar-state-error">\ |
96 | 96 | <div class="mw-moodBar-state-title"><html:msg key="moodbar-blocked-title" /></div>\ |
97 | 97 | <div class="mw-moodBar-state-subtitle"><html:msg key="moodbar-blocked-subtitle" /></div>\ |
| 98 | + </div>', |
| 99 | + ratelimited: '\ |
| 100 | + <div class="mw-moodBar-state mw-moodBar-state-error">\ |
| 101 | + <div class="mw-moodBar-state-title"><html:msg key="moodbar-ratelimited-title" /></div>\ |
| 102 | + <div class="mw-moodBar-state-subtitle"><html:msg key="moodbar-ratelimited-subtitle" /></div>\ |
| 103 | + </div>', |
| 104 | + abuse: '\ |
| 105 | + <div class="mw-moodBar-state mw-moodBar-state-error">\ |
| 106 | + <div class="mw-moodBar-state-title"><html:msg key="moodbar-abuse-title" /></div>\ |
| 107 | + <div class="mw-moodBar-state-subtitle"><html:msg key="moodbar-abuse-subtitle" /></div>\ |
98 | 108 | </div>' |
99 | 109 | }, |
100 | 110 | |
— | — | @@ -163,6 +173,16 @@ |
164 | 174 | setTimeout( function() { |
165 | 175 | mb.ui.overlay.fadeOut(); |
166 | 176 | }, 3000 ); |
| 177 | + } else if (data && data.error && data.error.code === 'ratelimited') { |
| 178 | + mb.swapContent( mb.tpl.ratelimited ); |
| 179 | + setTimeout( function() { |
| 180 | + mb.ui.overlay.fadeOut(); |
| 181 | + }, 3000 ); |
| 182 | + } else if (data && data.error && data.error.code === 'abuse') { |
| 183 | + mb.swapContent( mb.tpl.abuse ); |
| 184 | + setTimeout( function() { |
| 185 | + mb.ui.overlay.fadeOut(); |
| 186 | + }, 3000 ); |
167 | 187 | } else { |
168 | 188 | mb.swapContent( mb.tpl.error ); |
169 | 189 | } |
Index: trunk/extensions/MoodBar/modules/ext.moodBar.dashboard/ext.moodBar.dashboard.js |
— | — | @@ -731,7 +731,11 @@ |
732 | 732 | success: function (data) { |
733 | 733 | // If rejected |
734 | 734 | if ( data.error !== undefined ) { |
735 | | - responseMessage( $item, 'error', mw.msg( 'response-ajax-error-head' ), data.error.info ); |
| 735 | + if ( data.error.code && data.error.code === 'abuse' ) { |
| 736 | + responseMessage( $item, 'error', mw.msg( 'moodbar-abuse-title' ), mw.msg( 'moodbar-abuse-subtitle') ); |
| 737 | + } else { |
| 738 | + responseMessage( $item, 'error', mw.msg( 'response-ajax-error-head' ), data.error.info ); |
| 739 | + } |
736 | 740 | } else if ( data.feedbackdashboardresponse !== undefined ) { |
737 | 741 | responseMessage( $item, 'success', mw.msg( 'response-ajax-success-head' ), mw.msg( 'response-ajax-success-body' ) ); |
738 | 742 | } |
Index: trunk/extensions/MoodBar/MoodBar.php |
— | — | @@ -164,6 +164,10 @@ |
165 | 165 | 'moodbar-success-subtitle', |
166 | 166 | 'moodbar-blocked-title', |
167 | 167 | 'moodbar-blocked-subtitle', |
| 168 | + 'moodbar-ratelimited-title', |
| 169 | + 'moodbar-ratelimited-subtitle', |
| 170 | + 'moodbar-abuse-title', |
| 171 | + 'moodbar-abuse-subtitle', |
168 | 172 | 'moodbar-email-title', |
169 | 173 | 'moodbar-email-input', |
170 | 174 | 'moodbar-email-desc', |
— | — | @@ -246,6 +250,25 @@ |
247 | 251 | /** The registration time after which users will be shown the MoodBar **/ |
248 | 252 | $wgMoodBarCutoffTime = null; |
249 | 253 | |
| 254 | +/** Rate limit setting for moodbar **/ |
| 255 | +$wgMoodBarFeedbackRateLimit = 300; |
| 256 | +$wgMoodBarResponseRateLimit = 60; |
| 257 | +$wgRateLimits += array( |
| 258 | + 'moodbar-feedback' => array( 'user' => array( 1 => $wgMoodBarFeedbackRateLimit ) ), |
| 259 | + 'moodbar-response' => array( 'user' => array( 1 => $wgMoodBarResponseRateLimit ) ) |
| 260 | + ); |
| 261 | +/** |
| 262 | + * Turn on abuse filtering |
| 263 | + * |
| 264 | + * If this is set to true, feedback/response will be run through: |
| 265 | + * 1. $wgSpamRegex, if set |
| 266 | + * 2. SpamBlacklist, if installed |
| 267 | + * 3. AbuseFilter, if installed |
| 268 | + * |
| 269 | + * @var boolean |
| 270 | + */ |
| 271 | +$wgMoodBarAbuseFiltering = true; |
| 272 | + |
250 | 273 | /** MoodBar configuration settings **/ |
251 | 274 | $wgMoodBarConfig = array( |
252 | 275 | 'bucketConfig' => |