Index: trunk/phase3/languages/messages/MessagesEn.php |
— | — | @@ -439,6 +439,9 @@ |
440 | 440 | 'Blankpage' => array( 'BlankPage' ), |
441 | 441 | 'LinkSearch' => array( 'LinkSearch' ), |
442 | 442 | 'DeletedContributions' => array( 'DeletedContributions' ), |
| 443 | + 'ListUserRestrictions' => array( 'ListUserRestrictions' ), |
| 444 | + 'RemoveRestrictions' => array( 'RemoveRestrictions' ), |
| 445 | + 'RestrictUser' => array( 'RestrictUser' ), |
443 | 446 | ); |
444 | 447 | |
445 | 448 | /** |
— | — | @@ -1197,7 +1200,23 @@ |
1198 | 1201 | 'edit-no-change' => 'Your edit was ignored, because no change was made to the text.', |
1199 | 1202 | 'edit-already-exists' => 'Could not create a new page. |
1200 | 1203 | It already exists.', |
| 1204 | +'userrestricted-page' => "<big>'''Your user name or IP address has been restricted from editing page \"$1\".'''</big> |
1201 | 1205 | |
| 1206 | +The restriction was put by [[User:$2|$2]]. |
| 1207 | +The reason given is ''$3''. |
| 1208 | + |
| 1209 | +Restriction was put at $4 and expires at $5. |
| 1210 | + |
| 1211 | +You can contact [[User:$2|$2]] or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the restriction.", |
| 1212 | +'userrestricted-namespace' => "<big>'''Your user name or IP address has been restricted from editing $1 namespace.'''</big> |
| 1213 | + |
| 1214 | +The restriction was put by [[User:$2|$2]]. |
| 1215 | +The reason given is ''$3''. |
| 1216 | + |
| 1217 | +Restriction was put at $4 and expires at $5. |
| 1218 | + |
| 1219 | +You can contact [[User:$2|$2]] or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the restriction.", |
| 1220 | + |
1202 | 1221 | # Parser/template warnings |
1203 | 1222 | 'expensive-parserfunction-warning' => 'Warning: This page contains too many expensive parser function calls. |
1204 | 1223 | |
— | — | @@ -1637,6 +1656,7 @@ |
1638 | 1657 | 'right-userrights' => 'Edit all user rights', |
1639 | 1658 | 'right-userrights-interwiki' => 'Edit user rights of users on other wikis', |
1640 | 1659 | 'right-siteadmin' => 'Lock and unlock the database', |
| 1660 | +'right-restrict' => 'Restrict user from editing certain namespaces and pages', |
1641 | 1661 | |
1642 | 1662 | # User rights log |
1643 | 1663 | 'rightslog' => 'User rights log', |
— | — | @@ -2497,6 +2517,7 @@ |
2498 | 2518 | 'ipbsubmit' => 'Block this user', |
2499 | 2519 | 'ipbother' => 'Other time:', |
2500 | 2520 | 'ipboptions' => '2 hours:2 hours,1 day:1 day,3 days:3 days,1 week:1 week,2 weeks:2 weeks,1 month:1 month,3 months:3 months,6 months:6 months,1 year:1 year,infinite:infinite', # display1:time1,display2:time2,... |
| 2521 | +'ipbinfinite' => 'infinite', |
2501 | 2522 | 'ipbotheroption' => 'other', |
2502 | 2523 | 'ipbotherreason' => 'Other/additional reason:', |
2503 | 2524 | 'ipbhidename' => 'Hide username from the block log, active block list and user list', |
— | — | @@ -2569,6 +2590,69 @@ |
2570 | 2591 | You cannot create an account', |
2571 | 2592 | 'cant-block-while-blocked' => 'You cannot block other users while you are blocked.', |
2572 | 2593 | |
| 2594 | +# Special:ListUserRestrictions |
| 2595 | +'listuserrestrictions' => 'List of user restrictions', |
| 2596 | +'listuserrestrictions-intro' => 'This list contains all restrictions from editing certain pages and namespaces put on users. |
| 2597 | +Note that blocks are listed [[Special:Ipblocklist|there]] and are not listed here.', |
| 2598 | +'listuserrestrictions-row-ns' => 'restricted $1 from editing $2 namespace ($3)', |
| 2599 | +'listuserrestrictions-row-page' => 'restricted $1 from editing $2 ($3)', |
| 2600 | +'listuserrestrictions-row-expiry' => 'expires at $1', |
| 2601 | +'listuserrestrictions-legend' => 'Find a restriction', |
| 2602 | +'listuserrestrictions-type' => 'Type:', |
| 2603 | +'listuserrestrictions-user' => 'User:', |
| 2604 | +'listuserrestrictions-namespace' => 'Namespace:', |
| 2605 | +'listuserrestrictions-page' => 'Page:', |
| 2606 | +'listuserrestrictions-submit' => 'Go', |
| 2607 | +'listuserrestrictions-notfound' => 'There is no restriction that matches specified criteria.', |
| 2608 | +'listuserrestrictions-empty' => 'This list is empty.', |
| 2609 | +'listuserrestrictions-remove' => 'remove', |
| 2610 | +'userrestrictiontype-none' => '(none)', |
| 2611 | +'userrestrictiontype-namespace' => 'Namespace', |
| 2612 | +'userrestrictiontype-page' => 'Page', |
| 2613 | + |
| 2614 | +# Special:RemoveRestrictions |
| 2615 | +'removerestrictions' => 'Remove restriction from a user', |
| 2616 | +'removerestrictions-intro' => 'Use the form below to remove a restriction from a certain user.', |
| 2617 | +'removerestrictions-noid' => 'No restriction ID was specified.', |
| 2618 | +'removerestrictions-wrongid' => 'Restriction with that ID not found. Most probably someone has removed it or it expired.', |
| 2619 | +'removerestrictions-legend' => 'Remove a restriction', |
| 2620 | +'removerestrictions-user' => 'Restricted user:', |
| 2621 | +'removerestrictions-type' => 'Restriction type:', |
| 2622 | +'removerestrictions-page' => 'Page:', |
| 2623 | +'removerestrictions-namespace' => 'Namespace:', |
| 2624 | +'removerestrictions-reason' => 'Reason:', |
| 2625 | +'removerestrictions-submit' => 'Remove the restriction', |
| 2626 | +'removerestrictions-success' => 'Successfully removed the restriction from [[User:$1|$1]].', |
| 2627 | + |
| 2628 | +# Special:RestrictUser |
| 2629 | +'restrictuser' => 'Restrict user', |
| 2630 | +'restrictuser-userselect' => 'Select a user', |
| 2631 | +'restrictuser-user' => 'User:', |
| 2632 | +'restrictuser-go' => 'Restrict user', |
| 2633 | +'restrictuser-notfound' => 'User not found', |
| 2634 | +'restrictuser-existing' => 'Existing restrictions', |
| 2635 | +'restrictuser-legend-page' => 'Restrict from editing certain page', |
| 2636 | +'restrictuser-legend-namespace' => 'Restrict from editing certain namespace', |
| 2637 | +'restrictuser-title' => 'Page to restrict:', |
| 2638 | +'restrictuser-namespace' => 'Namespace:', |
| 2639 | +'restrictuser-expiry' => 'Expires:', |
| 2640 | +'restrictuser-reason' => 'Reason:', |
| 2641 | +'restrictuser-sumbit' => 'Restrict user', |
| 2642 | +'restrictuser-badtitle' => 'Invalid title specified: $1.', |
| 2643 | +'restrictuser-badnamespace' => 'Invalid namespace specified.', |
| 2644 | +'restrictuser-badexpiry' => 'Invalid expiry specified: $1.', |
| 2645 | +'restrictuser-duptitle' => 'User is already restricted from editing this title.', |
| 2646 | +'restrictuser-dupnamespace' => 'User is already restricted from editing this namespace.', |
| 2647 | +'restrictuser-success' => 'Successfully restricted user $1.', |
| 2648 | + |
| 2649 | +# Special:Log/restrict |
| 2650 | +'restrictionlog' => 'User restriction log', |
| 2651 | +'restrictionlogtext' => 'This log contains all restrictions put on users by administrators.', |
| 2652 | +'restrictentry' => 'restricted $1 from editing $2 (expiry set to $3)', |
| 2653 | +'restrictremoveentry' => 'removed restriction from $1 for editing $2', |
| 2654 | +'restrictlognamespace' => '$1 namespace', |
| 2655 | +'restrictlogpage' => '[[$1]]', |
| 2656 | + |
2573 | 2657 | # Developer tools |
2574 | 2658 | 'lockdb' => 'Lock database', |
2575 | 2659 | 'unlockdb' => 'Unlock database', |
Index: trunk/phase3/languages/Language.php |
— | — | @@ -265,6 +265,20 @@ |
266 | 266 | } |
267 | 267 | |
268 | 268 | /** |
| 269 | + * A convenience function that returns the same thing as |
| 270 | + * getFormattedNsText() except with '(Main)' for zero namespace. |
| 271 | + * |
| 272 | + * @return array |
| 273 | + */ |
| 274 | + function getDisplayNsText( $index ) { |
| 275 | + if( $index == 0 ) { |
| 276 | + return wfMsg( 'blanknamespace' ); |
| 277 | + } else { |
| 278 | + return $this->getFormattedNsText( $index ); |
| 279 | + } |
| 280 | + } |
| 281 | + |
| 282 | + /** |
269 | 283 | * Get a namespace key by value, case insensitive. |
270 | 284 | * Only matches namespace names for the current language, not the |
271 | 285 | * canonical ones defined in Namespace.php. |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -144,8 +144,9 @@ |
145 | 145 | query string use the article path, rather than the script path |
146 | 146 | * Added the ability to set the target attribute on external links with |
147 | 147 | $wgExternalLinkTarget |
| 148 | +* (bug 674) Allow admins to block users from editing specific articles and |
| 149 | + namespaces |
148 | 150 | |
149 | | - |
150 | 151 | === Bug fixes in 1.14 === |
151 | 152 | |
152 | 153 | * (bug 14907) DatabasePostgres::fieldType now defined. |
Index: trunk/phase3/maintenance/archives/patch-user_restrictions.sql |
— | — | @@ -0,0 +1,40 @@ |
| 2 | +-- Allows admins to block user from editing certain namespaces or pages |
| 3 | + |
| 4 | +CREATE TABLE /*$wgDBprefix*/user_restrictions ( |
| 5 | + -- ID of the restriction |
| 6 | + ur_id int NOT NULL auto_increment, |
| 7 | + |
| 8 | + -- Restriction type. Block from either editing namespace or page |
| 9 | + ur_type varbinary(255) NOT NULL, |
| 10 | + -- Namespace to restrict if ur_type = namespace |
| 11 | + ur_namespace int default NULL, |
| 12 | + -- Page to restrict if ur_type = page |
| 13 | + ur_page_namespace int default NULL, |
| 14 | + ur_page_title varchar(255) binary default '', |
| 15 | + |
| 16 | + -- User that is restricted |
| 17 | + ur_user int unsigned NOT NULL, |
| 18 | + ur_user_text tinyblob NOT NULL, |
| 19 | + |
| 20 | + -- User who has done this restriction |
| 21 | + ur_by int unsigned NOT NULL, |
| 22 | + ur_by_text varchar(255) binary NOT NULL default '', |
| 23 | + -- Reason for this restriction |
| 24 | + ur_reason tinyblob NOT NULL, |
| 25 | + |
| 26 | + -- Time when this restriction was made |
| 27 | + ur_timestamp varbinary(14) NOT NULL default '', |
| 28 | + -- Expiry or "infinity" |
| 29 | + ur_expiry varbinary(14) NOT NULL default '', |
| 30 | + |
| 31 | + PRIMARY KEY ur_id (ur_id), |
| 32 | + -- For looking up restrictions for user |
| 33 | + INDEX ur_user (ur_user,ur_user_text(255)), |
| 34 | + -- For Special:ListUserRestrictions |
| 35 | + INDEX ur_type (ur_type(255),ur_timestamp), |
| 36 | + INDEX ur_namespace (ur_namespace,ur_timestamp), |
| 37 | + INDEX ur_page (ur_page_namespace,ur_page_title,ur_timestamp), |
| 38 | + INDEX ur_timestamp (ur_timestamp), |
| 39 | + -- For quick removal of expired restrictions |
| 40 | + INDEX ur_expiry (ur_expiry) |
| 41 | +) /*$wgDBTableOptions*/; |
Property changes on: trunk/phase3/maintenance/archives/patch-user_restrictions.sql |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 42 | + native |
Index: trunk/phase3/maintenance/tables.sql |
— | — | @@ -1243,4 +1243,44 @@ |
1244 | 1244 | PRIMARY KEY (ul_key) |
1245 | 1245 | ) /*$wgDBTableOptions*/; |
1246 | 1246 | |
| 1247 | +-- Allows admins to block user from editing certain namespaces or pages |
| 1248 | +CREATE TABLE /*$wgDBprefix*/user_restrictions ( |
| 1249 | + -- ID of the restriction |
| 1250 | + ur_id int NOT NULL auto_increment, |
| 1251 | + |
| 1252 | + -- Restriction type. Block from either editing namespace or page |
| 1253 | + ur_type varbinary(255) NOT NULL, |
| 1254 | + -- Namespace to restrict if ur_type = namespace |
| 1255 | + ur_namespace int default NULL, |
| 1256 | + -- Page to restrict if ur_type = page |
| 1257 | + ur_page_namespace int default NULL, |
| 1258 | + ur_page_title varchar(255) binary default '', |
| 1259 | + |
| 1260 | + -- User that is restricted |
| 1261 | + ur_user int unsigned NOT NULL, |
| 1262 | + ur_user_text tinyblob NOT NULL, |
| 1263 | + |
| 1264 | + -- User who has done this restriction |
| 1265 | + ur_by int unsigned NOT NULL, |
| 1266 | + ur_by_text varchar(255) binary NOT NULL default '', |
| 1267 | + -- Reason for this restriction |
| 1268 | + ur_reason tinyblob NOT NULL, |
| 1269 | + |
| 1270 | + -- Time when this restriction was made |
| 1271 | + ur_timestamp varbinary(14) NOT NULL default '', |
| 1272 | + -- Expiry or "infinity" |
| 1273 | + ur_expiry varbinary(14) NOT NULL default '', |
| 1274 | + |
| 1275 | + PRIMARY KEY ur_id (ur_id), |
| 1276 | + -- For looking up restrictions for user |
| 1277 | + INDEX ur_user (ur_user,ur_user_text(255)), |
| 1278 | + -- For Special:ListUserRestrictions |
| 1279 | + INDEX ur_type (ur_type(255),ur_timestamp), |
| 1280 | + INDEX ur_namespace (ur_namespace,ur_timestamp), |
| 1281 | + INDEX ur_page (ur_page_namespace,ur_page_title,ur_timestamp), |
| 1282 | + INDEX ur_timestamp (ur_timestamp), |
| 1283 | + -- For quick removal of expired restrictions |
| 1284 | + INDEX ur_expiry (ur_expiry) |
| 1285 | +) /*$wgDBTableOptions*/; |
| 1286 | + |
1247 | 1287 | -- vim: sw=2 sts=2 et |
Index: trunk/phase3/maintenance/updaters.inc |
— | — | @@ -145,9 +145,10 @@ |
146 | 146 | array( 'update_password_format' ), |
147 | 147 | |
148 | 148 | // 1.14 |
149 | | - array( 'add_field', 'site_stats', 'ss_active_users', 'patch-ss_active_users.sql' ), |
| 149 | + array( 'add_field', 'site_stats', 'ss_active_users', 'patch-ss_active_users.sql' ), |
150 | 150 | array( 'do_active_users_init' ), |
151 | | - array( 'add_field', 'ipblocks', 'ipb_allow_usertalk', 'patch-ipb_allow_usertalk.sql' ) |
| 151 | + array( 'add_field', 'ipblocks', 'ipb_allow_usertalk', 'patch-ipb_allow_usertalk.sql' ), |
| 152 | + array( 'add_table', 'user_restrictions', 'patch-user_restrictions.sql' ), |
152 | 153 | ); |
153 | 154 | |
154 | 155 | |
Index: trunk/phase3/includes/specials/SpecialRemoveRestrictions.php |
— | — | @@ -0,0 +1,62 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +function wfSpecialRemoveRestrictions() { |
| 5 | + global $wgOut, $wgRequest, $wgUser, $wgLang, $wgTitle; |
| 6 | + $sk = $wgUser->getSkin(); |
| 7 | + |
| 8 | + $id = $wgRequest->getVal( 'id' ); |
| 9 | + if( !is_numeric( $id ) ) { |
| 10 | + $wgOut->addWikiMsg( 'removerestrictions-noid' ); |
| 11 | + return; |
| 12 | + } |
| 13 | + |
| 14 | + UserRestriction::purgeExpired(); |
| 15 | + $r = UserRestriction::newFromId( $id, true ); |
| 16 | + if( !$r ) { |
| 17 | + $wgOut->addWikiMsg( 'removerestrictions-wrongid' ); |
| 18 | + return; |
| 19 | + } |
| 20 | + |
| 21 | + $legend = wfMsgHtml( 'removerestrictions-legend' ); |
| 22 | + |
| 23 | + $form = array(); |
| 24 | + $form['removerestrictions-user'] = $sk->userLink( $r->getSubjectId(), $r->getSubjectText() ) . |
| 25 | + $sk->userToolLinks( $r->getSubjectId(), $r->getSubjectText() ); |
| 26 | + $form['removerestrictions-type'] = UserRestriction::formatType( $r->getType() ); |
| 27 | + if( $r->isPage() ) |
| 28 | + $form['removerestrictions-page'] = $sk->link( $r->getPage() ); |
| 29 | + if( $r->isNamespace() ) |
| 30 | + $form['removerestrictions-namespace'] = $wgLang->getDisplayNsText( $r->getNamespace() ); |
| 31 | + $form['removerestrictions-reason'] = Xml::input( 'reason' ); |
| 32 | + |
| 33 | + $result = null; |
| 34 | + if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal( 'edittoken' ) ) ) |
| 35 | + $result = wfSpecialRemoveRestrictionsProcess( $r ); |
| 36 | + |
| 37 | + $wgOut->addWikiMsg( 'removerestrictions-intro' ); |
| 38 | + $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" ); |
| 39 | + if( $result ) |
| 40 | + $wgOut->addHTML( '<strong class="success">' . wfMsgExt( 'removerestrictions-success', |
| 41 | + 'parseinline', $r->getSubjectText() ) . '</strong>' ); |
| 42 | + $wgOut->addHTML( Xml::openElement( 'form', array( 'action' => $wgTitle->getLocalUrl( array( 'id' => $id ) ), |
| 43 | + 'method' => 'post' ) ) ); |
| 44 | + $wgOut->addHTML( Xml::buildForm( $form, 'removerestrictions-submit' ) ); |
| 45 | + $wgOut->addHTML( Xml::hidden( 'id', $r->getId() ) ); |
| 46 | + $wgOut->addHTML( Xml::hidden( 'title', $wgTitle->getPrefixedDbKey() ) ); |
| 47 | + $wgOut->addHTML( Xml::hidden( 'edittoken', $wgUser->editToken() ) ); |
| 48 | + $wgOut->addHTML( "</form></fieldset>" ); |
| 49 | +} |
| 50 | + |
| 51 | +function wfSpecialRemoveRestrictionsProcess( $r ) { |
| 52 | + global $wgUser, $wgRequest; |
| 53 | + $reason = $wgRequest->getVal( 'reason' ); |
| 54 | + $result = $r->delete(); |
| 55 | + $log = new LogPage( 'restrict' ); |
| 56 | + $params = array( $r->getType() ); |
| 57 | + if( $r->isPage() ) |
| 58 | + $params[] = $r->getPage()->getPrefixedDbKey(); |
| 59 | + if( $r->isNamespace() ) |
| 60 | + $params[] = $r->getNamespace(); |
| 61 | + $log->addEntry( 'remove', Title::makeTitle( NS_USER, $r->getSubjectText() ), $reason, $params ); |
| 62 | + return $result; |
| 63 | +} |
Property changes on: trunk/phase3/includes/specials/SpecialRemoveRestrictions.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 64 | + native |
Index: trunk/phase3/includes/specials/SpecialListUserRestrictions.php |
— | — | @@ -0,0 +1,162 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +function wfSpecialListUserRestrictions() { |
| 5 | + global $wgOut, $wgRequest; |
| 6 | + |
| 7 | + $wgOut->addWikiMsg( 'listuserrestrictions-intro' ); |
| 8 | + $f = new SpecialListUserRestrictionsForm(); |
| 9 | + $wgOut->addHTML( $f->getHTML() ); |
| 10 | + |
| 11 | + if( !mt_rand( 0, 10 ) ) |
| 12 | + UserRestriction::purgeExpired(); |
| 13 | + $pager = new UserRestrictionsPager( $f->getConds() ); |
| 14 | + if( $pager->getNumRows() ) |
| 15 | + $wgOut->addHTML( $pager->getNavigationBar() . |
| 16 | + Xml::tags( 'ul', null, $pager->getBody() ) . |
| 17 | + $pager->getNavigationBar() |
| 18 | + ); |
| 19 | + elseif( $f->getConds() ) |
| 20 | + $wgOut->addWikiMsg( 'listuserrestrictions-notfound' ); |
| 21 | + else |
| 22 | + $wgOut->addWikiMsg( 'listuserrestrictions-empty' ); |
| 23 | +} |
| 24 | + |
| 25 | +class SpecialListUserRestrictionsForm { |
| 26 | + public function getHTML() { |
| 27 | + global $wgRequest, $wgScript, $wgTitle; |
| 28 | + $s = ''; |
| 29 | + $legend = wfMsgHtml( 'listuserrestrictions-legend' ); |
| 30 | + $s .= "<fieldset><legend>{$legend}</legend>"; |
| 31 | + $s .= "<form action=\"{$wgScript}\">"; |
| 32 | + $s .= Xml::hidden( 'title', $wgTitle->getPrefixedDbKey() ); |
| 33 | + $s .= Xml::label( wfMsgHtml( 'listuserrestrictions-type' ), 'type' ) . ' ' . |
| 34 | + self::typeSelector( 'type', $wgRequest->getVal( 'type' ), 'type' ); |
| 35 | + $s .= ' '; |
| 36 | + $s .= Xml::inputLabel( wfMsgHtml( 'listuserrestrictions-user' ), 'user', 'user', |
| 37 | + false, $wgRequest->getVal( 'user' ) ); |
| 38 | + $s .= '<p>'; |
| 39 | + $s .= Xml::label( wfMsgHtml( 'listuserrestrictions-namespace' ), 'namespace' ) . ' ' . |
| 40 | + Xml::namespaceSelector( $wgRequest->getVal( 'namespace' ), '', false, 'namespace' ); |
| 41 | + $s .= ' '; |
| 42 | + $s .= Xml::inputLabel( wfMsgHtml( 'listuserrestrictions-page' ), 'page', 'page', |
| 43 | + false, $wgRequest->getVal( 'page' ) ); |
| 44 | + $s .= Xml::submitButton( wfMsgHtml( 'listuserrestrictions-submit' ) ); |
| 45 | + $s .= "</p></form></fieldset>"; |
| 46 | + return $s; |
| 47 | + } |
| 48 | + |
| 49 | + public static function typeSelector( $name = 'type', $value = '', $id = false ) { |
| 50 | + $s = new XmlSelect( $name, $id, $value ); |
| 51 | + $s->addOption( wfMsg( 'userrestrictiontype-none' ), '' ); |
| 52 | + $s->addOption( wfMsg( 'userrestrictiontype-page' ), UserRestriction::PAGE ); |
| 53 | + $s->addOption( wfMsg( 'userrestrictiontype-namespace' ), UserRestriction::NAMESPACE ); |
| 54 | + return $s->getHTML(); |
| 55 | + } |
| 56 | + |
| 57 | + public function getConds() { |
| 58 | + global $wgRequest; |
| 59 | + $conds = array(); |
| 60 | + |
| 61 | + $type = $wgRequest->getVal( 'type' ); |
| 62 | + if( in_array( $type, array( UserRestriction::PAGE, UserRestriction::NAMESPACE ) ) ) |
| 63 | + $conds['ur_type'] = $type; |
| 64 | + |
| 65 | + $user = $wgRequest->getVal( 'user' ); |
| 66 | + if( $user ) |
| 67 | + $conds['ur_user_text'] = $user; |
| 68 | + |
| 69 | + $namespace = $wgRequest->getVal( 'namespace' ); |
| 70 | + if( $namespace || $namespace === '0' ) |
| 71 | + $conds['ur_namespace'] = $namespace; |
| 72 | + |
| 73 | + $page = $wgRequest->getVal( 'page' ); |
| 74 | + $title = Title::newFromText( $page ); |
| 75 | + if( $title ) { |
| 76 | + $conds['ur_page_namespace'] = $title->getNamespace(); |
| 77 | + $conds['ur_page_title'] = $title->getDbKey(); |
| 78 | + } |
| 79 | + |
| 80 | + return $conds; |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +class UserRestrictionsPager extends ReverseChronologicalPager { |
| 85 | + public $mConds; |
| 86 | + |
| 87 | + public function __construct( $conds = array() ) { |
| 88 | + $this->mConds = $conds; |
| 89 | + parent::__construct(); |
| 90 | + } |
| 91 | + |
| 92 | + public function getStartBody() { |
| 93 | + # Copied from Special:Ipblocklist |
| 94 | + wfProfileIn( __METHOD__ ); |
| 95 | + # Do a link batch query |
| 96 | + $this->mResult->seek( 0 ); |
| 97 | + $lb = new LinkBatch; |
| 98 | + |
| 99 | + # Faster way |
| 100 | + # Usernames and titles are in fact related by a simple substitution of space -> underscore |
| 101 | + # The last few lines of Title::secureAndSplit() tell the story. |
| 102 | + foreach( $this->mResult as $row ) { |
| 103 | + $name = str_replace( ' ', '_', $row->ur_by_text ); |
| 104 | + $lb->add( NS_USER, $name ); |
| 105 | + $lb->add( NS_USER_TALK, $name ); |
| 106 | + $name = str_replace( ' ', '_', $row->ur_user_text ); |
| 107 | + $lb->add( NS_USER, $name ); |
| 108 | + $lb->add( NS_USER_TALK, $name ); |
| 109 | + if( $row->ur_type == UserRestriction::PAGE ) |
| 110 | + $lb->add( $row->ur_page_namespace, $row->ur_page_title ); |
| 111 | + } |
| 112 | + $lb->execute(); |
| 113 | + wfProfileOut( __METHOD__ ); |
| 114 | + return ''; |
| 115 | + } |
| 116 | + |
| 117 | + public function getQueryInfo() { |
| 118 | + return array( |
| 119 | + 'tables' => 'user_restrictions', |
| 120 | + 'fields' => '*', |
| 121 | + 'conds' => $this->mConds, |
| 122 | + ); |
| 123 | + } |
| 124 | + |
| 125 | + public function formatRow( $row ) { |
| 126 | + return self::formatRestriction( UserRestriction::newFromRow( $row ) ); |
| 127 | + } |
| 128 | + |
| 129 | + // Split off for use on Special:RestrictUser |
| 130 | + public static function formatRestriction( $r ) { |
| 131 | + global $wgUser, $wgLang; |
| 132 | + $sk = $wgUser->getSkin(); |
| 133 | + $timestamp = $wgLang->timeanddate( $r->getTimestamp(), true ); |
| 134 | + $blockerlink = $sk->userLink( $r->getBlockerId(), $r->getBlockerText() ) . |
| 135 | + $sk->userToolLinks( $r->getBlockerId(), $r->getBlockerText() ); |
| 136 | + $subjlink = $sk->userLink( $r->getSubjectId(), $r->getSubjectText() ) . |
| 137 | + $sk->userToolLinks( $r->getSubjectId(), $r->getSubjectText() ); |
| 138 | + $expiry = is_numeric( $r->getExpiry() ) ? |
| 139 | + wfMsg( 'listuserrestrictions-row-expiry', $wgLang->timeanddate( $r->getExpiry() ) ) : |
| 140 | + wfMsg( 'ipbinfinite' ); |
| 141 | + $msg = ''; |
| 142 | + if( $r->isNamespace() ) { |
| 143 | + $msg = wfMsgHtml( 'listuserrestrictions-row-ns', $subjlink, |
| 144 | + $wgLang->getDisplayNsText( $r->getNamespace() ), $expiry ); |
| 145 | + } |
| 146 | + if( $r->isPage() ) { |
| 147 | + $pagelink = $sk->link( $r->getPage() ); |
| 148 | + $msg = wfMsgHtml( 'listuserrestrictions-row-page', $subjlink, |
| 149 | + $pagelink, $expiry ); |
| 150 | + } |
| 151 | + $reason = $sk->commentBlock( $r->getReason() ); |
| 152 | + $removelink = ''; |
| 153 | + if( $wgUser->isAllowed( 'restrict' ) ) { |
| 154 | + $removelink = '(' . $sk->link( SpecialPage::getTitleFor( 'RemoveRestrictions' ), |
| 155 | + wfMsgHtml( 'listuserrestrictions-remove' ), array(), array( 'id' => $r->getId() ) ) . ')'; |
| 156 | + } |
| 157 | + return "<li>{$timestamp}, {$blockerlink} {$msg} {$reason} {$removelink}</li>\n"; |
| 158 | + } |
| 159 | + |
| 160 | + public function getIndexField() { |
| 161 | + return 'ur_timestamp'; |
| 162 | + } |
| 163 | +} |
Property changes on: trunk/phase3/includes/specials/SpecialListUserRestrictions.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 164 | + native |
Index: trunk/phase3/includes/specials/SpecialRestrictUser.php |
— | — | @@ -0,0 +1,187 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +function wfSpecialRestrictUser( $par = null ) { |
| 5 | + global $wgOut, $wgRequest; |
| 6 | + $user = $userOrig = null; |
| 7 | + if( $par ) { |
| 8 | + $userOrig = $par; |
| 9 | + } elseif( $wgRequest->getVal( 'user' ) ) { |
| 10 | + $userOrig = $wgRequest->getVal( 'user' ); |
| 11 | + } else { |
| 12 | + $wgOut->addHTML( RestrictUserForm::selectUserForm() ); |
| 13 | + return; |
| 14 | + } |
| 15 | + $isIP = User::isIP( $userOrig ); |
| 16 | + if( $isIP ) |
| 17 | + $user = $userOrig; |
| 18 | + else |
| 19 | + $user = User::getCanonicalName( $userOrig ); |
| 20 | + $uid = User::idFromName( $user ); |
| 21 | + if( !$uid && !$isIP ) { |
| 22 | + $err = '<strong class="error">' . wfMsgHtml( 'restrictuser-notfound' ) . '</strong>'; |
| 23 | + $wgOut->addHTML( RestrictUserForm::selectUserForm( $userOrig, $err ) ); |
| 24 | + return; |
| 25 | + } |
| 26 | + $wgOut->addHTML( RestrictUserForm::selectUserForm( $user ) ); |
| 27 | + |
| 28 | + UserRestriction::purgeExpired(); |
| 29 | + $old = UserRestriction::fetchForUser( $user, true ); |
| 30 | + |
| 31 | + RestrictUserForm::pageRestrictionForm( $uid, $user, $old ); |
| 32 | + RestrictUserForm::namespaceRestrictionForm( $uid, $user, $old ); |
| 33 | + |
| 34 | + $old = UserRestriction::fetchForUser( $user, true ); // Renew it after possible changes in previous two functions |
| 35 | + if( $old ) { |
| 36 | + $wgOut->addHTML( RestrictUserForm::existingRestrictions( $old ) ); |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +class RestrictUserForm { |
| 41 | + public static function selectUserForm( $val = null, $error = null ) { |
| 42 | + global $wgScript, $wgTitle; |
| 43 | + $legend = wfMsgHtml( 'restrictuser-userselect' ); |
| 44 | + $s = "<fieldset><legend>{$legend}</legend><form action=\"{$wgScript}\">"; |
| 45 | + if( $error ) |
| 46 | + $s .= '<p>' . $error . '</p>'; |
| 47 | + $s .= Xml::hidden( 'title', $wgTitle->getPrefixedDbKey() ); |
| 48 | + $form = array( 'restrictuser-user' => Xml::input( 'user', false, $val ) ); |
| 49 | + $s .= Xml::buildForm( $form, 'restrictuser-go' ); |
| 50 | + $s .= "</form></fieldset>"; |
| 51 | + return $s; |
| 52 | + } |
| 53 | + |
| 54 | + public static function existingRestrictions( $restrictions ) { |
| 55 | + require_once( dirname( __FILE__ ) . '/SpecialListUserRestrictions.php' ); |
| 56 | + $legend = wfMsgHtml( 'restrictuser-existing' ); |
| 57 | + $s = "<fieldset><legend>{$legend}</legend><ul>"; |
| 58 | + foreach( $restrictions as $r ) |
| 59 | + $s .= UserRestrictionsPager::formatRestriction( $r ); |
| 60 | + $s .= "</ul></fieldset>"; |
| 61 | + return $s; |
| 62 | + } |
| 63 | + |
| 64 | + public static function pageRestrictionForm( $uid, $user, $oldRestrictions ) { |
| 65 | + global $wgOut, $wgTitle, $wgRequest, $wgUser; |
| 66 | + $error = ''; |
| 67 | + $success = false; |
| 68 | + if( $wgRequest->wasPosted() && $wgRequest->getVal( 'type' ) == UserRestriction::PAGE && |
| 69 | + $wgUser->matchEditToken( $wgRequest->getVal( 'edittoken' ) ) ) { |
| 70 | + $title = Title::newFromText( $wgRequest->getVal( 'page' ) ); |
| 71 | + if( !$title ) |
| 72 | + $error = wfMsgExt( 'restrictuser-badtitle', 'parseinline', $wgRequest->getVal( 'page' ) ); |
| 73 | + elseif( UserRestriction::convertExpiry( $wgRequest->getVal( 'expiry' ) ) === false ) |
| 74 | + $error = wfMsgExt( 'restrictuser-badexpiry', 'parseinline', $wgRequest->getVal( 'expiry' ) ); |
| 75 | + else |
| 76 | + foreach( $oldRestrictions as $r ) |
| 77 | + if( $r->isPage() && $r->getPage()->equals( $title ) ) |
| 78 | + $error = wfMsgExt( 'restrictuser-duptitle', 'parse' ); |
| 79 | + if( !$error ) { |
| 80 | + self::doPageRestriction( $uid, $user ); |
| 81 | + $success = true; |
| 82 | + } |
| 83 | + } |
| 84 | + $useRequestValues = $wgRequest->getVal( 'type' ) == UserRestriction::PAGE; |
| 85 | + $legend = wfMsgHtml( 'restrictuser-legend-page' ); |
| 86 | + $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" ); |
| 87 | + if( $error ) |
| 88 | + $wgOut->addHTML( '<strong class="error">' . $error . '</strong>' ); |
| 89 | + if( $success ) |
| 90 | + $wgOut->addHTML( '<strong class="success">' . wfMsgExt( 'restrictuser-success', |
| 91 | + 'parseinline', $user ) . '</strong>' ); |
| 92 | + $wgOut->addHTML( Xml::openElement( 'form', array( 'action' => $wgTitle->getLocalUrl(), |
| 93 | + 'method' => 'post' ) ) ); |
| 94 | + $wgOut->addHTML( Xml::hidden( 'type', UserRestriction::PAGE ) ); |
| 95 | + $wgOut->addHTML( Xml::hidden( 'edittoken', $wgUser->editToken() ) ); |
| 96 | + $wgOut->addHTML( Xml::hidden( 'user', $user ) ); |
| 97 | + $form = array(); |
| 98 | + $form['restrictuser-title'] = Xml::input( 'page', false, |
| 99 | + $useRequestValues ? $wgRequest->getVal( 'page' ) : false ); |
| 100 | + $form['restrictuser-expiry'] = Xml::input( 'expiry', false, |
| 101 | + $useRequestValues ? $wgRequest->getVal( 'expiry' ) : false ); |
| 102 | + $form['restrictuser-reason'] = Xml::input( 'reason', false, |
| 103 | + $useRequestValues ? $wgRequest->getVal( 'reason' ) : false ); |
| 104 | + $wgOut->addHTML( Xml::buildForm( $form, 'restrictuser-sumbit' ) ); |
| 105 | + $wgOut->addHTML( "</form></fieldset>" ); |
| 106 | + } |
| 107 | + |
| 108 | + public static function doPageRestriction( $uid, $user ) { |
| 109 | + global $wgUser, $wgRequest; |
| 110 | + $r = new UserRestriction(); |
| 111 | + $r->setType( UserRestriction::PAGE ); |
| 112 | + $r->setPage( Title::newFromText( $wgRequest->getVal( 'page' ) ) ); |
| 113 | + $r->setSubjectId( $uid ); |
| 114 | + $r->setSubjectText( $user ); |
| 115 | + $r->setBlockerId( $wgUser->getId() ); |
| 116 | + $r->setBlockerText( $wgUser->getName() ); |
| 117 | + $r->setReason( $wgRequest->getVal( 'reason' ) ); |
| 118 | + $r->setExpiry( UserRestriction::convertExpiry( $wgRequest->getVal( 'expiry' ) ) ); |
| 119 | + $r->setTimestamp( wfTimestampNow( TS_MW ) ); |
| 120 | + $r->commit(); |
| 121 | + $logExpiry = $wgRequest->getVal( 'expiry' ) ? $wgRequest->getVal( 'expiry' ) : Block::infinity(); |
| 122 | + $l = new LogPage( 'restrict' ); |
| 123 | + $l->addEntry( 'restrict', Title::makeTitle( NS_USER, $user ), $r->getReason(), |
| 124 | + array( $r->getType(), $r->getPage()->getFullText(), $logExpiry) ); |
| 125 | + } |
| 126 | + |
| 127 | + public static function namespaceRestrictionForm( $uid, $user, $oldRestrictions ) { |
| 128 | + global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgContLang; |
| 129 | + $error = ''; |
| 130 | + $success = false; |
| 131 | + if( $wgRequest->wasPosted() && $wgRequest->getVal( 'type' ) == UserRestriction::NAMESPACE && |
| 132 | + $wgUser->matchEditToken( $wgRequest->getVal( 'edittoken' ) ) ) { |
| 133 | + $ns = $wgRequest->getVal( 'namespace' ); |
| 134 | + if( $wgContLang->getNsText( $ns ) === false ) |
| 135 | + $error = wfMsgExt( 'restrictuser-badnamespace', 'parseinline' ); |
| 136 | + elseif( UserRestriction::convertExpiry( $wgRequest->getVal( 'expiry' ) ) === false ) |
| 137 | + $error = wfMsgExt( 'restrictuser-badexpiry', 'parseinline', $wgRequest->getVal( 'expiry' ) ); |
| 138 | + else |
| 139 | + foreach( $oldRestrictions as $r ) |
| 140 | + if( $r->isNamespace() && $r->getNamespace() == $ns ) |
| 141 | + $error = wfMsgExt( 'restrictuser-dupnamespace', 'parse' ); |
| 142 | + if( !$error ) { |
| 143 | + self::doNamespaceRestriction( $uid, $user ); |
| 144 | + $success = true; |
| 145 | + } |
| 146 | + } |
| 147 | + $useRequestValues = $wgRequest->getVal( 'type' ) == UserRestriction::NAMESPACE; |
| 148 | + $legend = wfMsgHtml( 'restrictuser-legend-namespace' ); |
| 149 | + $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" ); |
| 150 | + if( $error ) |
| 151 | + $wgOut->addHTML( '<strong class="error">' . $error . '</strong>' ); |
| 152 | + if( $success ) |
| 153 | + $wgOut->addHTML( '<strong class="success">' . wfMsgExt( 'restrictuser-success', |
| 154 | + 'parseinline', $user ) . '</strong>' ); |
| 155 | + $wgOut->addHTML( Xml::openElement( 'form', array( 'action' => $wgTitle->getLocalUrl(), |
| 156 | + 'method' => 'post' ) ) ); |
| 157 | + $wgOut->addHTML( Xml::hidden( 'type', UserRestriction::NAMESPACE ) ); |
| 158 | + $wgOut->addHTML( Xml::hidden( 'edittoken', $wgUser->editToken() ) ); |
| 159 | + $wgOut->addHTML( Xml::hidden( 'user', $user ) ); |
| 160 | + $form = array(); |
| 161 | + $form['restrictuser-namespace'] = Xml::namespaceSelector( $wgRequest->getVal( 'namespace' ) ); |
| 162 | + $form['restrictuser-expiry'] = Xml::input( 'expiry', false, |
| 163 | + $useRequestValues ? $wgRequest->getVal( 'expiry' ) : false ); |
| 164 | + $form['restrictuser-reason'] = Xml::input( 'reason', false, |
| 165 | + $useRequestValues ? $wgRequest->getVal( 'reason' ) : false ); |
| 166 | + $wgOut->addHTML( Xml::buildForm( $form, 'restrictuser-sumbit' ) ); |
| 167 | + $wgOut->addHTML( "</form></fieldset>" ); |
| 168 | + } |
| 169 | + |
| 170 | + public static function doNamespaceRestriction( $uid, $user ) { |
| 171 | + global $wgUser, $wgRequest; |
| 172 | + $r = new UserRestriction(); |
| 173 | + $r->setType( UserRestriction::NAMESPACE ); |
| 174 | + $r->setNamespace( $wgRequest->getVal( 'namespace' ) ); |
| 175 | + $r->setSubjectId( $uid ); |
| 176 | + $r->setSubjectText( $user ); |
| 177 | + $r->setBlockerId( $wgUser->getId() ); |
| 178 | + $r->setBlockerText( $wgUser->getName() ); |
| 179 | + $r->setReason( $wgRequest->getVal( 'reason' ) ); |
| 180 | + $r->setExpiry( UserRestriction::convertExpiry( $wgRequest->getVal( 'expiry' ) ) ); |
| 181 | + $r->setTimestamp( wfTimestampNow( TS_MW ) ); |
| 182 | + $r->commit(); |
| 183 | + $logExpiry = $wgRequest->getVal( 'expiry' ) ? $wgRequest->getVal( 'expiry' ) : Block::infinity(); |
| 184 | + $l = new LogPage( 'restrict' ); |
| 185 | + $l->addEntry( 'restrict', Title::makeTitle( NS_USER, $user ), $r->getReason(), |
| 186 | + array( $r->getType(), $r->getNamespace(), $logExpiry ) ); |
| 187 | + } |
| 188 | +} |
Property changes on: trunk/phase3/includes/specials/SpecialRestrictUser.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 189 | + native |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -197,6 +197,7 @@ |
198 | 198 | 'UserArray' => 'includes/UserArray.php', |
199 | 199 | 'UserArrayFromResult' => 'includes/UserArray.php', |
200 | 200 | 'UserMailer' => 'includes/UserMailer.php', |
| 201 | + 'UserRestriction' => 'includes/UserRestriction.php', |
201 | 202 | 'UserRightsProxy' => 'includes/UserRightsProxy.php', |
202 | 203 | 'WatchedItem' => 'includes/WatchedItem.php', |
203 | 204 | 'WatchlistEditor' => 'includes/WatchlistEditor.php', |
Index: trunk/phase3/includes/UserRestriction.php |
— | — | @@ -0,0 +1,158 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Object that represents a user restriction |
| 6 | + */ |
| 7 | +class UserRestriction { |
| 8 | + const PAGE = 'page'; |
| 9 | + const NAMESPACE = 'namespace'; |
| 10 | + |
| 11 | + private $mId, $mType, $mNamespace, $mPage, $mSubjectText, $mSubjectId, |
| 12 | + $mBlockerId, $mBlockerText, $mReason, $mTimestamp, $mExpiry; |
| 13 | + |
| 14 | + public static function newFromRow( $row ) { |
| 15 | + if( !$row ) |
| 16 | + return null; |
| 17 | + |
| 18 | + $obj = new UserRestriction(); |
| 19 | + $obj->mId = $row->ur_id; |
| 20 | + $obj->mType = $row->ur_type; |
| 21 | + if( $obj->mType == self::PAGE ) { |
| 22 | + $obj->mPage = Title::makeTitle( $row->ur_page_namespace, $row->ur_page_title ); |
| 23 | + } elseif( $obj->mType == self::NAMESPACE ) { |
| 24 | + $obj->mNamespace = $row->ur_namespace; |
| 25 | + } else { |
| 26 | + throw new MWException( "Unknown user restriction type: {$row->ur_type}" ); |
| 27 | + } |
| 28 | + |
| 29 | + $obj->mSubjectId = $row->ur_user; |
| 30 | + $obj->mSubjectText = $row->ur_user_text; |
| 31 | + $obj->mBlockerId = $row->ur_by; |
| 32 | + $obj->mBlockerText = $row->ur_by_text; |
| 33 | + $obj->mReason = $row->ur_reason; |
| 34 | + $obj->mTimestamp = wfTimestamp( TS_MW, $row->ur_timestamp ); |
| 35 | + $obj->mExpiry = $row->ur_expiry; |
| 36 | + return $obj; |
| 37 | + } |
| 38 | + |
| 39 | + public static function fetchForUser( $user, $forWrite = false ) { |
| 40 | + $dbr = wfGetDB( $forWrite ? DB_MASTER : DB_SLAVE ); |
| 41 | + if( is_int( $user ) ) |
| 42 | + $query = array( 'ur_user' => $user ); |
| 43 | + else |
| 44 | + $query = array( 'ur_user_text' => $user ); |
| 45 | + $res = $dbr->select( 'user_restrictions', '*', $query, __METHOD__ ); |
| 46 | + $result = array(); |
| 47 | + foreach( $res as $row ) { |
| 48 | + $result[] = self::newFromRow( $row ); |
| 49 | + } |
| 50 | + return $result; |
| 51 | + } |
| 52 | + |
| 53 | + public static function newFromId( $id, $forWrite = false ) { |
| 54 | + $dbr = wfGetDB( $forWrite ? DB_MASTER : DB_SLAVE ); |
| 55 | + if( !$id || !is_numeric( $id ) ) |
| 56 | + return null; |
| 57 | + $res = $dbr->selectRow( 'user_restrictions', '*', array( 'ur_id' => $id ), __METHOD__ ); |
| 58 | + return self::newFromRow( $res ); |
| 59 | + } |
| 60 | + |
| 61 | + public function getId() { return $this->mId; } |
| 62 | + public function setId( $v ) { $this->mId = $v; } |
| 63 | + public function getType() { return $this->mType; } |
| 64 | + public function setType( $v ) { $this->mType = $v; } |
| 65 | + public function getNamespace() { return $this->mNamespace; } |
| 66 | + public function setNamespace( $v ) { $this->mNamespace = $v; } |
| 67 | + public function getPage() { return $this->mPage; } |
| 68 | + public function setPage( $v ) { $this->mPage = $v; } |
| 69 | + public function getSubjectId() { return $this->mSubjectId; } |
| 70 | + public function setSubjectId( $v ) { $this->mSubjectId = $v; } |
| 71 | + public function getSubjectText() { return $this->mSubjectText; } |
| 72 | + public function setSubjectText( $v ) { $this->mSubjectText = $v; } |
| 73 | + public function getBlockerId() { return $this->mBlockerId; } |
| 74 | + public function setBlockerId( $v ) { $this->mBlockerId = $v; } |
| 75 | + public function getBlockerText() { return $this->mBlockerText; } |
| 76 | + public function setBlockerText( $v ) { $this->mBlockerText = $v; } |
| 77 | + public function getReason() { return $this->mReason; } |
| 78 | + public function setReason( $v ) { $this->mReason = $v; } |
| 79 | + public function getTimestamp() { return $this->mTimestamp; } |
| 80 | + public function setTimestamp( $v ) { $this->mTimestamp = $v; } |
| 81 | + public function getExpiry() { return $this->mExpiry; } |
| 82 | + public function setExpiry( $v ) { $this->mExpiry = $v; } |
| 83 | + |
| 84 | + public function isPage() { |
| 85 | + return $this->mType == self::PAGE; |
| 86 | + } |
| 87 | + public function isNamespace() { |
| 88 | + return $this->mType == self::NAMESPACE; |
| 89 | + } |
| 90 | + |
| 91 | + public function isExpired() { |
| 92 | + return is_numeric( $this->mExpiry ) && $this->mExpiry < wfTimestampNow( TS_MW ); |
| 93 | + } |
| 94 | + |
| 95 | + public function deleteIfExpired() { |
| 96 | + if( $this->isExpired() ) { |
| 97 | + $this->delete(); |
| 98 | + return true; |
| 99 | + } else { |
| 100 | + return false; |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + public function delete() { |
| 105 | + $dbw = wfGetDB( DB_MASTER ); |
| 106 | + $dbw->delete( 'user_restrictions', array( 'ur_id' => $this->mId ), __METHOD__ ); |
| 107 | + return $dbw->affectedRows(); |
| 108 | + } |
| 109 | + |
| 110 | + public static function purgeExpired() { |
| 111 | + $dbw = wfGetDB( DB_MASTER ); |
| 112 | + $dbw->delete( 'user_restrictions', array( 'ur_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ), __METHOD__ ); |
| 113 | + } |
| 114 | + |
| 115 | + public function commit() { |
| 116 | + $dbw = wfGetDB( DB_MASTER ); |
| 117 | + $this->setId( $dbw->nextSequenceValue('user_restrictions_ur_id_val') ); |
| 118 | + $row = array( |
| 119 | + 'ur_id' => $this->mId, |
| 120 | + 'ur_type' => $this->mType, |
| 121 | + 'ur_user' => $this->mSubjectId, |
| 122 | + 'ur_user_text' => $this->mSubjectText, |
| 123 | + 'ur_by' => $this->mBlockerId, |
| 124 | + 'ur_by_text' => $this->mBlockerText, |
| 125 | + 'ur_reason' => $this->mReason, |
| 126 | + 'ur_timestamp' => $dbw->timestamp( $this->mTimestamp ), |
| 127 | + 'ur_expiry' => $this->mExpiry, |
| 128 | + ); |
| 129 | + if( $this->isPage() ) { |
| 130 | + $row['ur_page_namespace'] = $this->mPage->getNamespace(); |
| 131 | + $row['ur_page_title'] = $this->mPage->getDbKey(); |
| 132 | + } |
| 133 | + if( $this->isNamespace() ) { |
| 134 | + $row['ur_namespace'] = $this->mNamespace; |
| 135 | + } |
| 136 | + $dbw->insert( 'user_restrictions', $row, __METHOD__ ); |
| 137 | + } |
| 138 | + |
| 139 | + public static function formatType( $type ) { |
| 140 | + return wfMsg( 'userrestrictiontype-' . $type ); |
| 141 | + } |
| 142 | + |
| 143 | + /** |
| 144 | + * Converts expiry which user input to the internal representation. |
| 145 | + * Returns false if invalid expiry is set, Block::infinity() on empty value, |
| 146 | + * Block::infinity() on infinity or 14-symbol timestamp |
| 147 | + */ |
| 148 | + public static function convertExpiry( $expiry ) { |
| 149 | + if( !$expiry ) |
| 150 | + return Block::infinity(); |
| 151 | + if( in_array( $expiry, array( 'infinite', 'infinity', 'indefinite' ) ) ) |
| 152 | + return Block::infinity(); |
| 153 | + $unix = @strtotime( $expiry ); |
| 154 | + if( !$unix || $unix === -1 ) |
| 155 | + return false; |
| 156 | + else |
| 157 | + return wfTimestamp( TS_MW, $unix ); |
| 158 | + } |
| 159 | +} |
Property changes on: trunk/phase3/includes/UserRestriction.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 160 | + native |
Index: trunk/phase3/includes/SpecialPage.php |
— | — | @@ -126,6 +126,9 @@ |
127 | 127 | 'Allpages' => 'SpecialAllpages', |
128 | 128 | 'Prefixindex' => 'SpecialPrefixindex', |
129 | 129 | 'Ipblocklist' => array( 'SpecialPage', 'Ipblocklist' ), |
| 130 | + 'ListUserRestrictions' => array( 'SpecialPage', 'ListUserRestrictions' ), |
| 131 | + 'RemoveRestrictions' => array( 'UnlistedSpecialPage', 'RemoveRestrictions', 'restrict' ), |
| 132 | + 'RestrictUser' => array( 'SpecialPage', 'RestrictUser', 'restrict' ), |
130 | 133 | 'Specialpages' => array( 'UnlistedSpecialPage', 'Specialpages' ), |
131 | 134 | 'Contributions' => array( 'SpecialPage', 'Contributions' ), |
132 | 135 | 'Emailuser' => array( 'UnlistedSpecialPage', 'Emailuser' ), |
Index: trunk/phase3/includes/User.php |
— | — | @@ -118,6 +118,8 @@ |
119 | 119 | 'mEditCount', |
120 | 120 | // user_group table |
121 | 121 | 'mGroups', |
| 122 | + // user_restrictions table |
| 123 | + 'mRestrictions', |
122 | 124 | ); |
123 | 125 | |
124 | 126 | /** |
— | — | @@ -156,6 +158,7 @@ |
157 | 159 | 'proxyunbannable', |
158 | 160 | 'purge', |
159 | 161 | 'read', |
| 162 | + 'restrict', |
160 | 163 | 'reupload', |
161 | 164 | 'reupload-shared', |
162 | 165 | 'rollback', |
— | — | @@ -177,7 +180,8 @@ |
178 | 181 | //@{ |
179 | 182 | var $mId, $mName, $mRealName, $mPassword, $mNewpassword, $mNewpassTime, |
180 | 183 | $mEmail, $mOptions, $mTouched, $mToken, $mEmailAuthenticated, |
181 | | - $mEmailToken, $mEmailTokenExpires, $mRegistration, $mGroups; |
| 184 | + $mEmailToken, $mEmailTokenExpires, $mRegistration, $mGroups, |
| 185 | + $mRestrictions; |
182 | 186 | //@} |
183 | 187 | |
184 | 188 | /** |
— | — | @@ -297,6 +301,7 @@ |
298 | 302 | function saveToCache() { |
299 | 303 | $this->load(); |
300 | 304 | $this->loadGroups(); |
| 305 | + $this->loadRestrictions(); |
301 | 306 | if ( $this->isAnon() ) { |
302 | 307 | // Anonymous users are uncached |
303 | 308 | return; |
— | — | @@ -878,6 +883,7 @@ |
879 | 884 | # Initialise user table data |
880 | 885 | $this->loadFromRow( $s ); |
881 | 886 | $this->mGroups = null; // deferred |
| 887 | + $this->mRestrictions = null; |
882 | 888 | $this->getEditCount(); // revalidation for nulls |
883 | 889 | return true; |
884 | 890 | } else { |
— | — | @@ -3236,4 +3242,50 @@ |
3237 | 3243 | return true; |
3238 | 3244 | } |
3239 | 3245 | |
| 3246 | + // Restrictions-related block |
| 3247 | + |
| 3248 | + public function loadRestrictions() { |
| 3249 | + if( !$this->mRestrictions ) |
| 3250 | + $this->mRestrictions = UserRestriction::fetchForUser( $this->isLoggedIn() ? |
| 3251 | + intval( $this->getId() ) : $this->getName() ); |
| 3252 | + } |
| 3253 | + |
| 3254 | + public function getRestrictions() { |
| 3255 | + $this->loadRestrictions(); |
| 3256 | + |
| 3257 | + // Check for expired restrictions. Recache if found expired ones |
| 3258 | + static $checked = false; |
| 3259 | + if( !$checked ) { |
| 3260 | + $expired = false; |
| 3261 | + $old = $this->mRestrictions; |
| 3262 | + $this->mRestrictions = array(); |
| 3263 | + foreach( $old as $restriction ) { |
| 3264 | + if( $restriction->deleteIfExpired() ) |
| 3265 | + $expired = true; |
| 3266 | + else |
| 3267 | + $this->mRestrictions[] = $restriction; |
| 3268 | + } |
| 3269 | + if( $expired ) |
| 3270 | + $this->saveToCache(); |
| 3271 | + $checked = true; |
| 3272 | + } |
| 3273 | + |
| 3274 | + return $this->mRestrictions; |
| 3275 | + } |
| 3276 | + |
| 3277 | + public function getRestrictionForPage( Title $page ) { |
| 3278 | + foreach( $this->getRestrictions() as $r ) { |
| 3279 | + if( $r->isPage() && $page->equals( $r->getPage() ) ) |
| 3280 | + return $r; |
| 3281 | + } |
| 3282 | + return null; |
| 3283 | + } |
| 3284 | + |
| 3285 | + public function getRestrictionForNamespace( $nsid ) { |
| 3286 | + foreach( $this->getRestrictions() as $r ) { |
| 3287 | + if( $r->isNamespace() && $r->getNamespace() == $nsid ) |
| 3288 | + return $r; |
| 3289 | + } |
| 3290 | + return null; |
| 3291 | + } |
3240 | 3292 | } |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -1176,6 +1176,7 @@ |
1177 | 1177 | $wgGroupPermissions['sysop']['apihighlimits'] = true; |
1178 | 1178 | $wgGroupPermissions['sysop']['browsearchive'] = true; |
1179 | 1179 | $wgGroupPermissions['sysop']['noratelimit'] = true; |
| 1180 | +$wgGroupPermissions['sysop']['restrict'] = true; |
1180 | 1181 | #$wgGroupPermissions['sysop']['mergehistory'] = true; |
1181 | 1182 | |
1182 | 1183 | // Permission to change users' group assignments |
— | — | @@ -2661,6 +2662,7 @@ |
2662 | 2663 | 'patrol', |
2663 | 2664 | 'merge', |
2664 | 2665 | 'suppress', |
| 2666 | + 'restrict', |
2665 | 2667 | ); |
2666 | 2668 | |
2667 | 2669 | /** |
— | — | @@ -2691,6 +2693,7 @@ |
2692 | 2694 | 'patrol' => 'patrol-log-page', |
2693 | 2695 | 'merge' => 'mergelog', |
2694 | 2696 | 'suppress' => 'suppressionlog', |
| 2697 | + 'restrict' => 'restrictionlog', |
2695 | 2698 | ); |
2696 | 2699 | |
2697 | 2700 | /** |
— | — | @@ -2711,6 +2714,7 @@ |
2712 | 2715 | 'patrol' => 'patrol-log-header', |
2713 | 2716 | 'merge' => 'mergelogpagetext', |
2714 | 2717 | 'suppress' => 'suppressionlogtext', |
| 2718 | + 'restrict' => 'restrictionlogtext', |
2715 | 2719 | ); |
2716 | 2720 | |
2717 | 2721 | /** |
— | — | @@ -2743,6 +2747,8 @@ |
2744 | 2748 | 'suppress/event' => 'logdelete-logentry', |
2745 | 2749 | 'suppress/delete' => 'suppressedarticle', |
2746 | 2750 | 'suppress/block' => 'blocklogentry', |
| 2751 | + 'restrict/restrict' => 'restrictentry', |
| 2752 | + 'restrict/remove' => 'restrictremoveentry', |
2747 | 2753 | ); |
2748 | 2754 | |
2749 | 2755 | /** |
— | — | @@ -2813,6 +2819,8 @@ |
2814 | 2820 | 'Preferences' => 'users', |
2815 | 2821 | 'Resetpass' => 'users', |
2816 | 2822 | 'DeletedContributions' => 'users', |
| 2823 | + 'ListUserRestrictions' => 'users', |
| 2824 | + 'RestrictUser' => 'users', |
2817 | 2825 | |
2818 | 2826 | 'Mostlinked' => 'highuse', |
2819 | 2827 | 'Mostlinkedcategories' => 'highuse', |
Index: trunk/phase3/includes/LogPage.php |
— | — | @@ -193,6 +193,19 @@ |
194 | 194 | } else { |
195 | 195 | $rv = wfMsgForContent( $wgLogActions[$key], $titleLink ); |
196 | 196 | } |
| 197 | + } elseif( $type == 'restrict' ) { |
| 198 | + if( $params[0] == UserRestriction::PAGE ) |
| 199 | + $subj = wfMsgExt( 'restrictlogpage', 'parseinline', $params[1] ); |
| 200 | + if( $params[0] == UserRestriction::NAMESPACE ) |
| 201 | + $subj = wfMsgExt( 'restrictlognamespace', 'parseinline', $wgLang->getDisplayNsText( $params[1] ) ); |
| 202 | + $expiry = ''; |
| 203 | + if( $key == 'restrict/restrict' ) |
| 204 | + $expiry = $wgLang->translateBlockExpiry( $params[2] ); |
| 205 | + if ( $skin ) { |
| 206 | + $rv = wfMsg( $wgLogActions[$key], $titleLink, $subj, $expiry ); |
| 207 | + } else { |
| 208 | + $rv = wfMsgForContent( $wgLogActions[$key], $titleLink, $subj, $expiry ); |
| 209 | + } |
197 | 210 | } else { |
198 | 211 | $details = ''; |
199 | 212 | array_unshift( $params, $titleLink ); |
— | — | @@ -260,6 +273,7 @@ |
261 | 274 | } |
262 | 275 | break; |
263 | 276 | case 'rights': |
| 277 | + case 'restrict': |
264 | 278 | $text = $wgContLang->ucfirst( $title->getText() ); |
265 | 279 | $titleLink = $skin->makeLinkObj( Title::makeTitle( NS_USER, $text ) ); |
266 | 280 | break; |
Index: trunk/phase3/includes/Title.php |
— | — | @@ -1107,9 +1107,7 @@ |
1108 | 1108 | } |
1109 | 1109 | $errors = $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries ); |
1110 | 1110 | |
1111 | | - global $wgContLang; |
1112 | | - global $wgLang; |
1113 | | - global $wgEmailConfirmToEdit; |
| 1111 | + global $wgContLang, $wgLang, $wgEmailConfirmToEdit; |
1114 | 1112 | |
1115 | 1113 | if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount' ) { |
1116 | 1114 | $errors[] = array( 'confirmedittext' ); |
— | — | @@ -1141,20 +1139,7 @@ |
1142 | 1140 | $blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $user->mBlock->mTimestamp ), true ); |
1143 | 1141 | |
1144 | 1142 | if ( $blockExpiry == 'infinity' ) { |
1145 | | - // Entry in database (table ipblocks) is 'infinity' but 'ipboptions' uses 'infinite' or 'indefinite' |
1146 | | - $scBlockExpiryOptions = wfMsg( 'ipboptions' ); |
1147 | | - |
1148 | | - foreach ( explode( ',', $scBlockExpiryOptions ) as $option ) { |
1149 | | - if ( strpos( $option, ':' ) == false ) |
1150 | | - continue; |
1151 | | - |
1152 | | - list ($show, $value) = explode( ":", $option ); |
1153 | | - |
1154 | | - if ( $value == 'infinite' || $value == 'indefinite' ) { |
1155 | | - $blockExpiry = $show; |
1156 | | - break; |
1157 | | - } |
1158 | | - } |
| 1143 | + $blockExpiry = wfMsg( 'ipbinfinite' ); |
1159 | 1144 | } else { |
1160 | 1145 | $blockExpiry = $wgLang->timeanddate( wfTimestamp( TS_MW, $blockExpiry ), true ); |
1161 | 1146 | } |
— | — | @@ -1164,9 +1149,9 @@ |
1165 | 1150 | $errors[] = array( ($block->mAuto ? 'autoblockedtext' : 'blockedtext'), $link, $reason, $ip, $name, |
1166 | 1151 | $blockid, $blockExpiry, $intended, $blockTimestamp ); |
1167 | 1152 | } |
1168 | | - |
| 1153 | + |
1169 | 1154 | // Remove the errors being ignored. |
1170 | | - |
| 1155 | + |
1171 | 1156 | foreach( $errors as $index => $error ) { |
1172 | 1157 | $error_key = is_array($error) ? $error[0] : $error; |
1173 | 1158 | |
— | — | @@ -1189,6 +1174,8 @@ |
1190 | 1175 | * @return \type{\array} Array of arrays of the arguments to wfMsg to explain permissions problems. |
1191 | 1176 | */ |
1192 | 1177 | private function getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries = true ) { |
| 1178 | + global $wgLang; |
| 1179 | + |
1193 | 1180 | wfProfileIn( __METHOD__ ); |
1194 | 1181 | |
1195 | 1182 | $errors = array(); |
— | — | @@ -1334,6 +1321,26 @@ |
1335 | 1322 | $errors[] = $return; |
1336 | 1323 | } |
1337 | 1324 | |
| 1325 | + // Check per-user restrictions |
| 1326 | + if( $action != 'read' ) { |
| 1327 | + $r = $user->getRestrictionForPage( $this ); |
| 1328 | + if( !$r ) |
| 1329 | + $r = $user->getRestrictionForNamespace( $this->getNamespace() ); |
| 1330 | + if( $r ) { |
| 1331 | + $start = $wgLang->timeanddate( $r->getTimestamp() ); |
| 1332 | + $end = $r->getExpiry() == 'infinity' ? |
| 1333 | + wfMsg( 'ipbinfinite' ) : |
| 1334 | + $wgLang->timeanddate( $r->getExpiry() ); |
| 1335 | + if( $r->isPage() ) |
| 1336 | + $errors[] = array( 'userrestricted-page', $this->getFullText(), |
| 1337 | + $r->getBlockerText(), $r->getReason(), $start, $end ); |
| 1338 | + elseif( $r->isNamespace() ) { |
| 1339 | + $errors[] = array( 'userrestricted-namespace', $wgLang->getDisplayNsText( $this->getNamespace() ), |
| 1340 | + $r->getBlockerText(), $r->getReason(), $start, $end ); |
| 1341 | + } |
| 1342 | + } |
| 1343 | + } |
| 1344 | + |
1338 | 1345 | wfProfileOut( __METHOD__ ); |
1339 | 1346 | return $errors; |
1340 | 1347 | } |