r12207 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r12206‎ | r12207 | r12208 >
Date:05:41, 22 December 2005
Author:vibber
Status:old
Tags:
Comment:
* (bug 1735) Revamped protection interface
* (bug 675) Add page protection level for unregistered/new accounts
* User::isNewbie now uses the registration date and $wgAutoconfirmAge
* Log views show message when no matches
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/Article.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/ProtectionForm.php (added) (history)
  • /trunk/phase3/includes/SpecialLog.php (modified) (history)
  • /trunk/phase3/includes/User.php (modified) (history)
  • /trunk/phase3/languages/Language.php (modified) (history)
  • /trunk/phase3/maintenance/archives/patch-user_registration.sql (added) (history)
  • /trunk/phase3/maintenance/mysql5/tables.sql (modified) (history)
  • /trunk/phase3/maintenance/tables.sql (modified) (history)
  • /trunk/phase3/maintenance/updaters.inc (modified) (history)
  • /trunk/phase3/skins/common/protect.js (added) (history)

Diff [purge]

Index: trunk/phase3/maintenance/archives/patch-user_registration.sql
@@ -0,0 +1,9 @@
 2+--
 3+-- New user field for tracking registration time
 4+-- 2005-12-21
 5+--
 6+
 7+ALTER TABLE /*$wgDBprefix*/user
 8+ -- Timestamp of account registration.
 9+ -- Accounts predating this schema addition may contain NULL.
 10+ ADD user_registration CHAR(14) BINARY;
Property changes on: trunk/phase3/maintenance/archives/patch-user_registration.sql
___________________________________________________________________
Added: svn:eol-style
111 + native
Added: svn:keywords
212 + Author Date Id Revision
Index: trunk/phase3/maintenance/mysql5/tables.sql
@@ -119,6 +119,10 @@
120120 -- Expiration date for the user_email_token
121121 user_email_token_expires CHAR(14) BINARY,
122122
 123+ -- Timestamp of account registration.
 124+ -- Accounts predating this schema addition may contain NULL.
 125+ user_registration CHAR(14) BINARY,
 126+
123127 PRIMARY KEY user_id (user_id),
124128 UNIQUE INDEX user_name (user_name),
125129 INDEX (user_email_token)
Index: trunk/phase3/maintenance/updaters.inc
@@ -39,6 +39,7 @@
4040 array( 'user', 'user_real_name', 'patch-user-realname.sql' ),
4141 array( 'user', 'user_token', 'patch-user_token.sql' ),
4242 array( 'user', 'user_email_token', 'patch-user_email_token.sql' ),
 43+ array( 'user', 'user_registration','patch-user_registration.sql' ),
4344 array( 'logging', 'log_params', 'patch-log_params.sql' ),
4445 array( 'archive', 'ar_rev_id', 'patch-archive-rev_id.sql' ),
4546 array( 'archive', 'ar_text_id', 'patch-archive-text_id.sql' ),
Index: trunk/phase3/maintenance/tables.sql
@@ -105,6 +105,10 @@
106106
107107 -- Expiration date for the user_email_token
108108 user_email_token_expires CHAR(14) BINARY,
 109+
 110+ -- Timestamp of account registration.
 111+ -- Accounts predating this schema addition may contain NULL.
 112+ user_registration CHAR(14) BINARY,
