--- /dev/null
+<?php
+
+# Wikimedia Foundation Board of Trustees Election
+
+# Register extension
+$wgExtensionFunctions[] = "wfBoardvoteSetup";
+
+
+function wfBoardvoteSetup()
+{
+# Look out, freaky indenting
+# All this happens after SpecialPage.php has been included in Setup.php
+
+class BoardVotePage extends SpecialPage {
+ var $mPosted, $mContributing, $mVolunteer, $mDBname, $mUserDays, $mUserEdits;
+ var $mHasVoted, $mAction, $mUserKey;
+
+ function BoardVotePage() {
+ SpecialPage::SpecialPage( "Boardvote" );
+ }
+
+ function execute( $par ) {
+ global $wgUser, $wgDBname, $wgInputEncoding, $wgRequest, $wgBoardVoteDB;
+
+ $this->mUserKey = iconv( $wgInputEncoding, "UTF-8", $wgUser->getName() ) . "@$wgDBname";
+ $this->mPosted = $wgRequest->wasPosted();
+ $this->mContributing = $wgRequest->getInt( "contributing" );
+ $this->mVolunteer = $wgRequest->getInt( "volunteer" );
+ $this->mDBname = $wgBoardVoteDB;
+ $this->mHasVoted = $this->hasVoted( $wgUser );
+
+ if ( $par ) {
+ $this->mAction = $par;
+ } else {
+ $this->mAction = $wgRequest->getText( "action" );
+ }
+
+ $this->setHeaders();
+
+ if ( $this->mAction == "list" ) {
+ $this->displayList();
+ } elseif ( $this->mAction == "dump" ) {
+ $this->dump();
+ } elseif( $this->mAction == "vote" ) {
+ if ( !$wgUser->getID() ) {
+ $this->notLoggedIn();
+ } else {
+ $this->getQualifications( $wgUser );
+ if ( $this->mUserDays < 90 ) {
+ $this->notQualified();
+ } elseif ( $this->mPosted ) {
+ $this->logVote();
+ } else {
+ $this->displayVote();
+ }
+ }
+ } else {
+ $this->displayEntry();
+ }
+ }
+
+ function displayEntry() {
+ global $wgOut;
+ $wgOut->addWikiText( wfMsg( "boardvote_entry" ) );
+ }
+
+ function hasVoted( &$user ) {
+ global $wgDBname;
+ $row = wfGetArray( $this->mDBname . ".log", array( "1" ),
+ array( "log_user_key" => $this->mUserKey ), "BoardVotePage::getUserVote" );
+ if ( $row === false ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ function logVote() {
+ global $wgUser, $wgDBname, $wgIP, $wgOut;
+ $fname = "BoardVotePage::logVote";
+
+ $now = wfTimestampNow();
+ $record = $this->encrypt( $this->mContributing, $this->mVolunteer );
+ $db = $this->mDBname;
+
+ # Mark previous votes as old
+ $encKey = wfStrencode( $this->mUserKey );
+ $sql = "UPDATE $db.log SET log_current=0 WHERE log_user_key='$encKey'";
+ wfQuery( $sql, DB_WRITE, $fname );
+
+ # Add vote to log
+ wfInsertArray( "$db.log", array(
+ "log_user" => $wgUser->getID(),
+ "log_user_text" => $wgUser->getName(),
+ "log_user_key" => $this->mUserKey,
+ "log_wiki" => $wgDBname,
+ "log_edits" => $this->mUserEdits,
+ "log_days" => $this->mUserDays,
+ "log_record" => $record,
+ "log_ip" => $wgIP,
+ "log_xff" => @$_SERVER['HTTP_X_FORWARDED_FOR'],
+ "log_ua" => $_SERVER['HTTP_USER_AGENT'],
+ "log_timestamp" => $now,
+ "log_current" => 1
+ ), $fname );
+
+ $wgOut->addWikiText( wfMsg( "boardvote_entered", $record ) );
+ }
+
+ function displayVote() {
+ global $wgContributingCandidates, $wgVolunteerCandidates, $wgOut;
+
+ $thisTitle = Title::makeTitle( NS_SPECIAL, "Boardvote" );
+ $action = $thisTitle->getLocalURL( "action=vote" );
+ if ( $this->mHasVoted ) {
+ $intro = wfMsg( "boardvote_intro_change" );
+ } else {
+ $intro = wfMsg( "boardvote_intro" );
+ }
+ $contributing = wfMsg( "boardvote_contributing" );
+ $volunteer = wfMsg( "boardvote_volunteer" );
+ $ok = wfMsg( "ok" );
+
+ $candidatesV = $candidatesC = array();
+ foreach( $wgContributingCandidates as $i => $candidate ) {
+ $candidatesC[] = array( $i, $candidate );
+ }
+ foreach ( $wgVolunteerCandidates as $i => $candidate ) {
+ $candidatesV[] = array( $i, $candidate );
+ }
+
+ srand ((float)microtime()*1000000);
+ shuffle( $candidatesC );
+ shuffle( $candidatesV );
+
+ $text = "
+ $intro
+ <form name=\"boardvote\" id=\"boardvote\" method=\"post\" action=\"$action\">
+ <table border='0'><tr><td colspan=2>
+ <h2>$contributing</h2>
+ </td></tr>";
+ $text .= $this->voteEntry( -1, wfMsg( "boardvote_abstain" ), "contributing" );
+ foreach ( $candidatesC as $candidate ) {
+ $text .= $this->voteEntry( $candidate[0], $candidate[1], "contributing" );
+ }
+ $text .= "
+ <tr><td colspan=2>
+ <h2>$volunteer</h2></td></tr>";
+ $text .= $this->voteEntry( -1, wfMsg( "boardvote_abstain" ), "volunteer" );
+ foreach ( $candidatesV as $candidate ) {
+ $text .= $this->voteEntry( $candidate[0], $candidate[1], "volunteer" );
+ }
+
+ $text .= "<tr><td> </td><td>
+ <input name=\"submit\" type=\"submit\" value=\"$ok\">
+ </td></tr></table></form>";
+ $text .= wfMsg( "boardvote_footer" );
+ $wgOut->addHTML( $text );
+ }
+
+ function voteEntry( $index, $candidate, $name ) {
+ if ( $index == -1 ) {
+ $checked = " CHECKED";
+ } else {
+ $checked = "";
+ }
+
+ return "
+ <tr><td align=\"right\">
+ <input type=\"radio\" name=\"$name\" value=\"$index\"$checked>
+ </td><td align=\"left\">
+ $candidate
+ </td></tr>";
+ }
+
+ function notLoggedIn() {
+ global $wgOut;
+ $wgOut->addWikiText( wfMsg( "boardvote_notloggedin" ) );
+ }
+
+ function notQualified() {
+ global $wgOut;
+ $wgOut->addWikiText( wfMsg( "boardvote_notqualified", $this->mUserDays ) );
+ }
+
+ function encrypt( $contributing, $volunteer ) {
+ global $wgVolunteerCandidates, $wgContributingCandidates;
+ global $wgGPGCommand, $wgGPGRecipient, $wgGPGHomedir;
+ $file = @fopen( "/dev/urandom", "r" );
+ if ( $file ) {
+ $salt = implode( "", unpack( "H*", fread( $file, 64 ) ));
+ fclose( $file );
+ } else {
+ $salt = Parser::getRandomString() . Parser::getRandomString();
+ }
+ $record =
+ "Contributing: $contributing (" .$wgContributingCandidates[$contributing] . ")\n" .
+ "Volunteer: $volunteer (" . $wgVolunteerCandidates[$volunteer] . ")\n" .
+ "Salt: $salt\n";
+ # Get file names
+ $input = tempnam( "/tmp", "gpg_" );
+ $output = tempnam( "/tmp", "gpg_" );
+
+ # Write unencrypted record
+ $file = fopen( $input, "w" );
+ fwrite( $file, $record );
+ fclose( $file );
+
+ # Call GPG
+ $command = wfEscapeShellArg( $wgGPGCommand ) . " --batch --yes -ear " .
+ wfEscapeShellArg( $wgGPGRecipient ) . " -o " . wfEscapeShellArg( $output );
+ if ( $wgGPGHomedir ) {
+ $command .= " --homedir " . wfEscapeShellArg( $wgGPGHomedir );
+ }
+ $command .= " " . wfEscapeShellArg( $input );
+
+ shell_exec( $command );
+
+ # Read result
+ $result = file_get_contents( $output );
+
+ # Delete temporary files
+ unlink( $input );
+ unlink( $output );
+
+ return $result;
+ }
+
+ function getQualifications( &$user ) {
+ $id = $user->getID();
+ if ( !$id ) {
+ $this->mUserDays = 0;
+ $this->mUserEdits = 0;
+ return;
+ }
+
+ # Count contributions and find earliest edit
+ # First cur
+ $sql = "SELECT COUNT(*) as n, MIN(cur_timestamp) as t FROM cur WHERE cur_user=$id";
+ $res = wfQuery( $sql, DB_READ, "BoardVotePage::getQualifications" );
+ $cur = wfFetchObject( $res );
+ wfFreeResult( $res );
+
+ # If the user has stacks of contributions, don't check old as well
+ $now = time();
+ if ( is_null( $cur->t ) ) {
+ $signup = $now;
+ } else {
+ $signup = wfTimestamp2Unix( $cur->t );
+ }
+
+ $days = ($now - $signup) / 86400;
+ if ( $cur->n > 400 && $days > 180 ) {
+ $this->mUserDays = 0x7fffffff;
+ $this->mUserEdits = 0x7fffffff;
+ return;
+ }
+
+ # Now check old
+ $sql = "SELECT COUNT(*) as n, MIN(old_timestamp) as t FROM old WHERE old_user=$id";
+ $res = wfQuery( $sql, DB_READ, "BoardVotePage::getQualifications" );
+ $old = wfFetchObject( $res );
+ wfFreeResult( $res );
+
+ if ( !is_null( $old->t ) ) {
+ $signup = min( wfTimestamp2Unix( $old->t ), $signup );
+ }
+ $this->mUserDays = (int)(($now - $signup) / 86400);
+ $this->mUserEdits = $cur->n + $old->n;
+ }
+
+ function displayList() {
+ global $wgOut, $wgOutputEncoding, $wgLang, $wgUser;
+ $sql = "SELECT log_timestamp,log_user_key FROM {$this->mDBname}.log ORDER BY log_user_key";
+ $res = wfQuery( $sql, DB_READ, "BoardVotePage::list" );
+ if ( wfNumRows( $res ) == 0 ) {
+ $wgOut->addWikiText( wfMsg( "boardvote_novotes" ) );
+ return;
+ }
+ $thisTitle = Title::makeTitle( NS_SPECIAL, "Boardvote" );
+ $sk = $wgUser->getSkin();
+ $dumpLink = $sk->makeKnownLinkObj( $thisTitle, wfMsg( "boardvote_dumplink" ), "action=dump" );
+
+ $intro = wfMsg( "boardvote_listintro", $dumpLink );
+ $hTime = wfMsg( "boardvote_time" );
+ $hUser = wfMsg( "boardvote_user" );
+ $hContributing = wfMsg( "boardvote_contributing" );
+ $hVolunteer = wfMsg( "boardvote_volunteer" );
+
+ $s = "$intro <table border=1><tr><th>
+ $hUser
+ </th><th>
+ $hTime
+ </th></tr>";
+
+ while ( $row = wfFetchObject( $res ) ) {
+ if ( $wgOutputEncoding != "utf-8" ) {
+ $user = wfUtf8ToHTML( $row->log_user_key );
+ } else {
+ $user = $row->log_user_key;
+ }
+ $time = $wgLang->timeanddate( $row->log_timestamp );
+ $s .= "<tr><td>
+ $user
+ </td><td>
+ $time
+ </td></tr>";
+ }
+ $s .= "</table>";
+ $wgOut->addHTML( $s );
+ }
+
+ function dump() {
+ global $wgOut, $wgOutputEncoding, $wgLang, $wgUser;
+
+ $userRights = $wgUser->getRights();
+ if ( in_array( "boardvote", $userRights ) ) {
+ $admin = true;
+ } else {
+ $admin = false;
+ }
+
+ $sql = "SELECT * FROM {$this->mDBname}.log";
+ $res = wfQuery( $sql, DB_READ, "BoardVotePage::list" );
+ if ( wfNumRows( $res ) == 0 ) {
+ $wgOut->addWikiText( wfMsg( "boardvote_novotes" ) );
+ return;
+ }
+ $s = "<table border=1>";
+ if ( $admin ) {
+ $s .= wfMsg( "boardvote_dumpheader" );
+ }
+
+ while ( $row = wfFetchObject( $res ) ) {
+ if ( $wgOutputEncoding != "utf-8" ) {
+ $user = wfUtf8ToHTML( $row->log_user_key );
+ } else {
+ $user = $row->log_user_key;
+ }
+ $time = $wgLang->timeanddate( $row->log_timestamp );
+ $record = nl2br( $row->log_record );
+ if ( $admin ) {
+ $edits = $row->log_edits == 0x7fffffff ? "many" : $row->log_edits;
+ $days = $row->log_days == 0x7fffffff ? "many" : $row->log_days;
+ $s .= "<tr><td>
+ $time
+ </td><td>
+ $user
+ </td><td>
+ $edits
+ </td><td>
+ $days
+ </td><td>
+ {$row->log_ip}
+ </td><td>
+ {$row->log_ua}
+ </td><td>
+ $record
+ </td></tr>";
+ } else {
+ $s .= "<tr><td>$time</td><td>$user</td><td>$record</td></tr>";
+ }
+ }
+ $s .= "</table>";
+ $wgOut->addHTML( $s );
+ }
+}
+
+SpecialPage::addPage( new BoardVotePage );
+
+global $wgMessageCache;
+$wgMessageCache->addMessages( array(
+# Board vote
+"boardvote" => "Wikimedia Board of Trustees election",
+"boardvote_entry" =>
+"* [[Special:Boardvote/vote|Vote]]
+* [[Special:Boardvote/list|List votes to date]]
+* [[Special:Boardvote/dump|Dump encrypted election record]]",
+"boardvote_intro" => "<p>Please choose your preferred candidate for both the
+Contributing Representative and the Volunteer Representative.</p>",
+"boardvote_intro_change" => "<p>You have voted before. However you may change
+your vote using the form below.</p>",
+"boardvote_abstain" => "Abstain",
+"boardvote_footer" => " ",
+"boardvote_entered" => "Thank you, your vote has been recorded.
+
+Following is your encrypted vote record. It will appear publicly at [[Special:Boardvote/dump]].
+
+<pre>$1</pre>
+
+[[Special:Boardvote/entry|Back]]",
+"boardvote_notloggedin" => "You are not logged in. To vote, you must use an account
+which has existed for at least 90 days.",
+"boardvote_notqualified" => "Sorry, your first contribution was only $1 days ago.
+You need to have been contributing for at least 90 days to vote in this election.",
+"boardvote_novotes" => "Nobody has voted yet.",
+"boardvote_contributing" => "Contributing candidate",
+"boardvote_volunteer" => "Volunteer candidate",
+"boardvote_time" => "Time",
+"boardvote_user" => "User",
+"boardvote_listintro" => "<p>This is a list of all votes which have been recorded
+to date. $1 for the full encrypted election record.</p>",
+"boardvote_dumplink" => "Click here",
+"boardvote_dumpheader" => "<caption><strong>Election administrator private dump</strong></caption>
+<tr><th>Time</th><th>User</th><th>Edits</th><th>Days</th>
+<th>IP</th><th>User agent</th><th>Record</th></tr>"
+
+));
+
+} # End of extension function
+
+?>
$wgGPGCommand = "gpg";
$wgGPGRecipient = "boardvote";
$wgGPGHomedir = false;
+
+# Extensions
+$wgExtensionFunctions = array();
?>
wfDebugDieBacktrace( "Call to obsolete function wfCleanQueryVar(); use wgRequest instead" );
}
-function wfSpecialPage()
-{
- global $wgUser, $wgOut, $wgTitle, $wgLang;
-
- /* FIXME: this list probably shouldn't be language-specific, per se */
- $validSP = $wgLang->getValidSpecialPages();
- $sysopSP = $wgLang->getSysopSpecialPages();
- $devSP = $wgLang->getDeveloperSpecialPages();
-
- $wgOut->setArticleRelated( false );
- $wgOut->setRobotpolicy( "noindex,follow" );
-
- $bits = split( "/", $wgTitle->getDBkey(), 2 );
- $t = $bits[0];
- if( empty( $bits[1] ) ) {
- $par = NULL;
- } else {
- $par = $bits[1];
- }
-
- if ( array_key_exists( $t, $validSP ) ||
- ( $wgUser->isSysop() && array_key_exists( $t, $sysopSP ) ) ||
- ( $wgUser->isDeveloper() && array_key_exists( $t, $devSP ) ) ) {
- if($par !== NULL)
- $wgTitle = Title::makeTitle( Namespace::getSpecial(), $t );
-
- $wgOut->setPageTitle( wfMsg( strtolower( $wgTitle->getText() ) ) );
-
- $inc = "Special" . $t . ".php";
- require_once( $inc );
- $call = "wfSpecial" . $t;
- $call( $par );
- } else if ( array_key_exists( $t, $sysopSP ) ) {
- $wgOut->sysopRequired();
- } else if ( array_key_exists( $t, $devSP ) ) {
- $wgOut->developerRequired();
- } else {
- $wgOut->errorpage( "nosuchspecialpage", "nospecialpagetext" );
- }
-}
-
function wfSearch( $s )
{
$se = new SearchEngine( $s );
{
var $mCache, $mUseCache, $mDisable, $mExpiry;
var $mMemcKey, $mKeys, $mParserOptions, $mParser;
-
+ var $mExtensionMessages;
+
var $mInitialised = false;
function initialise( &$memCached, $useDB, $expiry, $memcPrefix ) {
return "<$key>";
}
- if ( $this->mDisable ) {
- return $this->transform( $wgLang->getMessage( $key ) );
- }
- $title = $wgLang->ucfirst( $key );
-
$message = false;
+ if ( !$this->mDisable ) {
+ $title = $wgLang->ucfirst( $key );
+
- # Try the cache
- if ( $this->mUseCache && $this->mCache && array_key_exists( $title, $this->mCache ) ) {
- $message = $this->mCache[$title];
- }
-
- # If it wasn't in the cache, load each message from the DB individually
- if ( !$message && $useDB) {
- $result = wfGetArray( "cur", array("cur_text"),
- array( "cur_namespace" => NS_MEDIAWIKI, "cur_title" => $title ),
- "MessageCache::get" );
- if ( $result ) {
- $message = $result->cur_text;
+ # Try the cache
+ if ( $this->mUseCache && $this->mCache && array_key_exists( $title, $this->mCache ) ) {
+ $message = $this->mCache[$title];
}
+
+ # If it wasn't in the cache, load each message from the DB individually
+ if ( !$message && $useDB) {
+ $result = wfGetArray( "cur", array("cur_text"),
+ array( "cur_namespace" => NS_MEDIAWIKI, "cur_title" => $title ),
+ "MessageCache::get" );
+ if ( $result ) {
+ $message = $result->cur_text;
+ }
+ }
+ }
+ # Try the extension array
+ if ( !$message ) {
+ $message = @$this->mExtensionMessages[$key];
}
# Try the array in $wgLang
function enable() { $this->mDisable = false; }
function disableTransform() { $this->mDisableTransform = true; }
+ function addMessage( $key, $value ) {
+ $this->mExtensionMessages[$key] = $value;
+ }
+
+ function addMessages( $messages ) {
+ foreach ( $messages as $key => $value ) {
+ $this->mExtensionMessages[$key] = $value;
+ }
+ }
}
?>
require_once( "Parser.php" );
require_once( "ParserCache.php" );
require_once( "WebRequest.php" );
+require_once( "SpecialPage.php" );
+
$wgRequest = new WebRequest();
$wgParser = new Parser();
$wgOut->setParserOptions( ParserOptions::newFromUser( $wgUser ) );
+if ( !$wgAllowSysopQueries ) {
+ SpecialPage::removePage( "Asksql" );
+}
+
+# Extension setup functions
+# Entries should be added to this variable during the inclusion
+# of the extension file. This allows the extension to perform
+# any necessary initialisation in the fully initialised environment
+foreach ( $wgExtensionFunctions as $func ) {
+ $func();
+}
+
wfProfileOut( "$fname-misc" );
wfProfileOut( $fname );
+++ /dev/null
-<?php
-
-function wfSpecialBoardvote( $par = "" ) {
- global $wgRequest, $wgBoardVoteDB;
-
- $form = new BoardVoteForm( $wgRequest, $wgBoardVoteDB );
- if ( $par ) {
- $form->mAction = $par;
- }
-
- $form->execute();
-}
-
-class BoardVoteForm {
- var $mPosted, $mContributing, $mVolunteer, $mDBname, $mUserDays, $mUserEdits;
- var $mHasVoted, $mAction, $mUserKey;
-
- function BoardVoteForm( &$request, $dbName ) {
- global $wgUser, $wgDBname, $wgInputEncoding;
-
- $this->mUserKey = iconv( $wgInputEncoding, "UTF-8", $wgUser->getName() ) . "@$wgDBname";
- $this->mPosted = $request->wasPosted();
- $this->mContributing = $request->getInt( "contributing" );
- $this->mVolunteer = $request->getInt( "volunteer" );
- $this->mDBname = $dbName;
- $this->mHasVoted = $this->hasVoted( $wgUser );
- $this->mAction = $request->getText( "action" );
- }
-
- function execute() {
- global $wgUser;
- if ( $this->mAction == "list" ) {
- $this->displayList();
- } elseif ( $this->mAction == "dump" ) {
- $this->dump();
- } elseif( $this->mAction == "vote" ) {
- if ( !$wgUser->getID() ) {
- $this->notLoggedIn();
- } else {
- $this->getQualifications( $wgUser );
- if ( $this->mUserDays < 90 ) {
- $this->notQualified();
- } elseif ( $this->mPosted ) {
- $this->logVote();
- } else {
- $this->displayVote();
- }
- }
- } else {
- $this->displayEntry();
- }
- }
-
- function displayEntry() {
- global $wgOut;
- $wgOut->addWikiText( wfMsg( "boardvote_entry" ) );
- }
-
- function hasVoted( &$user ) {
- global $wgDBname;
- $row = wfGetArray( $this->mDBname . ".vote", array( "1" ),
- array( "vote_key" => $this->mUserKey ), "BoardVoteForm::getUserVote" );
- if ( $row === false ) {
- return false;
- } else {
- return true;
- }
- }
-
- function logVote() {
- global $wgUser, $wgDBname, $wgIP, $wgOut;
- $now = wfTimestampNow();
- $record = $this->encrypt( $this->mContributing, $this->mVolunteer );
- $db = $this->mDBname;
-
- # Add vote to log
- wfInsertArray( "$db.log", array(
- "log_user" => $wgUser->getID(),
- "log_user_text" => $wgUser->getName(),
- "log_user_key" => $this->mUserKey,
- "log_wiki" => $wgDBname,
- "log_edits" => $this->mUserEdits,
- "log_days" => $this->mUserDays,
- "log_record" => $record,
- "log_ip" => $wgIP,
- "log_xff" => @$_SERVER['HTTP_X_FORWARDED_FOR'],
- "log_ua" => $_SERVER['HTTP_USER_AGENT'],
- "log_timestamp" => $now
- ));
-
- # Record vote in non-duplicating vote table
- $sql = "REPLACE INTO $db.vote (vote_key,vote_record) " .
- "VALUES ('". wfStrencode( $this->mUserKey ) . "','" . wfStrencode( $record ) . "')";
- wfQuery( $sql, DB_WRITE );
-
- $wgOut->addWikiText( wfMsg( "boardvote_entered", $record ) );
- }
-
- function displayVote() {
- global $wgContributingCandidates, $wgVolunteerCandidates, $wgOut;
-
- $thisTitle = Title::makeTitle( NS_SPECIAL, "Boardvote" );
- $action = $thisTitle->getLocalURL( "action=vote" );
- if ( $this->mHasVoted ) {
- $intro = wfMsg( "boardvote_intro_change" );
- } else {
- $intro = wfMsg( "boardvote_intro" );
- }
- $contributing = wfMsg( "boardvote_contributing" );
- $volunteer = wfMsg( "boardvote_volunteer" );
- $ok = wfMsg( "ok" );
-
- $candidatesV = $candidatesC = array();
- foreach( $wgContributingCandidates as $i => $candidate ) {
- $candidatesC[] = array( $i, $candidate );
- }
- foreach ( $wgVolunteerCandidates as $i => $candidate ) {
- $candidatesV[] = array( $i, $candidate );
- }
-
- srand ((float)microtime()*1000000);
- shuffle( $candidatesC );
- shuffle( $candidatesV );
-
- $text = "
- $intro
- <form name=\"boardvote\" id=\"boardvote\" method=\"post\" action=\"$action\">
- <table border='0'><tr><td colspan=2>
- <h2>$contributing</h2>
- </td></tr>";
- $text .= $this->voteEntry( -1, wfMsg( "boardvote_abstain" ), "contributing" );
- foreach ( $candidatesC as $candidate ) {
- $text .= $this->voteEntry( $candidate[0], $candidate[1], "contributing" );
- }
- $text .= "
- <tr><td colspan=2>
- <h2>$volunteer</h2></td></tr>";
- $text .= $this->voteEntry( -1, wfMsg( "boardvote_abstain" ), "volunteer" );
- foreach ( $candidatesV as $candidate ) {
- $text .= $this->voteEntry( $candidate[0], $candidate[1], "volunteer" );
- }
-
- $text .= "<tr><td> </td><td>
- <input name=\"submit\" type=\"submit\" value=\"$ok\">
- </td></tr></table></form>";
- $text .= wfMsg( "boardvote_footer" );
- $wgOut->addHTML( $text );
- }
-
- function voteEntry( $index, $candidate, $name ) {
- if ( $index == -1 ) {
- $checked = " CHECKED";
- } else {
- $checked = "";
- }
-
- return "
- <tr><td align=\"right\">
- <input type=\"radio\" name=\"$name\" value=\"$index\"$checked>
- </td><td align=\"left\">
- $candidate
- </td></tr>";
- }
-
- function notLoggedIn() {
- global $wgOut;
- $wgOut->addWikiText( wfMsg( "boardvote_notloggedin" ) );
- }
-
- function notQualified() {
- global $wgOut;
- $wgOut->addWikiText( wfMsg( "boardvote_notqualified", $this->mUserDays ) );
- }
-
- function encrypt( $contributing, $volunteer ) {
- global $wgVolunteerCandidates, $wgContributingCandidates;
- global $wgGPGCommand, $wgGPGRecipient, $wgGPGHomedir;
- $file = @fopen( "/dev/urandom", "r" );
- if ( $file ) {
- $salt = implode( "", unpack( "H*", fread( $file, 64 ) ));
- fclose( $file );
- } else {
- $salt = Parser::getRandomString() . Parser::getRandomString();
- }
- $record =
- "Contributing: $contributing (" .$wgContributingCandidates[$contributing] . ")\n" .
- "Volunteer: $volunteer (" . $wgVolunteerCandidates[$volunteer] . ")\n" .
- "Salt: $salt\n";
- # Get file names
- $input = tempnam( "/tmp", "gpg_" );
- $output = tempnam( "/tmp", "gpg_" );
-
- # Write unencrypted record
- $file = fopen( $input, "w" );
- fwrite( $file, $record );
- fclose( $file );
-
- # Call GPG
- $command = wfEscapeShellArg( $wgGPGCommand ) . " --batch --yes -ear " .
- wfEscapeShellArg( $wgGPGRecipient ) . " -o " . wfEscapeShellArg( $output );
- if ( $wgGPGHomedir ) {
- $command .= " --homedir " . wfEscapeShellArg( $wgGPGHomedir );
- }
- $command .= " " . wfEscapeShellArg( $input );
-
- shell_exec( $command );
-
- # Read result
- $result = file_get_contents( $output );
-
- # Delete temporary files
- unlink( $input );
- unlink( $output );
-
- return $result;
- }
-
- function getQualifications( &$user ) {
- $id = $user->getID();
- if ( !$id ) {
- $this->mUserDays = 0;
- $this->mUserEdits = 0;
- return;
- }
-
- # Count contributions and find earliest edit
- # First cur
- $sql = "SELECT COUNT(*) as n, MIN(cur_timestamp) as t FROM cur WHERE cur_user=$id";
- $res = wfQuery( $sql, DB_READ, "BoardVoteForm::getQualifications" );
- $cur = wfFetchObject( $res );
- wfFreeResult( $res );
-
- # If the user has stacks of contributions, don't check old as well
- $now = time();
- if ( is_null( $cur->t ) ) {
- $signup = $now;
- } else {
- $signup = wfTimestamp2Unix( $cur->t );
- }
-
- $days = ($now - $signup) / 86400;
- if ( $cur->n > 400 && $days > 180 ) {
- $this->mUserDays = 0x7fffffff;
- $this->mUserEdits = 0x7fffffff;
- return;
- }
-
- # Now check old
- $sql = "SELECT COUNT(*) as n, MIN(old_timestamp) as t FROM old WHERE old_user=$id";
- $res = wfQuery( $sql, DB_READ, "BoardVoteForm::getQualifications" );
- $old = wfFetchObject( $res );
- wfFreeResult( $res );
-
- if ( !is_null( $old->t ) ) {
- $signup = min( wfTimestamp2Unix( $old->t ), $signup );
- }
- $this->mUserDays = (int)(($now - $signup) / 86400);
- $this->mUserEdits = $cur->n + $old->n;
- }
-
- function displayList() {
- global $wgOut, $wgOutputEncoding, $wgLang, $wgUser;
- $sql = "SELECT log_timestamp,log_user_key FROM {$this->mDBname}.log";
- $res = wfQuery( $sql, DB_READ, "BoardVoteForm::list" );
- if ( wfNumRows( $res ) == 0 ) {
- $wgOut->addWikiText( wfMsg( "boardvote_novotes" ) );
- return;
- }
- $thisTitle = Title::makeTitle( NS_SPECIAL, "Boardvote" );
- $sk = $wgUser->getSkin();
- $dumpLink = $sk->makeKnownLinkObj( $thisTitle, wfMsg( "boardvote_dumplink" ), "action=dump" );
-
- $intro = wfMsg( "boardvote_listintro", $dumpLink );
- $hTime = wfMsg( "boardvote_time" );
- $hUser = wfMsg( "boardvote_user" );
- $hContributing = wfMsg( "boardvote_contributing" );
- $hVolunteer = wfMsg( "boardvote_volunteer" );
-
- $s = "$intro <table border=0><tr><th>
- $hTime
- </th><th>
- $hUser
- </th></tr>";
-
- while ( $row = wfFetchObject( $res ) ) {
- if ( $wgOutputEncoding != "utf-8" ) {
- $user = wfUtf8ToHTML( $row->log_user_key );
- } else {
- $user = $row->log_user_key;
- }
- $time = $wgLang->timeanddate( $row->log_timestamp );
- $s .= "<tr><td>
- $time
- </td><td>
- $user
- </td></tr>";
- }
- $s .= "</table>";
- $wgOut->addHTML( $s );
- }
-
- function dump() {
- global $wgOut, $wgOutputEncoding, $wgLang, $wgUser;
-
- $userRights = $wgUser->getRights();
- if ( in_array( "boardvote", $userRights ) ) {
- $admin = true;
- } else {
- $admin = false;
- }
-
- $sql = "SELECT * FROM {$this->mDBname}.log";
- $res = wfQuery( $sql, DB_READ, "BoardVoteForm::list" );
- if ( wfNumRows( $res ) == 0 ) {
- $wgOut->addWikiText( wfMsg( "boardvote_novotes" ) );
- return;
- }
- $s = "<table border=1>";
- if ( $admin ) {
- $s .= wfMsg( "boardvote_dumpheader" );
- }
-
- while ( $row = wfFetchObject( $res ) ) {
- if ( $wgOutputEncoding != "utf-8" ) {
- $user = wfUtf8ToHTML( $row->log_user_key );
- } else {
- $user = $row->log_user_key;
- }
- $time = $wgLang->timeanddate( $row->log_timestamp );
- $record = nl2br( $row->log_record );
- if ( $admin ) {
- $edits = $row->log_edits == 0x7fffffff ? "many" : $row->log_edits;
- $days = $row->log_days == 0x7fffffff ? "many" : $row->log_days;
- $s .= "<tr><td>
- $time
- </td><td>
- $user
- </td><td>
- $edits
- </td><td>
- $days
- </td><td>
- {$row->log_ip}
- </td><td>
- {$row->log_ua}
- </td><td>
- $record
- </td></tr>";
- } else {
- $s .= "<tr><td>$time</td><td>$user</td><td>$record</td></tr>";
- }
- }
- $s .= "</table>";
- $wgOut->addHTML( $s );
- }
-}
-?>
--- /dev/null
+<?php
+
+$wgSpecialPages = array(
+ "Userlogin" => new UnlistedSpecialPage( "Userlogin" ),
+ "Userlogout" => new UnlistedSpecialPage( "Userlogout" ),
+ "Preferences" => new SpecialPage( "Preferences" ),
+ "Watchlist" => new SpecialPage( "Watchlist" ),
+ "Recentchanges" => new SpecialPage( "Recentchanges" ),
+ "Upload" => new SpecialPage( "Upload" ),
+ "Imagelist" => new SpecialPage( "Imagelist" ),
+ "Listusers" => new SpecialPage( "Listusers" ),
+ "Statistics" => new SpecialPage( "Statistics" ),
+ "Randompage" => new SpecialPage( "Randompage" ),
+ "Lonelypages" => new SpecialPage( "Lonelypages" ),
+ "Unusedimages" => new SpecialPage( "Unusedimages" ),
+ "Popularpages" => new SpecialPage( "Popularpages" ),
+ "Wantedpages" => new SpecialPage( "Wantedpages" ),
+ "Shortpages" => new SpecialPage( "Shortpages" ),
+ "Longpages" => new SpecialPage( "Longpages" ),
+ "Newpages" => new SpecialPage( "Newpages" ),
+ "Ancientpages" => new SpecialPage( "Ancientpages" ),
+ "Deadendpages" => new SpecialPage( "Deadendpages" ),
+ "Allpages" => new SpecialPage( "Allpages" ),
+ "Ipblocklist" => new SpecialPage( "Ipblocklist" ),
+ "Maintenance" => new SpecialPage( "Maintenance" ),
+ "Specialpages" => new UnlistedSpecialPage( "Specialpages" ),
+ "Contributions" => new UnlistedSpecialPage( "Contributions" ),
+ "Emailuser" => new UnlistedSpecialPage( "Emailuser" ),
+ "Whatlinkshere" => new UnlistedSpecialPage( "Whatlinkshere" ),
+ "Recentchangeslinked" => new UnlistedSpecialPage( "Recentchangeslinked" ),
+ "Movepage" => new UnlistedSpecialPage( "Movepage" ),
+ "Blockme" => new UnlistedSpecialPage( "Blockme" ),
+ "Booksources" => new SpecialPage( "Booksources" ),
+ "Categories" => new SpecialPage( "Categories" ),
+ "Export" => new SpecialPage( "Export" ),
+ "Version" => new SpecialPage( "Version" ),
+ "Allmessages" => new SpecialPage( "Allmessages" ),
+ "Search" => new UnlistedSpecialPage( "Search" ),
+ "Blockip" => new SpecialPage( "Blockip", "sysop" ),
+ "Asksql" => new SpecialPage( "Asksql", "sysop" ),
+ "Undelete" => new SpecialPage( "Undelete", "sysop" ),
+ "Makesysop" => new SpecialPage( "Makesysop", "sysop" ),
+ "Import" => new SpecialPage( "Import", "sysop" ),
+ "Lockdb" => new SpecialPage( "Lockdb", "developer" ),
+ "Unlockdb" => new SpecialPage( "Unlockdb", "developer" )
+);
+
+class SpecialPage
+{
+ /* private */ var $mName, $mRestriction, $mListed, $mFunction, $mFile;
+
+ /* static */ function addPage( &$obj ) {
+ global $wgSpecialPages;
+ $wgSpecialPages[$obj->mName] = $obj;
+ }
+
+ /* static */ function removePage( $name ) {
+ global $wgSpecialPages;
+ unset( $wgSpecialPages[$name] );
+ }
+
+ /* static */ function &getPage( $name ) {
+ global $wgSpecialPages;
+ if ( array_key_exists( $name, $wgSpecialPages ) ) {
+ return $wgSpecialPages[$name];
+ } else {
+ return NULL;
+ }
+ }
+
+ # Execute a special page path, which may contain slashes
+ /* static */ function executePath( &$title ) {
+ global $wgSpecialPages, $wgOut, $wgTitle;
+
+ $bits = split( "/", $title->getDBkey(), 2 );
+ $name = $bits[0];
+ if( empty( $bits[1] ) ) {
+ $par = NULL;
+ } else {
+ $par = $bits[1];
+ }
+
+ $page =& SpecialPage::getPage( $name );
+ if ( is_null( $page ) ) {
+ $wgOut->setArticleRelated( false );
+ $wgOut->setRobotpolicy( "noindex,follow" );
+ $wgOut->errorpage( "nosuchspecialpage", "nospecialpagetext" );
+ } else {
+ if($par !== NULL) {
+ $wgTitle = Title::makeTitle( NS_SPECIAL, $name );
+ } else {
+ $wgTitle = $title;
+ }
+
+ $page->execute( $par );
+ }
+ }
+
+ function SpecialPage( $name = "", $restriction = "", $listed = true, $function = false, $file = "default" ) {
+ $this->mName = $name;
+ $this->mRestriction = $restriction;
+ $this->mListed = $listed;
+ if ( $function == false ) {
+ $this->mFunction = "wfSpecial{$name}";
+ } else {
+ $this->mFunction = $function;
+ }
+ if ( $file === "default" ) {
+ $this->mFile = "Special{$name}.php";
+ } else {
+ $this->mFile = $file;
+ }
+ }
+
+ function getName() { return $this->mName; }
+ function getRestriction() { return $this->mRestriction; }
+ function isListed() { return $this->mListed; }
+
+ function userCanExecute( &$user ) {
+ if ( $this->mRestriction == "" ) {
+ return true;
+ } else {
+ if ( in_array( $this->mRestriction, $user->getRights() ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ function displayRestrictionError() {
+ if ( $this->mRestriction == "developer" ) {
+ $wgOut->developerRequired();
+ } else {
+ $wgOut->sysopRequired();
+ }
+ }
+
+ function setHeaders() {
+ global $wgOut;
+ $wgOut->setArticleRelated( false );
+ $wgOut->setRobotPolicy( "noindex,follow" );
+ $wgOut->setPageTitle( $this->getDescription() );
+ }
+
+ function execute( $par ) {
+ global $wgUser, $wgOut, $wgTitle;
+
+ $this->setHeaders();
+
+ if ( $this->userCanExecute( $wgUser ) ) {
+ if ( $this->mFile ) {
+ require_once( $this->mFile );
+ }
+ $func = $this->mFunction;
+ $func( $par );
+ } else {
+ $this->displayRestrictionError();
+ }
+ }
+
+ function getDescription() {
+ return wfMsg( strtolower( $this->mName ) );
+ }
+
+ function getTitle() {
+ return Title::makeTitle( NS_SPECIAL, $this->mName );
+ }
+
+ function setListed( $listed ) {
+ return wfSetVar( $this->mListed, $listed );
+ }
+}
+
+class UnlistedSpecialPage extends SpecialPage
+{
+ function UnlistedSpecialPage( $name, $restriction = "", $function = false, $file = "default" ) {
+ SpecialPage::SpecialPage( $name, $restriction, false, $function, $file );
+ }
+}
function wfSpecialSpecialpages()
{
- global $wgLang, $wgOut, $wgUser;
+ global $wgLang, $wgOut, $wgUser, $wgSpecialPages;
- # sub function generating the list of pages
- # $SP : the list of pages
- # $heading : header to be used
- # $sk : skin object ???
-
- function wfSpecialSpecialpages_gen($SP,$heading,$sk)
- {
- global $wgLang, $wgOut, $wgAllowSysopQueries;
-
- $wgOut->addHTML( "<h2>" . wfMsg( $heading ) . "</h2>\n<ul>" );
- foreach ( $SP as $name => $desc ) {
- if( "" == $desc ) {
- continue;
- }
- if( "Asksql" == $name && !$wgAllowSysopQueries ) {
- continue;
- }
- $link = $sk->makeKnownLink( $wgLang->specialPage( $name ), $desc );
- $wgOut->addHTML( "<li>{$link}</li>\n" );
- }
- $wgOut->addHTML( "</ul>\n" );
- }
-
$wgOut->setRobotpolicy( "index,nofollow" );
$sk = $wgUser->getSkin();
+ # Categorise special pages
+
+ $pages = array(
+ "" => array(),
+ "sysop" => array(),
+ "developer" => array()
+ );
+
+ foreach ( $wgSpecialPages as $page ) {
+ $pages[$page->getRestriction()][$page->getName()] = $page;
+ }
+
+
# all users special pages
- wfSpecialSpecialpages_gen($wgLang->getValidSpecialPages(),"spheading",$sk);
+ wfSpecialSpecialpages_gen($pages[""],"spheading",$sk);
# sysops only special pages
if ( $wgUser->isSysop() ) {
- wfSpecialSpecialpages_gen($wgLang->getSysopSpecialPages(),"sysopspheading",$sk);
+ wfSpecialSpecialpages_gen($pages["sysop"],"sysopspheading",$sk);
}
# developers only special pages
if ( $wgUser->isDeveloper() ) {
- wfSpecialSpecialpages_gen($wgLang->getDeveloperSpecialPages(),"developerspheading",$sk);
+ wfSpecialSpecialpages_gen($pages["developer"],"developerspheading",$sk);
+
+ }
+}
+# sub function generating the list of pages
+# $pages : the list of pages
+# $heading : header to be used
+# $sk : skin object ???
+
+function wfSpecialSpecialpages_gen($pages,$heading,$sk)
+{
+ global $wgLang, $wgOut, $wgAllowSysopQueries;
+
+ $wgOut->addHTML( "<h2>" . wfMsg( $heading ) . "</h2>\n<ul>" );
+ foreach ( $pages as $name => $page ) {
+ if( !$page->isListed() ) {
+ continue;
+ }
+ $link = $sk->makeKnownLinkObj( $page->getTitle(), $page->getDescription() );
+ $wgOut->addHTML( "<li>{$link}</li>\n" );
}
+ $wgOut->addHTML( "</ul>\n" );
}
?>
/* redirect to canonical url, make it a 301 to allow caching */
$wgOut->redirect( $wgTitle->getFullURL(), '301');
} else if ( Namespace::getSpecial() == $wgTitle->getNamespace() ) {
- wfSpecialPage();
+ SpecialPage::executePath( $wgTitle );
} else {
if ( Namespace::getMedia() == $wgTitle->getNamespace() ) {
$wgTitle = Title::makeTitle( Namespace::getImage(), $wgTitle->getDBkey() );
MAG_SERVER => array( 0, "SERVER" )
);
-# All special pages have to be listed here: a description of ""
-# will make them not show up on the "Special Pages" page, which
-# is the right thing for some of them (such as the "targeted" ones).
-#
-/* private */ $wgValidSpecialPagesEn = array(
- "Userlogin" => "",
- "Userlogout" => "",
- "Preferences" => "Set my user preferences",
- "Watchlist" => "My watchlist",
- "Recentchanges" => "Recently updated pages",
- "Upload" => "Upload image files",
- "Imagelist" => "Image list",
- "Listusers" => "Registered users",
- "Statistics" => "Site statistics",
- "Randompage" => "Random article",
-
- "Lonelypages" => "Orphaned articles",
- "Unusedimages" => "Orphaned images",
- "Popularpages" => "Popular articles",
- "Wantedpages" => "Most wanted articles",
- "Shortpages" => "Short articles",
- "Longpages" => "Long articles",
- "Newpages" => "Newly created articles",
- "Ancientpages" => "Oldest articles",
- "Deadendpages" => "Dead-end pages",
-# "Intl" => "Interlanguage Links",
- "Allpages" => "All pages by title",
-
- "Ipblocklist" => "Blocked users/IP addresses",
- "Maintenance" => "Maintenance page",
- "Specialpages" => "",
- "Contributions" => "",
- "Emailuser" => "",
- "Whatlinkshere" => "",
- "Recentchangeslinked" => "",
- "Movepage" => "",
- "Blockme" => "",
- "Booksources" => "External book sources",
- "Categories" => "Page categories",
- "Export" => "XML page export",
- "Version" => "Show MediaWiki version",
- "Allmessages" => "All system messages",
- "Search" => ""
-# "Boardvote" => "Wikimedia Foundation Board of Trustees election"
-);
-
-/* private */ $wgSysopSpecialPagesEn = array(
- "Blockip" => "Block a user/IP address",
- "Asksql" => "Query the database",
- "Undelete" => "Restore deleted pages",
- "Makesysop" => "Turn a user into a sysop",
- "Import" => "Import a page with history",
-);
-
-/* private */ $wgDeveloperSpecialPagesEn = array(
- "Lockdb" => "Make database read-only",
- "Unlockdb" => "Restore DB write access"
-);
-
#-------------------------------------------------------------------
# Default messages
#-------------------------------------------------------------------
"lastmodifiedby" => "This page was last modified $1 by $2.",
"and" => "and",
"othercontribs" => "Based on work by $1.",
-"siteusers" => "$wgSitename user(s) $1",
-
-# Board vote
-"boardvote" => "Wikimedia Board of Trustees election",
-"boardvote_entry" =>
-"* [[Special:Boardvote/vote|Vote]]
-* [[Special:Boardvote/list|List votes to date]]
-* [[Special:Boardvote/dump|Dump encrypted election record]]",
-"boardvote_intro" => "<p>Please choose your preferred candidate for both the
-Contributing Representative and the Volunteer Representative.</p>",
-"boardvote_intro_change" => "<p>You have voted before. However you may change
-your vote using the form below.</p>",
-"boardvote_abstain" => "Abstain",
-"boardvote_footer" => " ",
-"boardvote_entered" => "Thank you, your vote has been recorded.
-
-Following is your encrypted vote record. It will appear publicly at [[Special:Boardvote/dump]].
-
-<pre>$1</pre>
-
-[[Special:Boardvote/entry|Back]]",
-"boardvote_notloggedin" => "You are not logged in. To vote, you must use an account
-which has existed for at least 90 days.",
-"boardvote_notqualified" => "Sorry, your first contribution was only $1 days ago.
-You need to have been contributing for at least 90 days to vote in this election.",
-"boardvote_novotes" => "Nobody has voted yet.",
-"boardvote_contributing" => "Contributing candidate",
-"boardvote_volunteer" => "Volunteer candidate",
-"boardvote_time" => "Time",
-"boardvote_user" => "User",
-"boardvote_listintro" => "<p>This is a list of all votes which have been recorded
-to date. $1 for the full encrypted election record.</p>",
-"boardvote_dumplink" => "Click here",
-"boardvote_dumpheader" => "<caption><strong>Election administrator private dump</strong></caption>
-<tr><th>Time</th><th>User</th><th>Edits</th><th>Days</th>
-<th>IP</th><th>User agent</th><th>Record</th></tr>"
+"siteusers" => "$wgSitename user(s) $1"
+
);
#--------------------------------------------------------------------------
log_xff varchar(255) not null default '',
log_ua varchar(255) not null default '',
log_timestamp char(14) not null default '',
- unique key log_id (log_id)
-);
-
-CREATE TABLE vote (
- vote_key varchar(255) not null default '',
- vote_record blob not null default '',
- vote_contributing text not null default '',
- vote_volunteer text not null default '',
- unique key vote_key (vote_key)
+ log_current tinyint(1) not null default 0,
+ unique index log_id (log_id),
+ index log_user_key (log_user_key)
);