r41352 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r41351‎ | r41352 | r41353 >
Date:16:08, 28 September 2008
Author:vasilievvv
Status:old (Comments)
Tags:
Comment:
* (bug 674) Allow users to be blocked from editing a specific article
** Also supports blocking user from editing whole namespace
* Replace ugly ipboptions parsing code in Title.php with a simple message

Requires schema change (I showed it to Tim Starling).
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/LogPage.php (modified) (history)
  • /trunk/phase3/includes/SpecialPage.php (modified) (history)
  • /trunk/phase3/includes/Title.php (modified) (history)
  • /trunk/phase3/includes/User.php (modified) (history)
  • /trunk/phase3/includes/UserRestriction.php (added) (history)
  • /trunk/phase3/includes/specials/SpecialListUserRestrictions.php (added) (history)
  • /trunk/phase3/includes/specials/SpecialRemoveRestrictions.php (added) (history)
  • /trunk/phase3/includes/specials/SpecialRestrictUser.php (added) (history)
  • /trunk/phase3/languages/Language.php (modified) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/maintenance/archives/patch-user_restrictions.sql (added) (history)
  • /trunk/phase3/maintenance/tables.sql (modified) (history)
  • /trunk/phase3/maintenance/updaters.inc (modified) (history)

Diff [purge]

Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -439,6 +439,9 @@
440440 'Blankpage' => array( 'BlankPage' ),
441441 'LinkSearch' => array( 'LinkSearch' ),
442442 'DeletedContributions' => array( 'DeletedContributions' ),
 443+ 'ListUserRestrictions' => array( 'ListUserRestrictions' ),
 444+ 'RemoveRestrictions' => array( 'RemoveRestrictions' ),
 445+ 'RestrictUser' => array( 'RestrictUser' ),
443446 );
444447
445448 /**
@@ -1197,7 +1200,23 @@
11981201 'edit-no-change' => 'Your edit was ignored, because no change was made to the text.',
11991202 'edit-already-exists' => 'Could not create a new page.
12001203 It already exists.',
 1204+'userrestricted-page' => "<big>'''Your user name or IP address has been restricted from editing page \"$1\".'''</big>
12011205
 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+
12021221 # Parser/template warnings
12031222 'expensive-parserfunction-warning' => 'Warning: This page contains too many expensive parser function calls.
12041223
@@ -1637,6 +1656,7 @@
16381657 'right-userrights' => 'Edit all user rights',
16391658 'right-userrights-interwiki' => 'Edit user rights of users on other wikis',
16401659 'right-siteadmin' => 'Lock and unlock the database',
 1660+'right-restrict' => 'Restrict user from editing certain namespaces and pages',
16411661
16421662 # User rights log
16431663 'rightslog' => 'User rights log',
@@ -2497,6 +2517,7 @@
24982518 'ipbsubmit' => 'Block this user',
24992519 'ipbother' => 'Other time:',
25002520 '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',
25012522 'ipbotheroption' => 'other',
25022523 'ipbotherreason' => 'Other/additional reason:',
25032524 'ipbhidename' => 'Hide username from the block log, active block list and user list',
@@ -2569,6 +2590,69 @@
25702591 You cannot create an account',
25712592 'cant-block-while-blocked' => 'You cannot block other users while you are blocked.',
25722593
 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+
25732657 # Developer tools
25742658 'lockdb' => 'Lock database',
25752659 'unlockdb' => 'Unlock database',
Index: trunk/phase3/languages/Language.php
@@ -265,6 +265,20 @@
266266 }
267267
268268 /**
 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+ /**
269283 * Get a namespace key by value, case insensitive.
270284 * Only matches namespace names for the current language, not the
271285 * canonical ones defined in Namespace.php.
Index: trunk/phase3/RELEASE-NOTES
@@ -144,8 +144,9 @@
145145 query string use the article path, rather than the script path
146146 * Added the ability to set the target attribute on external links with
147147 $wgExternalLinkTarget
 148+* (bug 674) Allow admins to block users from editing specific articles and
 149+ namespaces
148150
149 -
150151 === Bug fixes in 1.14 ===
151152
152153 * (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
142 + native
Index: trunk/phase3/maintenance/tables.sql
@@ -1243,4 +1243,44 @@
12441244 PRIMARY KEY (ul_key)
12451245 ) /*$wgDBTableOptions*/;
12461246
 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+