109113
110114 PRIMARY KEY user_id (user_id),
111115 UNIQUE INDEX user_name (user_name),
Index: trunk/phase3/skins/common/protect.js
@@ -0,0 +1,126 @@
 2+function protectInitialize(tableId, labelText) {
 3+ if (document.createTextNode) {
 4+ var box = document.getElementById(tableId);
 5+ if (!box)
 6+ return false;
 7+
 8+ var tbody = box.getElementsByTagName('tbody')[0];
 9+ var row = document.createElement('tr');
 10+ tbody.appendChild(row);
 11+
 12+ row.appendChild(document.createElement('td'));
 13+ var col2 = document.createElement('td');
 14+ row.appendChild(col2);
 15+
 16+ var check = document.createElement('input');
 17+ check.id = "mwProtectUnchained";
 18+ check.type = "checkbox";
 19+ check.onclick = protectChainUpdate;
 20+ col2.appendChild(check);
 21+
 22+ var label = document.createElement('label');
 23+ label.setAttribute("for", "mwProtectUnchained");
 24+ label.appendChild(document.createTextNode(labelText));
 25+ col2.appendChild(label);
 26+
 27+ if (protectAllMatch()) {
 28+ check.checked = false;
 29+ protectEnable(false);
 30+ } else {
 31+ check.checked = true;
 32+ protectEnable(true);
 33+ }
 34+
 35+ return true;
 36+ }
 37+ return false;
 38+}
 39+
 40+function protectLevelsUpdate(source) {
 41+ if (!protectUnchained()) {
 42+ protectUpdateAll(source.selectedIndex);
 43+ }
 44+}
 45+
 46+function protectChainUpdate() {
 47+ if (protectUnchained()) {
 48+ protectEnable(true);
 49+ } else {
 50+ protectChain();
 51+ protectEnable(false);
 52+ }
 53+}
 54+
 55+
 56+function protectAllMatch() {
 57+ var values = new Array();
 58+ protectForSelectors(function(set) {
 59+ values[values.length] = set.selectedIndex;
 60+ });
 61+ for (var i = 1; i < values.length; i++) {
 62+ if (values[i] != values[0]) {
 63+ return false;
 64+ }
 65+ }
 66+ return true;
 67+}
 68+
 69+function protectUnchained() {
 70+ var unchain = document.getElementById("mwProtectUnchained");
 71+ if (!unchain) {
 72+ alert("This shouldn't happen");
 73+ return false;
 74+ }
 75+ return unchain.checked;
 76+}
 77+
 78+function protectChain() {
 79+ / Find the highest-protected action and bump them all to this level
 80+ var maxIndex = -1;
 81+ protectForSelectors(function(set) {
 82+ if (set.selectedIndex > maxIndex) {
 83+ maxIndex = set.selectedIndex;
 84+ }
 85+ });
 86+ protectUpdateAll(maxIndex);
 87+}
 88+
 89+function protectUpdateAll(index) {
 90+ protectForSelectors(function(set) {
 91+ if (set.selectedIndex != index) {
 92+ set.selectedIndex = index;
 93+ }
 94+ });
 95+}
 96+
 97+function protectForSelectors(func) {
 98+ var selectors = protectSelectors();
 99+ for (var i = 0; i < selectors.length; i++) {
 100+ func(selectors[i]);
 101+ }
 102+}
 103+
 104+function protectSelectors() {
 105+ var all = document.getElementsByTagName("select");
 106+ var ours = new Array();
 107+ for (var i = 0; i < all.length; i++) {
 108+ var set = all[i];
 109+ if (set.id.match(/^mwProtect-level-/)) {
 110+ ours[ours.length] = set;
 111+ }
 112+ }
 113+ return ours;
 114+}
 115+
 116+function protectEnable(val) {
 117+ / fixme
 118+ var first = true;
 119+ protectForSelectors(function(set) {
 120+ if (first) {
 121+ first = false;
 122+ } else {
 123+ set.disabled = !val;
 124+ set.style.visible = val ? "visible" : "hidden";
 125+ }
 126+ });
 127+}
