Index: trunk/extensions/FlaggedRevs/FlaggedRevs.php |
— | — | @@ -141,20 +141,19 @@ |
142 | 142 | # Define when users get automatically promoted to Editors. Set as false to disable. |
143 | 143 | # Once users meet these requirements they will be promoted, unless previously demoted. |
144 | 144 | $wgFlaggedRevsAutopromote = array( |
145 | | - 'days' => 60, # days since registration |
146 | | - 'edits' => 250, # total edit count |
147 | | - 'excludeDeleted' => true, # exclude deleted edits from 'edits' count above? |
148 | | - 'excludeLastDays' => 1, # exclude last X days of edits from 'edits' count above |
149 | | - 'benchmarks' => 15, # number of "spread out" edits |
150 | | - 'spacing' => 3, # number of days between these edits (the "spread") |
| 145 | + 'days' => 60, # days since registration |
| 146 | + 'edits' => 250, # total edit count |
| 147 | + 'excludeLastDays' => 1, # exclude the last X days of edits from edit counts |
| 148 | + 'benchmarks' => 15, # number of "spread out" edits |
| 149 | + 'spacing' => 3, # number of days between these edits (the "spread") |
151 | 150 | // Either totalContentEdits reqs OR totalCheckedEdits requirements needed |
152 | | - 'totalContentEdits' => 300, # $wgContentNamespaces edits OR... |
153 | | - 'totalCheckedEdits' => 200, # ...Edits before the stable version of pages |
154 | | - 'uniqueContentPages' => 12, # unique pages in $wgContentNamespaces edited |
155 | | - 'editComments' => 50, # number of manual edit summaries used |
156 | | - 'userpageBytes' => 0, # size of userpage (use 0 to not require a userpage) |
157 | | - 'neverBlocked' => true, # username was never blocked before? |
158 | | - 'maxRevertedEdits' => 5, # max times the user had edits undone/"rolled back" |
| 151 | + 'totalContentEdits' => 300, # edits to pages in $wgContentNamespaces |
| 152 | + 'totalCheckedEdits' => 200, # edits before the stable version of pages |
| 153 | + 'uniqueContentPages' => 12, # unique pages in $wgContentNamespaces edited |
| 154 | + 'editComments' => 50, # number of manual edit summaries used |
| 155 | + 'userpageBytes' => 0, # size of userpage (use 0 to not require a userpage) |
| 156 | + 'neverBlocked' => true, # username was never blocked before? |
| 157 | + 'maxRevertedEditRatio' => .03, # max fraction of edits reverted via "rollback"/"undo" |
159 | 158 | ); |
160 | 159 | |
161 | 160 | # Define when users get to have their own edits auto-reviewed. Set to false to disable. |
— | — | @@ -165,8 +164,8 @@ |
166 | 165 | $wgFlaggedRevsAutoconfirm = array( |
167 | 166 | 'days' => 30, # days since registration |
168 | 167 | 'edits' => 50, # total edit count |
169 | | - 'spacing' => 3, # spacing of edit intervals |
170 | | - 'benchmarks' => 7, # how many edit intervals are needed? |
| 168 | + 'benchmarks' => 7, # number of "spread out" edits |
| 169 | + 'spacing' => 3, # number of days between these edits (the "spread") |
171 | 170 | // Either totalContentEdits reqs OR totalCheckedEdits requirements needed |
172 | 171 | 'totalContentEdits' => 150, # $wgContentNamespaces edits OR... |
173 | 172 | 'totalCheckedEdits' => 50, # ...Edits before the stable version of pages |
— | — | @@ -426,7 +425,7 @@ |
427 | 426 | |
428 | 427 | # ######## DB write operations ######### |
429 | 428 | # Autopromote Editors |
430 | | -$wgHooks['ArticleSaveComplete'][] = 'FlaggedRevsHooks::maybeMakeEditor'; |
| 429 | +$wgHooks['ArticleSaveComplete'][] = 'FlaggedRevsHooks::onArticleSaveComplete'; |
431 | 430 | # Auto-reviewing |
432 | 431 | $wgHooks['RecentChange_save'][] = 'FlaggedRevsHooks::autoMarkPatrolled'; |
433 | 432 | $wgHooks['NewRevisionFromEditComplete'][] = 'FlaggedRevsHooks::maybeMakeEditReviewed'; |
Index: trunk/extensions/FlaggedRevs/FlaggedRevs.hooks.php |
— | — | @@ -1004,9 +1004,31 @@ |
1005 | 1005 | } |
1006 | 1006 | |
1007 | 1007 | /** |
| 1008 | + * Check if a user has enough implicitly reviewed edits (before stable version) |
| 1009 | + * @param $user User |
| 1010 | + * @param $editsReq int |
| 1011 | + * @param $cutoff_unixtime int exclude edits after this timestamp |
| 1012 | + * @return bool |
| 1013 | + */ |
| 1014 | + protected static function reviewedEditsCheck( $user, $editsReq, $cutoff_unixtime = 0 ) { |
| 1015 | + $dbr = wfGetDB( DB_SLAVE ); |
| 1016 | + $encCutoff = $dbr->addQuotes( $dbr->timestamp( $cutoff_unixtime ) ); |
| 1017 | + $res = $dbr->select( array( 'revision', 'flaggedpages' ), '1', |
| 1018 | + array( 'rev_user' => $user->getId(), |
| 1019 | + "rev_timestamp < $encCutoff", |
| 1020 | + 'fp_page_id = rev_page', |
| 1021 | + 'fp_pending_since IS NULL OR fp_pending_since > rev_timestamp' // bug 15515 |
| 1022 | + ), |
| 1023 | + __METHOD__, |
| 1024 | + array( 'USE INDEX' => array( 'revision' => 'user_timestamp' ), 'LIMIT' => $editsReq ) |
| 1025 | + ); |
| 1026 | + return ( $dbr->numRows( $res ) >= $editsReq ); |
| 1027 | + } |
| 1028 | + |
| 1029 | + /** |
1008 | 1030 | * Checks if $user was previously blocked |
1009 | 1031 | */ |
1010 | | - public static function previousBlockCheck( $user ) { |
| 1032 | + public static function wasPreviouslyBlocked( $user ) { |
1011 | 1033 | $dbr = wfGetDB( DB_SLAVE ); |
1012 | 1034 | return (bool)$dbr->selectField( 'logging', '1', |
1013 | 1035 | array( |
— | — | @@ -1031,6 +1053,32 @@ |
1032 | 1054 | } |
1033 | 1055 | |
1034 | 1056 | /** |
| 1057 | + * Callback that autopromotes user according to the setting in |
| 1058 | + * $wgFlaggedRevsAutopromote. This also handles user stats tallies. |
| 1059 | + */ |
| 1060 | + public static function onArticleSaveComplete( |
| 1061 | + Article $article, $user, $text, $summary, $m, $a, $b, &$f, $rev |
| 1062 | + ) { |
| 1063 | + global $wgFlaggedRevsAutopromote, $wgFlaggedRevsAutoconfirm; |
| 1064 | + # Ignore NULL edits or edits by anon users |
| 1065 | + if ( !$rev || !$user->getId() ) { |
| 1066 | + return true; |
| 1067 | + # No sense in running counters if nothing uses them |
| 1068 | + } elseif ( !$wgFlaggedRevsAutopromote && !$wgFlaggedRevsAutoconfirm ) { |
| 1069 | + return true; |
| 1070 | + } |
| 1071 | + $p = FRUserCounters::getUserParams( $user->getId(), FR_FOR_UPDATE ); |
| 1072 | + $changed = FRUserCounters::updateUserParams( $p, $article, $summary ); |
| 1073 | + if ( $changed ) { |
| 1074 | + FRUserCounters::saveUserParams( $user->getId(), $p ); // save any updates |
| 1075 | + } |
| 1076 | + if ( is_array( $wgFlaggedRevsAutopromote ) ) { |
| 1077 | + self::maybeMakeEditor( $user, $p, $wgFlaggedRevsAutopromote ); |
| 1078 | + } |
| 1079 | + return true; |
| 1080 | + } |
| 1081 | + |
| 1082 | + /** |
1035 | 1083 | * Grant implicit 'autoreview' group to users meeting the |
1036 | 1084 | * $wgFlaggedRevsAutoconfirm requirements. This lets people who |
1037 | 1085 | * opt-out as Editors still have their own edits automatically reviewed. |
— | — | @@ -1039,84 +1087,49 @@ |
1040 | 1088 | */ |
1041 | 1089 | public static function checkAutoPromote( $user, array &$promote ) { |
1042 | 1090 | global $wgFlaggedRevsAutoconfirm, $wgMemc; |
1043 | | - # Check if $wgFlaggedRevsAutoconfirm is actually enabled |
1044 | | - # and that this is a logged-in user that doesn't already |
1045 | | - # have the 'autoreview' permission |
1046 | | - if ( !$user->getId() || empty( $wgFlaggedRevsAutoconfirm ) ) { |
| 1091 | + $conds = $wgFlaggedRevsAutoconfirm; // convenience |
| 1092 | + if ( !is_array( $conds ) || !$user->getId() ) { |
| 1093 | + return true; // $wgFlaggedRevsAutoconfirm not applicable |
| 1094 | + } |
| 1095 | + $p = FRUserCounters::getUserParams( $user->getId() ); |
| 1096 | + $regTime = wfTimestampOrNull( TS_UNIX, $user->getRegistration() ); |
| 1097 | + if ( |
| 1098 | + # Check if user edited enough unique pages |
| 1099 | + $conds['uniqueContentPages'] > count( $p['uniqueContentPages'] ) || |
| 1100 | + # Check edit comment use |
| 1101 | + $conds['editComments'] > $p['editComments'] || |
| 1102 | + # Check user edit count |
| 1103 | + $conds['edits'] > $user->getEditCount() || |
| 1104 | + # Check account age |
| 1105 | + ( $regTime && $conds['days'] > ( ( time() - $regTime ) / 86400 ) ) || |
| 1106 | + # Check user email |
| 1107 | + $conds['email'] && !$user->isEmailConfirmed() || |
| 1108 | + # Don't grant to currently blocked users... |
| 1109 | + $user->isBlocked() |
| 1110 | + ) { |
1047 | 1111 | return true; |
1048 | 1112 | } |
| 1113 | + # Check if user edited enough content pages |
| 1114 | + $failedContentEdits = ( $conds['totalContentEdits'] > $p['totalContentEdits'] ); |
| 1115 | + |
1049 | 1116 | # Check if results are cached to avoid DB queries. |
1050 | 1117 | # Checked basic, already available, promotion heuristics first... |
1051 | 1118 | $APSkipKey = wfMemcKey( 'flaggedrevs', 'autoreview-skip', $user->getId() ); |
1052 | | - $value = $wgMemc->get( $APSkipKey ); |
1053 | | - if ( $value === 'true' ) { |
| 1119 | + if ( $wgMemc->get( $APSkipKey ) === 'true' ) { |
1054 | 1120 | return true; |
1055 | 1121 | } |
1056 | | - # Check $wgFlaggedRevsAutoconfirm settings... |
1057 | | - $now = time(); |
1058 | | - $userCreation = wfTimestampOrNull( TS_UNIX, $user->getRegistration() ); |
1059 | | - # User registration was not always tracked in DB...use null for such cases |
1060 | | - $userage = $userCreation |
1061 | | - ? floor( ( $now - $userCreation ) / 86400 ) |
1062 | | - : null; |
1063 | | - $p = FRUserCounters::getUserParams( $user->getId() ); |
1064 | | - # Check if user edited enough content pages |
1065 | | - $totalCheckedEditsNeeded = false; |
1066 | | - if ( $wgFlaggedRevsAutoconfirm['totalContentEdits'] > $p['totalContentEdits'] ) { |
1067 | | - if ( !$wgFlaggedRevsAutoconfirm['totalCheckedEdits'] ) { |
1068 | | - return true; |
1069 | | - } |
1070 | | - $totalCheckedEditsNeeded = true; |
1071 | | - } |
1072 | | - # Check if user edited enough unique pages |
1073 | | - $pages = $p['uniqueContentPages']; // page IDs |
1074 | | - if ( $wgFlaggedRevsAutoconfirm['uniqueContentPages'] > count( $pages ) ) { |
| 1122 | + # Check if user was ever blocked before |
| 1123 | + if ( $conds['neverBlocked'] && self::wasPreviouslyBlocked( $user ) ) { |
| 1124 | + $wgMemc->set( $APSkipKey, 'true', 3600 * 24 * 7 ); // cache results |
1075 | 1125 | return true; |
1076 | 1126 | } |
1077 | | - # Check edit comment use |
1078 | | - if ( $wgFlaggedRevsAutoconfirm['editComments'] > $p['editComments'] ) { |
1079 | | - return true; |
1080 | | - } |
1081 | | - # Check account age |
1082 | | - if ( !is_null( $userage ) && $userage < $wgFlaggedRevsAutoconfirm['days'] ) { |
1083 | | - return true; |
1084 | | - } |
1085 | | - # Check user edit count. Should be stored. |
1086 | | - if ( $user->getEditCount() < $wgFlaggedRevsAutoconfirm['edits'] ) { |
1087 | | - return true; |
1088 | | - } |
1089 | | - # Check user email |
1090 | | - if ( $wgFlaggedRevsAutoconfirm['email'] && !$user->isEmailConfirmed() ) { |
1091 | | - return true; |
1092 | | - } |
1093 | | - # Don't grant to currently blocked users... |
1094 | | - if ( $user->isBlocked() ) { |
1095 | | - return true; |
1096 | | - } |
1097 | | - # Check if user was ever blocked before |
1098 | | - if ( $wgFlaggedRevsAutoconfirm['neverBlocked'] ) { |
1099 | | - $blocked = self::previousBlockCheck( $user ); |
1100 | | - if ( $blocked ) { |
1101 | | - # Make a key to store the results |
1102 | | - $wgMemc->set( $APSkipKey, 'true', 3600 * 24 * 7 ); |
1103 | | - return true; |
1104 | | - } |
1105 | | - } |
1106 | 1127 | # Check for edit spacing. This lets us know that the account has |
1107 | 1128 | # been used over N different days, rather than all in one lump. |
1108 | | - if ( $wgFlaggedRevsAutoconfirm['spacing'] > 0 |
1109 | | - && $wgFlaggedRevsAutoconfirm['benchmarks'] > 1 ) |
1110 | | - { |
| 1129 | + if ( $conds['spacing'] > 0 && $conds['benchmarks'] > 1 ) { |
1111 | 1130 | $sTestKey = wfMemcKey( 'flaggedrevs', 'autoreview-spacing-ok', $user->getId() ); |
1112 | | - $value = $wgMemc->get( $sTestKey ); |
1113 | | - # Check if the user already passed this test via cache. |
1114 | | - # If no cache key is available, then check the DB... |
1115 | | - if ( $value !== 'true' ) { |
1116 | | - $pass = self::editSpacingCheck( |
1117 | | - $wgFlaggedRevsAutoconfirm['spacing'], |
1118 | | - $wgFlaggedRevsAutoconfirm['benchmarks'], |
1119 | | - $user |
1120 | | - ); |
| 1131 | + # Hit the DB only if the result is not cached... |
| 1132 | + if ( $wgMemc->get( $sTestKey ) !== 'true' ) { |
| 1133 | + $pass = self::editSpacingCheck( $conds['spacing'], $conds['benchmarks'], $user ); |
1121 | 1134 | # Make a key to store the results |
1122 | 1135 | if ( $pass === true ) { |
1123 | 1136 | $wgMemc->set( $sTestKey, 'true', 7 * 24 * 3600 ); |
— | — | @@ -1127,191 +1140,117 @@ |
1128 | 1141 | } |
1129 | 1142 | } |
1130 | 1143 | # Check implicitly checked edits |
1131 | | - if ( $totalCheckedEditsNeeded && $wgFlaggedRevsAutoconfirm['totalCheckedEdits'] ) { |
1132 | | - $dbr = wfGetDB( DB_SLAVE ); |
1133 | | - $res = $dbr->select( array( 'revision', 'flaggedpages' ), '1', |
1134 | | - array( 'rev_user' => $user->getId(), |
1135 | | - 'fp_page_id = rev_page', 'fp_stable >= rev_id' ), |
1136 | | - __METHOD__, |
1137 | | - array( 'USE INDEX' => array( 'revision' => 'user_timestamp' ), |
1138 | | - 'LIMIT' => $wgFlaggedRevsAutoconfirm['totalCheckedEdits'] ) |
1139 | | - ); |
1140 | | - if ( $dbr->numRows( $res ) < $wgFlaggedRevsAutoconfirm['totalCheckedEdits'] ) { |
| 1144 | + if ( $failedContentEdits && $conds['totalCheckedEdits'] > 0 ) { |
| 1145 | + if ( !self::reviewedEditsCheck( $user, $conds['totalCheckedEdits'] ) ) { |
1141 | 1146 | return true; |
1142 | 1147 | } |
1143 | 1148 | } |
1144 | | - $promote[] = 'autoreview'; // add the group |
| 1149 | + $promote[] = 'autoreview'; // add the group |
1145 | 1150 | return true; |
1146 | 1151 | } |
1147 | 1152 | |
1148 | 1153 | /** |
1149 | | - * Callback that autopromotes user according to the setting in |
1150 | | - * $wgFlaggedRevsAutopromote. This also handles user stats tallies. |
| 1154 | + * Autopromotes user according to the setting in $wgFlaggedRevsAutopromote. |
| 1155 | + * @param $user User |
| 1156 | + * @param $p array user tallies |
| 1157 | + * @param $conds array $wgFlaggedRevsAutopromote |
1151 | 1158 | */ |
1152 | | - public static function maybeMakeEditor( |
1153 | | - Article $article, $user, $text, $summary, $m, $a, $b, &$f, $rev |
1154 | | - ) { |
1155 | | - global $wgFlaggedRevsAutopromote, $wgFlaggedRevsAutoconfirm, $wgMemc; |
1156 | | - # Ignore NULL edits or edits by anon users |
1157 | | - if ( !$rev || !$user->getId() ) { |
1158 | | - return true; |
1159 | | - # No sense in running counters if nothing uses them |
1160 | | - } elseif ( !$wgFlaggedRevsAutopromote && !$wgFlaggedRevsAutoconfirm ) { |
1161 | | - return true; |
| 1159 | + protected static function maybeMakeEditor( User $user, array $p, array $conds ) { |
| 1160 | + global $wgMemc, $wgContentNamespaces; |
| 1161 | + $groups = $user->getGroups(); // current groups |
| 1162 | + $regTime = wfTimestampOrNull( TS_UNIX, $user->getRegistration() ); |
| 1163 | + if ( |
| 1164 | + !$user->getId() || |
| 1165 | + # Do not give this to current holders |
| 1166 | + in_array( 'editor', $groups ) || |
| 1167 | + # Do not give this right to bots |
| 1168 | + $user->isAllowed( 'bot' ) || |
| 1169 | + # Do not re-add status if it was previously removed! |
| 1170 | + ( isset( $p['demoted'] ) && $p['demoted'] ) || |
| 1171 | + # Check if user edited enough unique pages |
| 1172 | + $conds['uniqueContentPages'] > count( $p['uniqueContentPages'] ) || |
| 1173 | + # Check edit summary usage |
| 1174 | + $conds['editComments'] > $p['editComments'] || |
| 1175 | + # Check reverted edits |
| 1176 | + $conds['maxRevertedEditRatio']*$user->getEditCount() < $p['revertedEdits'] || |
| 1177 | + # Check user edit count |
| 1178 | + $conds['edits'] > $user->getEditCount() || |
| 1179 | + # Check account age |
| 1180 | + ( $regTime && $conds['days'] > ( ( time() - $regTime ) / 86400 ) ) || |
| 1181 | + # See if the page actually has sufficient content... |
| 1182 | + $conds['userpageBytes'] > $user->getUserPage()->getLength() || |
| 1183 | + # Don't grant to currently blocked users... |
| 1184 | + $user->isBlocked() |
| 1185 | + ) { |
| 1186 | + return true; // not ready |
1162 | 1187 | } |
1163 | | - $p = FRUserCounters::getUserParams( $user->getId(), FR_FOR_UPDATE ); |
1164 | | - $changed = FRUserCounters::updateUserParams( $p, $article, $summary ); |
1165 | | - # Save any updates to user params |
1166 | | - if ( $changed ) { |
1167 | | - FRUserCounters::saveUserParams( $user->getId(), $p ); |
1168 | | - } |
1169 | | - if ( !is_array( $wgFlaggedRevsAutopromote ) ) { |
1170 | | - return true; // nothing to do |
1171 | | - } |
1172 | | - # Grab current groups |
1173 | | - $groups = $user->getGroups(); |
1174 | | - # Do not give this to current holders or bots |
1175 | | - if ( $user->isAllowed( 'bot' ) || in_array( 'editor', $groups ) ) { |
1176 | | - return true; |
1177 | | - } |
1178 | | - # Do not re-add status if it was previously removed! |
1179 | | - if ( isset( $p['demoted'] ) && $p['demoted'] ) { |
1180 | | - return true; |
1181 | | - } |
| 1188 | + # User needs to meet 'totalContentEdits' OR 'totalCheckedEdits' |
| 1189 | + $failedContentEdits = ( $conds['totalContentEdits'] > $p['totalContentEdits'] ); |
| 1190 | + |
| 1191 | + # More expensive checks below... |
1182 | 1192 | # Check if results are cached to avoid DB queries |
1183 | 1193 | $APSkipKey = wfMemcKey( 'flaggedrevs', 'autopromote-skip', $user->getId() ); |
1184 | | - $value = $wgMemc->get( $APSkipKey ); |
1185 | | - if ( $value == 'true' ) return true; |
1186 | | - # Check if user edited enough content pages |
1187 | | - $totalCheckedEditsNeeded = false; |
1188 | | - if ( $wgFlaggedRevsAutopromote['totalContentEdits'] > $p['totalContentEdits'] ) { |
1189 | | - if ( !$wgFlaggedRevsAutopromote['totalCheckedEdits'] ) { |
1190 | | - return true; |
1191 | | - } |
1192 | | - $totalCheckedEditsNeeded = true; |
1193 | | - } |
1194 | | - # Check if user edited enough unique pages |
1195 | | - $pages = $p['uniqueContentPages']; // page IDs |
1196 | | - if ( $wgFlaggedRevsAutopromote['uniqueContentPages'] > count( $pages ) ) { |
| 1194 | + if ( $wgMemc->get( $APSkipKey ) === 'true' ) { |
1197 | 1195 | return true; |
1198 | 1196 | } |
1199 | | - # Check edit comment use |
1200 | | - if ( $wgFlaggedRevsAutopromote['editComments'] > $p['editComments'] ) { |
| 1197 | + # Check if user was ever blocked before |
| 1198 | + if ( $conds['neverBlocked'] && self::wasPreviouslyBlocked( $user ) ) { |
| 1199 | + $wgMemc->set( $APSkipKey, 'true', 3600 * 24 * 7 ); // cache results |
1201 | 1200 | return true; |
1202 | 1201 | } |
1203 | | - # Check reverted edits |
1204 | | - if ( $wgFlaggedRevsAutopromote['maxRevertedEdits'] < $p['revertedEdits'] ) { |
1205 | | - return true; |
1206 | | - } |
1207 | | - # Check account age |
1208 | | - $now = time(); |
1209 | | - $usercreation = wfTimestampOrNull( TS_UNIX, $user->getRegistration() ); |
1210 | | - $userage = $usercreation ? floor( ( $now - $usercreation ) / 86400 ) : null; |
1211 | | - if ( !is_null( $userage ) && $userage < $wgFlaggedRevsAutopromote['days'] ) { |
1212 | | - return true; |
1213 | | - } |
1214 | | - # Check user edit count. Should be stored. |
1215 | | - if ( $user->getEditCount() < $wgFlaggedRevsAutopromote['edits'] ) { |
1216 | | - return true; |
1217 | | - } |
1218 | | - # Don't grant to currently blocked users... |
1219 | | - if ( $user->isBlocked() ) { |
1220 | | - return true; |
1221 | | - } |
1222 | | - # Check if user was ever blocked before |
1223 | | - if ( $wgFlaggedRevsAutopromote['neverBlocked'] ) { |
1224 | | - $blocked = self::previousBlockCheck( $user ); |
1225 | | - if ( $blocked ) { |
1226 | | - # Make a key to store the results |
1227 | | - $wgMemc->set( $APSkipKey, 'true', 3600 * 24 * 7 ); |
1228 | | - return true; |
1229 | | - } |
1230 | | - } |
1231 | 1202 | $dbr = wfGetDB( DB_SLAVE ); |
1232 | | - # See if the page actually has sufficient content... |
1233 | | - if ( $wgFlaggedRevsAutopromote['userpageBytes'] > 0 ) { |
1234 | | - if ( !$user->getUserPage()->exists() ) { |
1235 | | - return true; |
| 1203 | + $cutoff_ts = 0; |
| 1204 | + # Check to see if the user has enough non-"last minute" edits. |
| 1205 | + if ( $conds['excludeLastDays'] > 0 ) { |
| 1206 | + $minDiffAll = $user->getEditCount() - $conds['edits'] + 1; |
| 1207 | + # Get cutoff timestamp |
| 1208 | + $cutoff_ts = time() - 86400*$conds['excludeLastDays']; |
| 1209 | + $encCutoff = $dbr->addQuotes( $dbr->timestamp( $cutoff_ts ) ); |
| 1210 | + # Check all recent edits... |
| 1211 | + $res = $dbr->select( 'revision', '1', |
| 1212 | + array( 'rev_user' => $user->getId(), "rev_timestamp > $encCutoff" ), |
| 1213 | + __METHOD__, |
| 1214 | + array( 'USE INDEX' => 'user_timestamp', 'LIMIT' => $minDiffAll ) |
| 1215 | + ); |
| 1216 | + if ( $dbr->numRows( $res ) >= $minDiffAll ) { |
| 1217 | + return true; // delay promotion |
1236 | 1218 | } |
1237 | | - $size = $dbr->selectField( 'page', 'page_len', |
1238 | | - array( 'page_namespace' => $user->getUserPage()->getNamespace(), |
1239 | | - 'page_title' => $user->getUserPage()->getDBkey() ), |
1240 | | - __METHOD__ ); |
1241 | | - if ( $size < $wgFlaggedRevsAutopromote['userpageBytes'] ) { |
1242 | | - return true; |
| 1219 | + # Check recent content edits... |
| 1220 | + if ( !$failedContentEdits && $wgContentNamespaces ) { |
| 1221 | + $minDiffContent = $p['totalContentEdits'] - $conds['totalContentEdits'] + 1; |
| 1222 | + $res = $dbr->select( array( 'revision', 'page' ), '1', |
| 1223 | + array( 'rev_user' => $user->getId(), |
| 1224 | + "rev_timestamp > $encCutoff", |
| 1225 | + 'rev_page = page_id', |
| 1226 | + 'page_namespace' => $wgContentNamespaces ), |
| 1227 | + __METHOD__, |
| 1228 | + array( 'USE INDEX' => array( 'revision' => 'user_timestamp' ), |
| 1229 | + 'LIMIT' => $minDiffContent ) |
| 1230 | + ); |
| 1231 | + if ( $dbr->numRows( $res ) >= $minDiffContent ) { |
| 1232 | + $failedContentEdits = true; // totalCheckedEdits needed |
| 1233 | + } |
1243 | 1234 | } |
1244 | 1235 | } |
1245 | 1236 | # Check for edit spacing. This lets us know that the account has |
1246 | 1237 | # been used over N different days, rather than all in one lump. |
1247 | | - if ( $wgFlaggedRevsAutopromote['spacing'] > 0 |
1248 | | - && $wgFlaggedRevsAutopromote['benchmarks'] > 1 ) |
1249 | | - { |
1250 | | - $sTestKey = wfMemcKey( 'flaggedrevs', 'autopromote-spacing-ok', $user->getId() ); |
1251 | | - $value = $wgMemc->get( $sTestKey ); |
1252 | | - # Check if the user already passed this test via cache. |
1253 | | - # If no cache key is available, then check the DB... |
1254 | | - if ( $value !== 'true' ) { |
1255 | | - $pass = self::editSpacingCheck( |
1256 | | - $wgFlaggedRevsAutopromote['spacing'], |
1257 | | - $wgFlaggedRevsAutopromote['benchmarks'], |
1258 | | - $user |
1259 | | - ); |
1260 | | - # Make a key to store the results |
1261 | | - if ( $pass === true ) { |
1262 | | - $wgMemc->set( $sTestKey, 'true', 7 * 24 * 3600 ); |
1263 | | - } else { |
1264 | | - $wgMemc->set( $APSkipKey, 'true', $pass /* wait time */ ); |
1265 | | - return true; |
1266 | | - } |
| 1238 | + if ( $conds['spacing'] > 0 && $conds['benchmarks'] > 1 ) { |
| 1239 | + $pass = self::editSpacingCheck( $conds['spacing'], $conds['benchmarks'], $user ); |
| 1240 | + if ( $pass !== true ) { |
| 1241 | + $wgMemc->set( $APSkipKey, 'true', $pass /* wait time */ ); // cache results |
| 1242 | + return true; |
1267 | 1243 | } |
1268 | 1244 | } |
1269 | | - $deletedEdits = $recentEdits = 0; |
1270 | | - # Get one plus the surplus of edits needed |
1271 | | - $minDiff = $user->getEditCount() - $wgFlaggedRevsAutopromote['edits'] + 1; |
1272 | | - # Check to see if the user has so many deleted edits that |
1273 | | - # they don't actually enough live edits. This is because |
1274 | | - # $user->getEditCount() is the count of edits made, not live. |
1275 | | - # NOTE: check skipped if the query gets large (due to high edit count surplus) |
1276 | | - if ( $wgFlaggedRevsAutopromote['excludeDeleted'] && $minDiff <= 200 ) { |
1277 | | - $res = $dbr->select( 'archive', '1', |
1278 | | - array( 'ar_user_text' => $user->getName() ), |
1279 | | - __METHOD__, |
1280 | | - array( 'USE INDEX' => 'usertext_timestamp', 'LIMIT' => $minDiff ) ); |
1281 | | - $deletedEdits = $dbr->numRows( $res ); |
1282 | | - } |
1283 | | - # Check to see if the user made almost all their edits at |
1284 | | - # the last minute and delay promotion if that is the case. |
1285 | | - if ( $wgFlaggedRevsAutopromote['excludeLastDays'] > 0 ) { |
1286 | | - $cutoff_unixtime = time() - 86400*$wgFlaggedRevsAutopromote['excludeLastDays']; |
1287 | | - $encCutoff = $dbr->addQuotes( $dbr->timestamp( $cutoff_unixtime ) ); |
1288 | | - $res = $dbr->select( 'revision', '1', |
1289 | | - array( 'rev_user' => $user->getId(), "rev_timestamp > $encCutoff" ), |
1290 | | - __METHOD__, |
1291 | | - array( 'USE INDEX' => 'user_timestamp', 'LIMIT' => $minDiff ) |
1292 | | - ); |
1293 | | - $recentEdits = $dbr->numRows( $res ); |
1294 | | - } |
1295 | | - # Are too many edits deleted or too recent to count? |
1296 | | - if ( ( $deletedEdits + $recentEdits ) >= $minDiff ) { |
1297 | | - return true; |
1298 | | - } |
1299 | | - # Check implicitly checked edits |
1300 | | - if ( $totalCheckedEditsNeeded && $wgFlaggedRevsAutopromote['totalCheckedEdits'] ) { |
1301 | | - $res = $dbr->select( array( 'revision', 'flaggedpages' ), '1', |
1302 | | - array( 'rev_user' => $user->getId(), |
1303 | | - 'fp_page_id = rev_page', 'fp_stable >= rev_id' ), |
1304 | | - __METHOD__, |
1305 | | - array( 'USE INDEX' => array( 'revision' => 'user_timestamp' ), |
1306 | | - 'LIMIT' => $wgFlaggedRevsAutopromote['totalCheckedEdits'] ) |
1307 | | - ); |
1308 | | - if ( $dbr->numRows( $res ) < $wgFlaggedRevsAutopromote['totalCheckedEdits'] ) { |
| 1245 | + # Check if there are enough implicitly reviewed edits |
| 1246 | + if ( $failedContentEdits && $conds['totalCheckedEdits'] > 0 ) { |
| 1247 | + if ( !self::reviewedEditsCheck( $user, $conds['totalCheckedEdits'], $cutoff_ts ) ) { |
1309 | 1248 | return true; |
1310 | 1249 | } |
1311 | 1250 | } |
1312 | | - # Add editor rights |
1313 | | - $newGroups = $groups ; |
1314 | | - array_push( $newGroups, 'editor' ); |
1315 | 1251 | |
| 1252 | + # Add editor rights... |
| 1253 | + $newGroups = $groups; |
| 1254 | + array_push( $newGroups, 'editor' ); |
1316 | 1255 | $log = new LogPage( 'rights', false /* $rc */ ); |
1317 | 1256 | $log->addEntry( 'rights', |
1318 | 1257 | $user->getUserPage(), |