12471287 -- vim: sw=2 sts=2 et
Index: trunk/phase3/maintenance/updaters.inc
@@ -145,9 +145,10 @@
146146 array( 'update_password_format' ),
147147
148148 // 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' ),
150150 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' ),
152153 );
153154
154155
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
164 + 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' ) . '&nbsp;' .
 34+ self::typeSelector( 'type', $wgRequest->getVal( 'type' ), 'type' );
 35+ $s .= '&nbsp;';
 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' ) . '&nbsp;' .
 40+ Xml::namespaceSelector( $wgRequest->getVal( 'namespace' ), '', false, 'namespace' );
 41+ $s .= '&nbsp;';
 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
1164 + 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
1189 + native
Index: trunk/phase3/includes/AutoLoader.php
@@ -197,6 +197,7 @@
198198 'UserArray' => 'includes/UserArray.php',
199199 'UserArrayFromResult' => 'includes/UserArray.php',
200200 'UserMailer' => 'includes/UserMailer.php',
 201+ 'UserRestriction' => 'includes/UserRestriction.php',
201202 'UserRightsProxy' => 'includes/UserRightsProxy.php',
202203 'WatchedItem' => 'includes/WatchedItem.php',
203204 '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
1160 + native
Index: trunk/phase3/includes/SpecialPage.php
@@ -126,6 +126,9 @@
127127 'Allpages' => 'SpecialAllpages',
128128 'Prefixindex' => 'SpecialPrefixindex',
129129 'Ipblocklist' => array( 'SpecialPage', 'Ipblocklist' ),
 130+ 'ListUserRestrictions' => array( 'SpecialPage', 'ListUserRestrictions' ),
 131+ 'RemoveRestrictions' => array( 'UnlistedSpecialPage', 'RemoveRestrictions', 'restrict' ),
 132+ 'RestrictUser' => array( 'SpecialPage', 'RestrictUser', 'restrict' ),
130133 'Specialpages' => array( 'UnlistedSpecialPage', 'Specialpages' ),
131134 'Contributions' => array( 'SpecialPage', 'Contributions' ),
132135 'Emailuser' => array( 'UnlistedSpecialPage', 'Emailuser' ),
Index: trunk/phase3/includes/User.php
@@ -118,6 +118,8 @@
119119 'mEditCount',
120120 // user_group table
121121 'mGroups',
 122+ // user_restrictions table
 123+ 'mRestrictions',