Property changes on: trunk/phase3/skins/common/protect.js
___________________________________________________________________
Added: svn:eol-style
1128 + native
Added: svn:keywords
2129 + Author Date Id Revision
Index: trunk/phase3/includes/ProtectionForm.php
@@ -0,0 +1,244 @@
 2+<?php
 3+/**
 4+ * Copyright (C) 2005 Brion Vibber <[email protected]>
 5+ * http://www.mediawiki.org/
 6+ *
 7+ * This program is free software; you can redistribute it and/or modify
 8+ * it under the terms of the GNU General Public License as published by
 9+ * the Free Software Foundation; either version 2 of the License, or
 10+ * (at your option) any later version.
 11+ *
 12+ * This program is distributed in the hope that it will be useful,
 13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15+ * GNU General Public License for more details.
 16+ *
 17+ * You should have received a copy of the GNU General Public License along
 18+ * with this program; if not, write to the Free Software Foundation, Inc.,
 19+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 20+ * http://www.gnu.org/copyleft/gpl.html
 21+ *
 22+ * @package MediaWiki
 23+ * @subpackage SpecialPage
 24+ */
 25+
 26+class ProtectionForm {
 27+ var $mRestrictions = array();
 28+ var $mReason = '';
 29+
 30+ function ProtectionForm( &$article ) {
 31+ global $wgRequest, $wgUser;
 32+ global $wgRestrictionTypes, $wgRestrictionLevels;
 33+ $this->mArticle =& $article;
 34+ $this->mTitle =& $article->mTitle;
 35+
 36+ if( $this->mTitle ) {
 37+ foreach( $wgRestrictionTypes as $action ) {
 38+ / Fixme: this form currently requires individual selections,
 39+ / but the db allows multiples separated by commas.
 40+ $this->mRestrictions[$action] = implode( '', $this->mTitle->getRestrictions( $action ) );
 41+ }
 42+ }
 43+
 44+ / The form will be available in read-only to show levels.
 45+ $this->disabled = !$wgUser->isAllowed( 'protect' ) || wfReadOnly();
 46+ $this->disabledAttrib = $this->disabled
 47+ ? array( 'disabled' => 'disabled' )
 48+ : array();
 49+
 50+ if( $wgRequest->wasPosted() ) {
 51+ $this->mReason = $wgRequest->getText( 'mwProtect-reason' );
 52+ foreach( $wgRestrictionTypes as $action ) {
 53+ $val = $wgRequest->getVal( "mwProtect-level-$action" );
 54+ if( isset( $val ) && in_array( $val, $wgRestrictionLevels ) ) {
 55+ $this->mRestrictions[$action] = $val;
 56+ }
 57+ }
 58+ }
 59+ }
 60+
 61+ function show() {
 62+ global $wgOut;
 63+
 64+ $wgOut->setRobotpolicy( 'noindex,nofollow' );
 65+
 66+ if( is_null( $this->mTitle ) ||
 67+ !$this->mTitle->exists() ||
 68+ $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
 69+ $wgOut->fatalError( wfMsg( 'badarticleerror' ) );
 70+ return;
 71+ }
 72+
 73+ if( $this->save() ) {
 74+ $wgOut->redirect( $this->mTitle->getFullUrl() );
 75+ return;
 76+ }
 77+
 78+ $wgOut->setPageTitle( wfMsg( 'confirmprotect' ) );
 79+ $wgOut->setSubtitle( wfMsg( 'protectsub', $this->mTitle->getPrefixedText() ) );
 80+
 81+ $wgOut->addWikiText(
 82+ wfMsg( $this->disabled ? "protect-viewtext" : "protect-text",
 83+ $this->mTitle->getPrefixedText() ) );
 84+
 85+ $wgOut->addHTML( $this->buildForm() );
 86+
 87+ $this->showLogExtract( $wgOut );
 88+ }
 89+
 90+ function save() {
 91+ global $wgRequest, $wgUser;
 92+ if( !$wgRequest->wasPosted() ) {
 93+ return false;
 94+ }
 95+
 96+ if( $this->disabled ) {
 97+ return false;
 98+ }
 99+
 100+ $token = $wgRequest->getVal( 'wpEditToken' );
 101+ if( !$wgUser->matchEditToken( $token ) ) {
 102+ $wgOut->fatalError( wfMsg( 'sessionfailure' ) );
 103+ return false;
 104+ }
 105+
 106+ $ok = $this->mArticle->updateRestrictions( $this->mRestrictions, $this->mReason );
 107+ if( !$ok ) {
 108+ $wgOut->fatalError( "Unknown error at restriction save time." );
 109+ }
 110+ return $ok;
 111+ }
 112+
 113+ function buildForm() {
 114+ global $wgUser;
 115+
 116+ $out = '';
 117+ if( !$this->disabled ) {
 118+ $out .= $this->buildScript();
 119+ / The submission needs to reenable the move permission selector
 120+ / if it's in locked mode, or some browsers won't submit the data.
 121+ $out .= wfOpenElement( 'form', array(
 122+ 'action' => $this->mTitle->getLocalUrl( 'action=protect' ),
 123+ 'method' => 'post',
 124+ 'onsubmit' => 'protectEnable(true)' ) );
 125+
 126+ $out .= wfElement( 'input', array(
 127+ 'type' => 'hidden',
 128+ 'name' => 'wpEditToken',
 129+ 'value' => $wgUser->editToken() ) );
 130+ }
 131+
 132+ $out .= "<table id='mwProtectSet'>";
 133+ $out .= "<tbody>";
 134+ $out .= "<tr>\n";
 135+ foreach( $this->mRestrictions as $action => $required ) {
 136+ $out .= "<th>" . wfMsgHtml( $action ) . "</th>\n";
 137+ }
 138+ $out .= "</tr>\n";
 139+ $out .= "<tr>\n";
 140+ foreach( $this->mRestrictions as $action => $selected ) {
 141+ $out .= "<td>\n";
 142+ $out .= $this->buildSelector( $action, $selected );
 143+ $out .= "</td>\n";
 144+ }
 145+ $out .= "</tr>\n";
 146+
 147+ / JavaScript will add another row with a value-chaining checkbox
 148+
 149+ $out .= "</tbody>\n";
 150+ $out .= "</table>\n";
 151+
 152+ if( !$this->disabled ) {
 153+ $out .= "<table>\n";
 154+ $out .= "<tbody>\n";
 155+ $out .= "<tr><td>" . $this->buildReasonInput() . "</td></tr>\n";
 156+ $out .= "<tr><td></td><td>" . $this->buildSubmit() . "</td></tr>\n";
 157+ $out .= "</tbody>\n";
 158+ $out .= "</table>\n";
 159+ $out .= "</form>\n";
 160+ $out .= $this->buildCleanupScript();
 161+ }
 162+
 163+ return $out;
 164+ }
 165+
 166+ function buildSelector( $action, $selected ) {
 167+ global $wgRestrictionLevels;
 168+ $id = 'mwProtect-level-' . $action;
 169+ $attribs = array(
 170+ 'id' => $id,
 171+ 'name' => $id,
 172+ 'size' => count( $wgRestrictionLevels ),
 173+ 'onchange' => 'protectLevelsUpdate(this)',
 174+ ) + $this->disabledAttrib;
 175+
 176+ $out = wfOpenElement( 'select', $attribs );
 177+ foreach( $wgRestrictionLevels as $key ) {
 178+ $out .= $this->buildOption( $key, $selected );
 179+ }
 180+ $out .= "</select>\n";
 181+ return $out;
 182+ }
 183+
 184+ function buildOption( $key, $selected ) {
 185+ $text = ( $key == '' )
 186+ ? wfMsg( 'protect-default' )
 187+ : wfMsg( "protect-level-$key" );
 188+ $selectedAttrib = ($selected == $key)
 189+ ? array( 'selected' => 'selected' )
 190+ : array();
 191+ return wfElement( 'option',
 192+ array( 'value' => $key ) + $selectedAttrib,
 193+ $text );
 194+ }
 195+
 196+ function buildReasonInput() {
 197+ $id = 'mwProtect-reason';
 198+ return wfElement( 'label', array(
 199+ 'id' => "$id-label",
 200+ 'for' => $id ),
 201+ wfMsg( 'protectcomment' ) ) .
 202+ '</td><td>' .
 203+ wfElement( 'input', array(
 204+ 'size' => 60,
 205+ 'name' => $id,
 206+ 'id' => $id ) );
 207+ }
 208+
 209+ function buildSubmit() {
 210+ return wfElement( 'input', array(
 211+ 'type' => 'submit',
 212+ 'value' => wfMsg( 'confirm' ) ) );
 213+ }
 214+
 215+ function buildScript() {
 216+ global $wgStylePath;
 217+ return '<script type="text/javascript" src="' .
 218+ htmlspecialchars( $wgStylePath . "/common/protect.js" ) .
 219+ '"></script>';
 220+ }
 221+
 222+ function buildCleanupScript() {
 223+ return '<script type="text/javascript">protectInitialize("mwProtectSet","' .
 224+ wfEscapeJsString( wfMsg( 'protect-unchain' ) ) . '")</script>';
 225+ }
 226+
 227+ /**
 228+ * @param OutputPage $out
 229+ * @access private
 230+ */
 231+ function showLogExtract( &$out ) {
 232+ # Show relevant lines from the deletion log:
 233+ $out->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'protect' ) ) . "</h2>\n" );
 234+ require_once( 'SpecialLog.php' );
 235+ $logViewer = new LogViewer(
 236+ new LogReader(
 237+ new FauxRequest(
 238+ array( 'page' => $this->mTitle->getPrefixedText(),
 239+ 'type' => 'protect' ) ) ) );
 240+ $logViewer->showList( $out );
 241+ }
 242+}
 243+
 244+
 245+?>