122124 );
123125
124126 /**
@@ -156,6 +158,7 @@
157159 'proxyunbannable',
158160 'purge',
159161 'read',
 162+ 'restrict',
160163 'reupload',
161164 'reupload-shared',
162165 'rollback',
@@ -177,7 +180,8 @@
178181 //@{
179182 var $mId, $mName, $mRealName, $mPassword, $mNewpassword, $mNewpassTime,
180183 $mEmail, $mOptions, $mTouched, $mToken, $mEmailAuthenticated,
181 - $mEmailToken, $mEmailTokenExpires, $mRegistration, $mGroups;
 184+ $mEmailToken, $mEmailTokenExpires, $mRegistration, $mGroups,
 185+ $mRestrictions;
182186 //@}
183187
184188 /**
@@ -297,6 +301,7 @@
298302 function saveToCache() {
299303 $this->load();
300304 $this->loadGroups();
 305+ $this->loadRestrictions();
301306 if ( $this->isAnon() ) {
302307 // Anonymous users are uncached
303308 return;
@@ -878,6 +883,7 @@
879884 # Initialise user table data
880885 $this->loadFromRow( $s );
881886 $this->mGroups = null; // deferred
 887+ $this->mRestrictions = null;
882888 $this->getEditCount(); // revalidation for nulls
883889 return true;
884890 } else {
@@ -3236,4 +3242,50 @@
32373243 return true;
32383244 }
32393245
 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+ }
32403292 }
Index: trunk/phase3/includes/DefaultSettings.php
@@ -1176,6 +1176,7 @@
11771177 $wgGroupPermissions['sysop']['apihighlimits'] = true;
11781178 $wgGroupPermissions['sysop']['browsearchive'] = true;
11791179 $wgGroupPermissions['sysop']['noratelimit'] = true;
 1180+$wgGroupPermissions['sysop']['restrict'] = true;
11801181 #$wgGroupPermissions['sysop']['mergehistory'] = true;
11811182
11821183 // Permission to change users' group assignments
@@ -2661,6 +2662,7 @@
26622663 'patrol',
26632664 'merge',
26642665 'suppress',
 2666+ 'restrict',
26652667 );
26662668
26672669 /**
@@ -2691,6 +2693,7 @@
26922694 'patrol' => 'patrol-log-page',
26932695 'merge' => 'mergelog',
26942696 'suppress' => 'suppressionlog',
 2697+ 'restrict' => 'restrictionlog',
26952698 );
26962699
26972700 /**
@@ -2711,6 +2714,7 @@
27122715 'patrol' => 'patrol-log-header',
27132716 'merge' => 'mergelogpagetext',
27142717 'suppress' => 'suppressionlogtext',
 2718+ 'restrict' => 'restrictionlogtext',
27152719 );
27162720
27172721 /**
@@ -2743,6 +2747,8 @@
27442748 'suppress/event' => 'logdelete-logentry',
27452749 'suppress/delete' => 'suppressedarticle',
27462750 'suppress/block' => 'blocklogentry',
 2751+ 'restrict/restrict' => 'restrictentry',
 2752+ 'restrict/remove' => 'restrictremoveentry',
27472753 );
27482754
27492755 /**
@@ -2813,6 +2819,8 @@
28142820 'Preferences' => 'users',
28152821 'Resetpass' => 'users',
28162822 'DeletedContributions' => 'users',
 2823+ 'ListUserRestrictions' => 'users',
 2824+ 'RestrictUser' => 'users',
28172825
28182826 'Mostlinked' => 'highuse',
28192827 'Mostlinkedcategories' => 'highuse',
Index: trunk/phase3/includes/LogPage.php
@@ -193,6 +193,19 @@
194194 } else {
195195 $rv = wfMsgForContent( $wgLogActions[$key], $titleLink );
196196 }
 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+ }
197210 } else {
198211 $details = '';
199212 array_unshift( $params, $titleLink );
@@ -260,6 +273,7 @@
261274 }
262275 break;
263276 case 'rights':
 277+ case 'restrict':
264278 $text = $wgContLang->ucfirst( $title->getText() );
265279 $titleLink = $skin->makeLinkObj( Title::makeTitle( NS_USER, $text ) );
266280 break;
Index: trunk/phase3/includes/Title.php
@@ -1107,9 +1107,7 @@
11081108 }
11091109 $errors = $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries );
11101110
1111 - global $wgContLang;
1112 - global $wgLang;
1113 - global $wgEmailConfirmToEdit;
 1111+ global $wgContLang, $wgLang, $wgEmailConfirmToEdit;
11141112
11151113 if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount' ) {
11161114 $errors[] = array( 'confirmedittext' );
@@ -1141,20 +1139,7 @@
11421140 $blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $user->mBlock->mTimestamp ), true );
11431141
11441142 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' );
11591144 } else {
11601145 $blockExpiry = $wgLang->timeanddate( wfTimestamp( TS_MW, $blockExpiry ), true );
11611146 }
@@ -1164,9 +1149,9 @@
11651150 $errors[] = array( ($block->mAuto ? 'autoblockedtext' : 'blockedtext'), $link, $reason, $ip, $name,
11661151 $blockid, $blockExpiry, $intended, $blockTimestamp );
11671152 }
1168 -
 1153+
11691154 // Remove the errors being ignored.
1170 -
 1155+
11711156 foreach( $errors as $index => $error ) {
11721157 $error_key = is_array($error) ? $error[0] : $error;
11731158
@@ -1189,6 +1174,8 @@
11901175 * @return \type{\array} Array of arrays of the arguments to wfMsg to explain permissions problems.
11911176 */
11921177 private function getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries = true ) {
 1178+ global $wgLang;
 1179+
11931180 wfProfileIn( __METHOD__ );
11941181
11951182 $errors = array();
@@ -1334,6 +1321,26 @@
13351322 $errors[] = $return;
13361323 }
13371324
 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+
13381345 wfProfileOut( __METHOD__ );
13391346 return $errors;
13401347 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r41405Revert r41352-41355, r41362-41363: unauthorized schema change breaks parser t...brion00:07, 30 September 2008
r45231* (bug 674) Allow users to be blocked from editing a specific article...vasilievvv17:25, 31 December 2008
r45241Revert r45231, r45235 "* (bug 674) Allow users to be blocked from editing a s...brion18:56, 31 December 2008

Comments

#Comment by Brion VIBBER (talk | contribs)   20:39, 30 September 2008

Backed out in r41405: unauthorized schema changes break parser tests, etc

Status & tagging log