\ No newline at end of file
Property changes on: trunk/phase3/includes/ProtectionForm.php
___________________________________________________________________
Added: svn:eol-style
1246 + native
Added: svn:keywords
2247 + Author Date Id Revision
Index: trunk/phase3/includes/User.php
@@ -14,7 +14,7 @@
1515 define( 'USER_TOKEN_LENGTH', 32 );
1616
1717 # Serialized record version
18 -define( 'MW_USER_VERSION', 2 );
 18+define( 'MW_USER_VERSION', 3 );
1919
2020 /**
2121 *
@@ -36,6 +36,7 @@
3737 var $mHash;
3838 var $mGroups;
3939 var $mVersion; / serialized version
 40+ var $mRegistration;
4041
4142 /** Construct using User:loadDefaults() */
4243 function User() {
@@ -107,7 +108,7 @@
108109 return array( 'mId', 'mName', 'mPassword', 'mEmail', 'mNewtalk',
109110 'mEmailAuthenticated', 'mRights', 'mOptions', 'mDataLoaded',
110111 'mNewpassword', 'mBlockedby', 'mBlockreason', 'mTouched',
111 - 'mToken', 'mRealName', 'mHash', 'mGroups' );
 112+ 'mToken', 'mRealName', 'mHash', 'mGroups', 'mRegistration' );
112113 }
113114
114115 /**
@@ -321,6 +322,8 @@
322323 $this->mTouched = '0'; # Allow any pages to be cached
323324 }
324325
 326+ $this->mRegistration = wfTimestamp( TS_MW );
 327+
325328 wfProfileOut( $fname );
326329 }
327330
@@ -651,7 +654,7 @@
652655 } else {
653656 wfDebug( "User::loadFromSession() got from cache!\n" );
654657 }
655 -
 658+
656659 if ( isset( $_SESSION['wsToken'] ) ) {
657660 $passwordCorrect = $_SESSION['wsToken'] == $user->mToken;
658661 } else if ( isset( $_COOKIE["{$wgDBname}Token"] ) ) {
@@ -699,7 +702,7 @@
700703 $dbr =& wfGetDB( DB_SLAVE );
701704 $s = $dbr->selectRow( 'user', array( 'user_name','user_password','user_newpassword','user_email',
702705 'user_email_authenticated',
703 - 'user_real_name','user_options','user_touched', 'user_token' ),
 706+ 'user_real_name','user_options','user_touched', 'user_token', 'user_registration' ),
704707 array( 'user_id' => $this->mId ), $fname );
705708
706709 if ( $s !== false ) {
@@ -712,6 +715,7 @@
713716 $this->decodeOptions( $s->user_options );
714717 $this->mTouched = wfTimestamp(TS_MW,$s->user_touched);
715718 $this->mToken = $s->user_token;
 719+ $this->mRegistration = wfTimestamp( TS_MW, $s->user_registration );
716720
717721 $res = $dbr->select( 'user_groups',
718722 array( 'ug_group' ),
@@ -721,7 +725,15 @@
722726 while( $row = $dbr->fetchObject( $res ) ) {
723727 $this->mGroups[] = $row->ug_group;
724728 }
725 - $effectiveGroups = array_merge( array( '*', 'user' ), $this->mGroups );
 729+ $implicitGroups = array( '*', 'user' );
 730+
 731+ global $wgAutoConfirmAge;
 732+ $accountAge = time() - wfTimestampOrNull( TS_UNIX, $this->mRegistration );
 733+ if( $accountAge >= $wgAutoConfirmAge ) {
 734+ $implicitGroups[] = 'autoconfirmed';
 735+ }
 736+
 737+ $effectiveGroups = array_merge( $implicitGroups, $this->mGroups );
726738 $this->mRights = $this->getGroupPermissions( $effectiveGroups );
727739 }
728740
@@ -1392,7 +1404,8 @@
13931405 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
13941406 'user_real_name' => $this->mRealName,
13951407 'user_options' => $this->encodeOptions(),
1396 - 'user_token' => $this->mToken
 1408+ 'user_token' => $this->mToken,
 1409+ 'user_registration' => $dbw->timestamp( $this->mRegistration ),
13971410 ), $fname
13981411 );
13991412 $this->mId = $dbw->insertId();
@@ -1526,7 +1539,8 @@
15271540 * @return bool True if it is a newbie.
15281541 */
15291542 function isNewbie() {
1530 - return $this->isAnon() || $this->mId > User::getMaxID() * 0.99 && !$this->isAllowed( 'delete' ) && !$this->isBot();
 1543+ return !$this->isAllowed( 'autoconfirmed' );
 1544+ /return $this->isAnon() || $this->mId > User::getMaxID() * 0.99 && !$this->isAllowed( 'delete' ) && !$this->isBot();
15311545 }
15321546
15331547 /**
@@ -1811,9 +1825,9 @@
18121826 global $wgGroupPermissions;
18131827 return array_diff(
18141828 array_keys( $wgGroupPermissions ),
1815 - array( '*', 'user' ) );
 1829+ array( '*', 'user', 'autoconfirmed' ) );
18161830 }
1817 -
 1831+
18181832 }
18191833
18201834 ?>
Index: trunk/phase3/includes/Article.php
@@ -1582,166 +1582,93 @@
15831583 }
15841584
15851585 /**
1586 - * protect a page
 1586+ * action=protect handler
15871587 */
1588 - function protect( $limit = 'sysop' ) {
 1588+ function protect() {
 1589+ require_once 'ProtectionForm.php';
 1590+ $form = new ProtectionForm( $this );
 1591+ $form->show();
 1592+ }
 1593+
 1594+ /**
 1595+ * action=unprotect handler (alias)
 1596+ */
 1597+ function unprotect() {
 1598+ $this->protect();
 1599+ }
 1600+
 1601+ /**
 1602+ * Update the article's restriction field, and leave a log entry.
 1603+ *
 1604+ * @param array $limit set of restriction keys
 1605+ * @param string $reason
 1606+ * @return bool true on success
 1607+ */
 1608+ function updateRestrictions( $limit = array(), $reason = '' ) {
15891609 global $wgUser, $wgOut, $wgRequest;
15901610
1591 - if ( ! $wgUser->isAllowed('protect') ) {
1592 - $wgOut->sysopRequired();
1593 - return;
 1611+ if ( !$wgUser->isAllowed( 'protect' ) ) {
 1612+ return false;
15941613 }
15951614
1596 - / bug 2261
1597 - if ( $this->mTitle->isProtected() && $limit == 'sysop' ) {
1598 - $this->view();
1599 - return;
 1615+ if( wfReadOnly() ) {
 1616+ return false;
16001617 }
16011618
1602 - if ( wfReadOnly() ) {
1603 - $wgOut->readOnlyPage();
1604 - return;
1605 - }
1606 -
16071619 $id = $this->mTitle->getArticleID();
16081620 if ( 0 == $id ) {
1609 - $wgOut->fatalError( wfMsg( 'badarticleerror' ) );
1610 - return;
 1621+ return false;
16111622 }
16121623
1613 - $confirm = $wgRequest->wasPosted() &&
1614 - $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
1615 - $moveonly = $wgRequest->getBool( 'wpMoveOnly' );
1616 - $reason = $wgRequest->getText( 'wpReasonProtect' );
 1624+ $flat = Article::flattenRestrictions( $limit );
 1625+ $protecting = ($flat != '');
 1626+
 1627+ if( wfRunHooks( 'ArticleProtect', array( &$this, &$wgUser,
 1628+ $limit, $reason ) ) ) {
16171629
1618 - if ( $confirm ) {
16191630 $dbw =& wfGetDB( DB_MASTER );
16201631 $dbw->update( 'page',
16211632 array( /* SET */
16221633 'page_touched' => $dbw->timestamp(),
1623 - 'page_restrictions' => (string)$limit
 1634+ 'page_restrictions' => $flat
16241635 ), array( /* WHERE */
16251636 'page_id' => $id
16261637 ), 'Article::protect'
16271638 );
16281639
1629 - $restrictions = "move=" . $limit;
1630 - if( !$moveonly ) {
1631 - $restrictions .= ":edit=" . $limit;
1632 - }
1633 - if (wfRunHooks('ArticleProtect', array(&$this, &$wgUser, $limit == 'sysop', $reason, $moveonly))) {
 1640+ wfRunHooks( 'ArticleProtectComplete', array( &$this, &$wgUser,
 1641+ $limit, $reason ) );
16341642
1635 - $dbw =& wfGetDB( DB_MASTER );
1636 - $dbw->update( 'page',
1637 - array( /* SET */
1638 - 'page_touched' => $dbw->timestamp(),
1639 - 'page_restrictions' => $restrictions
1640 - ), array( /* WHERE */
1641 - 'page_id' => $id
1642 - ), 'Article::protect'
1643 - );
1644 -
1645 - wfRunHooks('ArticleProtectComplete', array(&$this, &$wgUser, $limit == 'sysop', $reason, $moveonly));
1646 -
1647 - $log = new LogPage( 'protect' );
1648 - if ( $limit === '' ) {
1649 - $log->addEntry( 'unprotect', $this->mTitle, $reason );
1650 - } else {
1651 - $log->addEntry( 'protect', $this->mTitle, $reason );
1652 - }
1653 - $wgOut->redirect( $this->mTitle->getFullURL() );
 1643+ $log = new LogPage( 'protect' );
 1644+ if( $protecting ) {
 1645+ $log->addEntry( 'protect', $this->mTitle, trim( $reason . " [$flat]" ) );
 1646+ } else {
 1647+ $log->addEntry( 'unprotect', $this->mTitle, $reason );
16541648 }
1655 - return;
1656 - } else {
1657 - return $this->confirmProtect( '', '', $limit );
16581649 }
 1650+ return true;
16591651 }
1660 -
 1652+
16611653 /**
1662 - * Output protection confirmation dialog
 1654+ * Take an array of page restrictions and flatten it to a string
 1655+ * suitable for insertion into the page_restrictions field.
 1656+ * @param array $limit
 1657+ * @return string
 1658+ * @access private
16631659 */
1664 - function confirmProtect( $par, $reason, $limit = 'sysop' ) {
1665 - global $wgOut, $wgUser;
1666 -
1667 - wfDebug( "Article::confirmProtect\n" );
1668 -
1669 - $sub = htmlspecialchars( $this->mTitle->getPrefixedText() );
1670 - $wgOut->setRobotpolicy( 'noindex,nofollow' );
1671 -
1672 - $check = '';
1673 - $protcom = '';
1674 - $moveonly = '';
1675 -
1676 - if ( $limit === '' ) {
1677 - $wgOut->setPageTitle( wfMsg( 'confirmunprotect' ) );
1678 - $wgOut->setSubtitle( wfMsg( 'unprotectsub', $sub ) );
1679 - $wgOut->addWikiText( wfMsg( 'confirmunprotecttext' ) );
1680 - $protcom = htmlspecialchars( wfMsg( 'unprotectcomment' ) );
1681 - $formaction = $this->mTitle->escapeLocalURL( 'action=unprotect' . $par );
1682 - } else {
1683 - $wgOut->setPageTitle( wfMsg( 'confirmprotect' ) );
1684 - $wgOut->setSubtitle( wfMsg( 'protectsub', $sub ) );
1685 - $wgOut->addWikiText( wfMsg( 'confirmprotecttext' ) );
1686 - $moveonly = wfMsg( 'protectmoveonly' ) ; / add it using addWikiText to prevent xss. bug:3991
1687 - $protcom = htmlspecialchars( wfMsg( 'protectcomment' ) );
1688 - $formaction = $this->mTitle->escapeLocalURL( 'action=protect' . $par );
 1660+ function flattenRestrictions( $limit ) {
 1661+ if( !is_array( $limit ) ) {
 1662+ wfDebugDieBacktrace( 'Article::flattenRestrictions given non-array restriction set' );
16891663 }
1690 -
1691 - $confirm = htmlspecialchars( wfMsg( 'protectpage' ) );
1692 - $token = htmlspecialchars( $wgUser->editToken() );
1693 -
1694 - $wgOut->addHTML( "
1695 -<form id='protectconfirm' method='post' action=\"{$formaction}\">
1696 - <table border='0'>
1697 - <tr>
1698 - <td align='right'>
1699 - <label for='wpReasonProtect'>{$protcom}:</label>
1700 - </td>
1701 - <td align='left'>
1702 - <input type='text' size='60' name='wpReasonProtect' id='wpReasonProtect' value=\"" . htmlspecialchars( $reason ) . "\" />
1703 - </td>
1704 - </tr>" );
1705 - if($moveonly != '') {
1706 - $wgOut->AddHTML( "
1707 - <tr>
1708 - <td align='right'>
1709 - <input type='checkbox' name='wpMoveOnly' value='1' id='wpMoveOnly' />
1710 - </td>
1711 - <td align='left'>
1712 - <label for='wpMoveOnly'> ");
1713 - $wgOut->addWikiText( $moveonly ); / bug 3991
1714 - $wgOut->addHTML( "
1715 - </label>
1716 - </td>
1717 - </tr> " );
 1664+ $bits = array();
 1665+ foreach( $limit as $action => $restrictions ) {
 1666+ if( $restrictions != '' ) {
 1667+ $bits[] = "$action=$restrictions";
 1668+ }
17181669 }
1719 - $wgOut->addHTML( "
1720 - <tr>
1721 - <td>&nbsp;</td>
1722 - <td>
1723 - <input type='submit' name='wpConfirmProtectB' value=\"{$confirm}\" />
1724 - </td>
1725 - </tr>
1726 - </table>
1727 - <input type='hidden' name='wpEditToken' value=\"{$token}\" />
1728 -</form>" );
1729 -
1730 - $wgOut->returnToMain( false );
 1670+ return implode( ':', $bits );
17311671 }
17321672
1733 - /**
1734 - * Unprotect the pages
1735 - */
1736 - function unprotect() {
1737 - / bug 2261
1738 - if ( $this->mTitle->isProtected() ) {
1739 - return $this->protect( '' );
1740 - } else {
1741 - $this->view();
1742 - return;
1743 - }
1744 - }
1745 -
17461673 /*
17471674 * UI entry point for page deletion
17481675 */
Index: trunk/phase3/includes/SpecialLog.php
@@ -275,7 +275,6 @@
276276
277277 function doShowList( &$out, $result ) {
278278 / Rewind result pointer and go through it again, making the HTML
279 - $html='';
280279 if ($this->numResults > 0) {
281280 $html = "\n<ul>\n";
282281 $result->seek( 0 );
@@ -283,9 +282,11 @@
284283 $html .= $this->logLine( $s );
285284 }
286285 $html .= "\n</ul>\n";
 286+ $out->addHTML( $html );
 287+ } else {
 288+ $out->addWikiText( wfMsg( 'logempty' ) );
287289 }
288290 $result->free();
289 - $out->addHTML( $html );
290291 }
291292
292293 /**
Index: trunk/phase3/includes/DefaultSettings.php
@@ -772,12 +772,14 @@
773773 */
774774 $wgGroupPermissions = array();
775775
 776+/ Implicit group for all visitors
776777 $wgGroupPermissions['*' ]['createaccount'] = true;
777778 $wgGroupPermissions['*' ]['read'] = true;
778779 $wgGroupPermissions['*' ]['edit'] = true;
779780 $wgGroupPermissions['*' ]['createpage'] = true;
780781 $wgGroupPermissions['*' ]['createtalk'] = true;
781782
 783+/ Implicit group for all logged-in accounts
782784 $wgGroupPermissions['user' ]['move'] = true;
783785 $wgGroupPermissions['user' ]['read'] = true;
784786 $wgGroupPermissions['user' ]['edit'] = true;
@@ -787,8 +789,15 @@
788790 $wgGroupPermissions['user' ]['reupload'] = true;
789791 $wgGroupPermissions['user' ]['reupload-shared'] = true;
790792
 793+/ Implicit group for accounts that pass $wgAutoConfirmAge
 794+$wgGroupPermissions['autoconfirmed']['autoconfirmed'] = true;
 795+
 796+/ Users with bot privilege can have their edits hidden
 797+/ from various log pages by default
791798 $wgGroupPermissions['bot' ]['bot'] = true;
 799+$wgGroupPermissions['bot' ]['autoconfirmed'] = true;
792800
 801+/ Most extra permission abilities go to this group
793802 $wgGroupPermissions['sysop']['block'] = true;
794803 $wgGroupPermissions['sysop']['createaccount'] = true;
795804 $wgGroupPermissions['sysop']['delete'] = true;
@@ -803,7 +812,9 @@
804813 $wgGroupPermissions['sysop']['reupload'] = true;
805814 $wgGroupPermissions['sysop']['reupload-shared'] = true;
806815 $wgGroupPermissions['sysop']['unwatchedpages'] = true;
 816+$wgGroupPermissions['sysop']['autoconfirmed'] = true;
807817
 818+/ Permission to change users' group assignments
808819 $wgGroupPermissions['bureaucrat']['userrights'] = true;
809820
810821 /**
@@ -815,7 +826,36 @@
816827 # $wgGroupPermissions['developer']['siteadmin'] = true;
817828
818829
 830+/**
 831+ * Set of available actions that can be restricted via Special:Protect
 832+ * You probably shouldn't change this.
 833+ */
 834+$wgRestrictionTypes = array( 'edit', 'move' );
819835
 836+/**
 837+ * Set of permission keys that can be selected via Special:Protect.
 838+ * 'autoconfirm' allows all registerd users if $wgAutoConfirmAge is 0.
 839+ */
 840+$wgRestrictionLevels = array( '', 'autoconfirmed', 'sysop' );
 841+
 842+
 843+/**
 844+ * Number of seconds an account is required to age before
 845+ * it's given the implicit 'autoconfirm' group membership.
 846+ * This can be used to limit privileges of new accounts.
 847+ *
 848+ * Accounts created by earlier versions of the software
 849+ * may not have a recorded creation date, and will always
 850+ * be considered to pass the age test.
 851+ *
 852+ * When left at 0, all registered accounts will pass.
 853+ */
 854+$wgAutoConfirmAge = 0;
 855+/$wgAutoConfirmAge = 600; / ten minutes
 856+/$wgAutoConfirmAge = 3600*24; / one day
 857+
 858+
 859+
820860 # Proxy scanner settings
821861 #
822862
Index: trunk/phase3/RELEASE-NOTES
@@ -341,6 +341,10 @@
342342 * (bug 3424) Update page_touched for category members on category page creation
343343 * (bug 4108, 4336) Remove trailing whitespace from various messages, which
344344 mucks up message updating to create dupe entries
 345+* (bug 1735) Revamped protection interface
 346+* (bug 675) Add page protection level for unregistered/new accounts
 347+* User::isNewbie now uses the registration date and $wgAutoconfirmAge
 348+* Log views show message when no matches
345349
346350
347351 === Caveats ===
Index: trunk/phase3/languages/Language.php
@@ -1208,7 +1208,9 @@
12091209 'log' => 'Logs',
12101210 'alllogstext' => 'Combined display of upload, deletion, protection, blocking, and sysop logs.
12111211 You can narrow down the view by selecting a log type, the user name, or the affected page.',
 1212+'logempty' => 'No matching items in log.',
12121213
 1214+
12131215 # Special:Allpages
12141216 'nextpage' => 'Next page ($1)',
12151217 'allpagesfrom' => 'Display pages starting at:',
@@ -1376,7 +1378,16 @@
13771379 'confirmunprotecttext' => 'Do you really want to unprotect this page?',
13781380 'confirmunprotect' => 'Confirm unprotection',
13791381 'unprotectcomment' => 'Reason for unprotecting',
 1382+'protect-unchain' => 'Unlock move permissions',
 1383+'protect-text' => 'You may view and change the protection level here for the page [[$1]].
 1384+Please be sure you are following the [[Project:Protected page|project guidelines]].',
 1385+'protect-viewtext' => 'Your account does not have permission to change
 1386+page protection levels. Here are the current settings for the page [[$1]]:',
 1387+'protect-default' => '(default)',
 1388+'protect-level-autoconfirmed' => 'Block unregistered users',
 1389+'protect-level-sysop' => 'Sysops only',
13801390
 1391+
13811392 # Undelete
13821393 'undelete' => 'View deleted pages',
13831394 'undeletepage' => 'View and restore deleted pages',

Status & tagging log

Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant