SamanthaNguyen has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/363761 )
Change subject: Reorganize directory structure + file renaming ...................................................................... Reorganize directory structure + file renaming Also split MiniAjaxUpload.php into: - includes/specials/SpecialPollAjaxUpload.php - includes/upload/PollAjaxUploadForm.class.php - includes/upload/PollUpload.class.php Bug: T160849 Change-Id: I86f0d0bef425f819b5d5ae6f591703cca2433f02 --- D MiniAjaxUpload.php M extension.json R includes/Poll.class.php R includes/PollNY.alias.php R includes/PollNY.hooks.php R includes/PollNY.namespaces.php R includes/PollPage.class.php R includes/api/ApiPollNY.php R includes/specials/SpecialAdminPoll.php R includes/specials/SpecialCreatePoll.php A includes/specials/SpecialPollAjaxUpload.php R includes/specials/SpecialRandomPoll.php R includes/specials/SpecialUpdatePoll.php R includes/specials/SpecialViewPoll.php R includes/templates/CreatePoll.template.php A includes/upload/PollAjaxUploadForm.class.php A includes/upload/PollUpload.class.php R resources/css/Poll.css R resources/js/Poll.js R sql/poll.sql 20 files changed, 584 insertions(+), 584 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/PollNY refs/changes/61/363761/1 diff --git a/MiniAjaxUpload.php b/MiniAjaxUpload.php deleted file mode 100644 index 53d5661..0000000 --- a/MiniAjaxUpload.php +++ /dev/null @@ -1,566 +0,0 @@ -<?php -/** - * New version of that fucking AJAX upload form. - * Originally written as 1.16-compatible; this one's built against and tested - * with MW 1.21.1. - * - * wpThumbWidth is the width of the thumbnail that will be returned - * Also, to prevent overwriting uploads of files with popular names i.e. - * Image.jpg all the uploaded files are prepended with the current timestamp. - * - * @file - * @ingroup SpecialPage - * @ingroup Upload - * @author Jack Phoenix <j...@countervandalism.net> - * @date 21 July 2013 - * @note Based on 1.16 core SpecialUpload.php (GPL-licensed) by Bryan et al. - * @see http://bugzilla.shoutwiki.com/show_bug.cgi?id=22 - */ -class SpecialPollAjaxUpload extends SpecialUpload { - /** - * Constructor: initialise object - * Get data POSTed through the form and assign them to the object - * - * @param $request WebRequest: Data posted. - */ - public function __construct() { - SpecialPage::__construct( 'PollAjaxUpload', 'upload', false ); - } - - /** - * apparently you don't need to (re)declare the protected/public class - * member variables here, so I removed them. - */ - - /** - * Initialize instance variables from request and create an Upload handler - * - * What was changed here: $this->mIgnoreWarning is now unconditionally true - * and mUpload uses PollUpload instead of UploadBase - * - * @param $request WebRequest: The request to extract variables from - */ - protected function loadRequest() { - $this->mRequest = $request = $this->getRequest(); - $this->mSourceType = $request->getVal( 'wpSourceType', 'file' ); - $this->mUpload = PollUpload::createFromRequest( $request ); - $this->mUploadClicked = $request->wasPosted() - && ( $request->getCheck( 'wpUpload' ) - || $request->getCheck( 'wpUploadIgnoreWarning' ) ); - - // Guess the desired name from the filename if not provided - $this->mDesiredDestName = $request->getText( 'wpDestFile' ); - if( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) { - $this->mDesiredDestName = $request->getFileName( 'wpUploadFile' ); - } - $this->mComment = $request->getText( 'wpUploadDescription' ); - $this->mLicense = $request->getText( 'wpLicense' ); - - $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' ); - $this->mIgnoreWarning = true;//$request->getCheck( 'wpIgnoreWarning' ) || $request->getCheck( 'wpUploadIgnoreWarning' ); - $this->mWatchthis = $request->getBool( 'wpWatchthis' ) && $this->getUser()->isLoggedIn(); - $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' ); - $this->mCopyrightSource = $request->getText( 'wpUploadSource' ); - - $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file - $this->mCancelUpload = $request->getCheck( 'wpCancelUpload' ) - || $request->getCheck( 'wpReUpload' ); // b/w compat - - // If it was posted check for the token (no remote POST'ing with user credentials) - $token = $request->getVal( 'wpEditToken' ); - if( $this->mSourceType == 'file' && $token == null ) { - // Skip token check for file uploads as that can't be faked via JS... - // Some client-side tools don't expect to need to send wpEditToken - // with their submissions, as that's new in 1.16. - $this->mTokenOk = true; - } else { - $this->mTokenOk = $this->getUser()->matchEditToken( $token ); - } - } - - /** - * Special page entry point - * - * What was changed here: the setArticleBodyOnly() line below was added, - * and some bits of code were entirely removed. - */ - public function execute( $par ) { - // Disable the skin etc. - $this->getOutput()->setArticleBodyOnly( true ); - - // Allow framing so that after uploading an image, we can actually show - // it to the user :) - $this->getOutput()->allowClickjacking(); - - # Check that uploading is enabled - if( !UploadBase::isEnabled() ) { - throw new ErrorPageError( 'uploaddisabled', 'uploaddisabledtext' ); - } - - # Check permissions - $user = $this->getUser(); - $permissionRequired = UploadBase::isAllowed( $user ); - if( $permissionRequired !== true ) { - throw new PermissionsError( $permissionRequired ); - } - - # Check blocks - if( $user->isBlocked() ) { - throw new UserBlockedError( $user->getBlock() ); - } - - # Check whether we actually want to allow changing stuff - $this->checkReadOnly(); - - $this->loadRequest(); - - # Unsave the temporary file in case this was a cancelled upload - if ( $this->mCancelUpload ) { - if ( !$this->unsaveUploadedFile() ) { - # Something went wrong, so unsaveUploadedFile showed a warning - return; - } - } - - # Process upload or show a form - if ( $this->mTokenOk && !$this->mCancelUpload && ( $this->mUpload && $this->mUploadClicked ) ) { - $this->processUpload(); - } else { - $this->showUploadForm( $this->getUploadForm() ); - } - - # Cleanup - if ( $this->mUpload ) { - $this->mUpload->cleanupTempFile(); - } - } - - /** - * Get a PollAjaxUploadForm instance with title and text properly set. - * - * @param $message String: HTML string to add to the form - * @param $sessionKey String: session key in case this is a stashed upload - * @return PollAjaxUploadForm - */ - protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) { - # Initialize form - $form = new PollAjaxUploadForm( array( - 'watch' => $this->getWatchCheck(), - 'forreupload' => $this->mForReUpload, - 'sessionkey' => $sessionKey, - 'hideignorewarning' => $hideIgnoreWarning, - 'destwarningack' => (bool)$this->mDestWarningAck, - 'destfile' => $this->mDesiredDestName, - ) ); - $form->setTitle( $this->getPageTitle() ); - - # Check the token, but only if necessary - if( !$this->mTokenOk && !$this->mCancelUpload - && ( $this->mUpload && $this->mUploadClicked ) ) { - $form->addPreText( $this->msg( 'session_fail_preview' )->parse() ); - } - - # Add upload error message - $form->addPreText( $message ); - - return $form; - } - - /** - * Stashes the upload and shows the main upload form. - * - * Note: only errors that can be handled by changing the name or - * description should be redirected here. It should be assumed that the - * file itself is sane and has passed UploadBase::verifyFile. This - * essentially means that UploadBase::VERIFICATION_ERROR and - * UploadBase::EMPTY_FILE should not be passed here. - * - * @param $message String: HTML message to be passed to mainUploadForm - */ - protected function showRecoverableUploadError( $message ) { - $sessionKey = $this->mUpload->stashSession(); - $message = '<h2>' . $this->msg( 'uploaderror' )->escaped() . "</h2>\n" . - '<div class="error">' . $message . "</div>\n"; - - $form = $this->getUploadForm( $message, $sessionKey ); - $form->setSubmitText( $this->msg( 'upload-tryagain' )->escaped() ); - $this->showUploadForm( $form ); - } - - /** - * Show the upload form with error message, but do not stash the file. - * - * @param $message String: error message to show - */ - protected function showUploadError( $message ) { - $message = addslashes( $message ); - $message = str_replace( array( "\r\n", "\r", "\n" ), ' ', $message ); - $output = "<script language=\"javascript\"> - /*<![CDATA[*/ - window.parent.PollNY.uploadError( '{$message}' ); - /*]]>*/</script>"; - $this->showUploadForm( $this->getUploadForm( $output ) ); - } - - /** - * Do the upload. - * Checks are made in SpecialPollAjaxUpload::execute() - * - * What was changed here: one hook and the post-upload redirect were - * removed in favor of the code below the $this->mUploadSuccessful = true; - * line - */ - protected function processUpload() { - // Fetch the file if required - $status = $this->mUpload->fetchFile(); - if( !$status->isOK() ) { - $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) ); - return; - } - - // Upload verification - $details = $this->mUpload->verifyUpload(); - if ( $details['status'] != UploadBase::OK ) { - $this->processVerificationError( $details ); - return; - } - - // Verify permissions for this title - $permErrors = $this->mUpload->verifyTitlePermissions( $this->getUser() ); - if( $permErrors !== true ) { - $code = array_shift( $permErrors[0] ); - $this->showRecoverableUploadError( $this->msg( $code, $permErrors[0] )->parse() ); - return; - } - - $this->mLocalFile = $this->mUpload->getLocalFile(); - - // Check warnings if necessary - if( !$this->mIgnoreWarning ) { - $warnings = $this->mUpload->checkWarnings(); - if( $this->showUploadWarning( $warnings ) ) { - return; - } - } - - // Get the page text if this is not a reupload - if( !$this->mForReUpload ) { - $pageText = self::getInitialPageText( - $this->mComment, $this->mLicense, - $this->mCopyrightStatus, $this->mCopyrightSource ); - } else { - $pageText = false; - } - - $status = $this->mUpload->performUpload( - $this->mComment, $pageText, $this->mWatchthis, $this->getUser() - ); - - if ( !$status->isGood() ) { - $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) ); - return; - } - - // Success, redirect to description page - $this->mUploadSuccessful = true; - - $this->getOutput()->setArticleBodyOnly( true ); - $this->getOutput()->clearHTML(); - - $thumbWidth = $this->getRequest()->getInt( 'wpThumbWidth', 75 ); - - // The old version below, which initially used $this->mDesiredDestName - // instead of that getTitle() caused plenty o' fatals...the new version - // seems to be OK...I think. - //$img = wfFindFile( $this->mUpload->getTitle() ); - $img = $this->mLocalFile; - - if ( !$img ) { - // This should NOT be happening...the transform() call below - // will cause a fatal error if $img is not an object - error_log( - 'PollNY/MiniAjaxUpload FATAL! $this->mUpload is: ' . - print_r( $this->mUpload, true ) - ); - } - - $thumb = $img->transform( array( 'width' => $thumbWidth ) ); - $img_tag = $thumb->toHtml(); - $slashedImgTag = addslashes( $img_tag ); - - // $this->mDesiredDestName doesn't include the timestamp so we can't - // use it as the second param to the JS function... - // To explain this fucked up logic: here we pass the image name to the - // uploadComplete JS function (see Poll.js), and that function sets - // the value of the hidden <input> with the ID and name - // "poll_image_name" to the image's name. - // Somewhere something uses WebRequest to get the value of - // poll_image_name and inserts that into the database. - // If we don't pass the correct (timestamped) image name here, we - // <s>will end</s> used to end up with fatals that are pretty damn - // tricky to fix. - // This is no longer true since I've added the is_object() checks to - // all social extensions (IIRC) that call wfFindFile somewhere. - $imgName = $img->getTitle()->getDBkey(); - echo "<script language=\"javascript\"> - /*<![CDATA[*/ - window.parent.PollNY.uploadComplete(\"{$slashedImgTag}\", \"{$imgName}\", ''); - /*]]>*/</script>"; - } -} - -class PollAjaxUploadForm extends UploadForm { - protected $mWatch; - protected $mForReUpload; - protected $mSessionKey; - protected $mHideIgnoreWarning; - protected $mDestWarningAck; - protected $mDestFile; - - protected $mSourceIds; - - public function __construct( $options = array() ) { - $this->mWatch = !empty( $options['watch'] ); - $this->mForReUpload = !empty( $options['forreupload'] ); - $this->mSessionKey = isset( $options['sessionkey'] ) - ? $options['sessionkey'] : ''; - $this->mHideIgnoreWarning = !empty( $options['hideignorewarning'] ); - $this->mDestWarningAck = !empty( $options['destwarningack'] ); - - $this->mDestFile = isset( $options['destfile'] ) ? $options['destfile'] : ''; - - $sourceDescriptor = $this->getSourceSection(); - $descriptor = $sourceDescriptor - + $this->getDescriptionSection() - + $this->getOptionsSection(); - - HTMLForm::__construct( $descriptor, 'upload' ); - - # Set some form properties - $this->setSubmitText( $this->msg( 'uploadbtn' )->text() ); - $this->setSubmitName( 'wpUpload' ); - $this->setSubmitTooltip( 'upload' ); - $this->setId( 'mw-upload-form' ); - - # Build a list of IDs for JavaScript insertion - $this->mSourceIds = array(); - foreach ( $sourceDescriptor as $key => $field ) { - if ( !empty( $field['id'] ) ) { - $this->mSourceIds[] = $field['id']; - } - } - } - - function displayForm( $submitResult ) { - parent::displayForm( $submitResult ); - if ( method_exists( $this->getOutput(), 'allowClickjacking' ) ) { - $this->getOutput()->allowClickjacking(); - } - } - - /** - * Wrap the form innards in an actual <form> element - * This is here because HTMLForm's default wrapForm() is so stupid that it - * doesn't let us add the onsubmit attribute...oh yeah, and because using - * $wgOut->addInlineScript in that addUploadJS() function doesn't work, - * either - * - * @param $html String: HTML contents to wrap. - * @return String: wrapped HTML. - */ - function wrapForm( $html ) { - # Include a <fieldset> wrapper for style, if requested. - if ( $this->mWrapperLegend !== false ) { - $html = Xml::fieldset( $this->mWrapperLegend, $html ); - } - # Use multipart/form-data - $encType = $this->mUseMultipart - ? 'multipart/form-data' - : 'application/x-www-form-urlencoded'; - # Attributes - $attribs = array( - 'action' => $this->getTitle()->getFullURL(), - 'method' => 'post', - 'class' => 'visualClear', - 'enctype' => $encType, - 'onsubmit' => 'submitForm()', // added - 'id' => 'upload', // added - 'name' => 'upload' // added - ); - - // fucking newlines... - return "<script type=\"text/javascript\"> - function submitForm() { - var valueToCheck = document.getElementById( 'wpUploadFile' ).value;//document.upload.wpUploadFile.value; - if( valueToCheck != '' ) { - //valueToCheck = '" . time() . "-' + valueToCheck; - window.parent.PollNY.completeImageUpload(); - return true; - } else { - // textError method is gone and I can't find it anywhere... - alert( '" . str_replace( array( "\r\n", "\r", "\n" ), ' ', wfMessage( 'emptyfile' )->plain() ) . "' ); - //window.parent.PollNY.textError( '" . str_replace( "\n", ' ', wfMessage( 'emptyfile' )->plain() ) . "' ); - return false; - } - } -</script>\n" . Html::rawElement( 'form', $attribs, $html ); - } - - /** - * Get the descriptor of the fieldset that contains the file source - * selection. The section is 'source' - * - * @return array Descriptor array - */ - protected function getSourceSection() { - if ( $this->mSessionKey ) { - return array( - 'wpSessionKey' => array( - 'type' => 'hidden', - 'default' => $this->mSessionKey, - ), - 'wpSourceType' => array( - 'type' => 'hidden', - 'default' => 'Stash', - ), - ); - } - - $canUploadByUrl = UploadFromUrl::isEnabled() && $this->getUser()->isAllowed( 'upload_by_url' ); - $radio = $canUploadByUrl; - $selectedSourceType = strtolower( $this->getRequest()->getText( 'wpSourceType', 'File' ) ); - - $descriptor = array(); - $descriptor['UploadFile'] = array( - 'class' => 'UploadSourceField', - 'section' => 'source', - 'type' => 'file', - 'id' => 'wpUploadFile', - 'label-message' => 'sourcefilename', - 'upload-type' => 'File', - 'radio' => &$radio, - // help removed, we don't need any tl,dr on this mini-upload form - 'checked' => $selectedSourceType == 'file', - ); - if ( $canUploadByUrl ) { - $descriptor['UploadFileURL'] = array( - 'class' => 'UploadSourceField', - 'section' => 'source', - 'id' => 'wpUploadFileURL', - 'label-message' => 'sourceurl', - 'upload-type' => 'url', - 'radio' => &$radio, - 'checked' => $selectedSourceType == 'url', - ); - } - - return $descriptor; - } - - /** - * Get the descriptor of the fieldset that contains the file description - * input. The section is 'description' - * - * @return array Descriptor array - */ - protected function getDescriptionSection() { - $descriptor = array( - 'DestFile' => array( - 'type' => 'hidden', - 'id' => 'wpDestFile', - 'size' => 60, - 'default' => $this->mDestFile, - # FIXME: hack to work around poor handling of the 'default' option in HTMLForm - 'nodata' => strval( $this->mDestFile ) !== '', - 'readonly' => true // users do not need to change the file name; normally this is true only when reuploading - ) - ); - - global $wgUseCopyrightUpload; - if ( $wgUseCopyrightUpload ) { - $descriptor['UploadCopyStatus'] = array( - 'type' => 'text', - 'section' => 'description', - 'id' => 'wpUploadCopyStatus', - 'label-message' => 'filestatus', - ); - $descriptor['UploadSource'] = array( - 'type' => 'text', - 'section' => 'description', - 'id' => 'wpUploadSource', - 'label-message' => 'filesource', - ); - } - - return $descriptor; - } - - /** - * Get the descriptor of the fieldset that contains the upload options, - * such as "watch this file". The section is 'options' - * - * @return array Descriptor array - */ - protected function getOptionsSection() { - $descriptor = array(); - - $descriptor['wpDestFileWarningAck'] = array( - 'type' => 'hidden', - 'id' => 'wpDestFileWarningAck', - 'default' => $this->mDestWarningAck ? '1' : '', - ); - - if ( $this->mForReUpload ) { - $descriptor['wpForReUpload'] = array( - 'type' => 'hidden', - 'id' => 'wpForReUpload', - 'default' => '1', - ); - } - - return $descriptor; - } - - /** - * Add the upload JS and show the form. - */ - public function show() { - HTMLForm::show(); - } - - /** - * Empty function; submission is handled elsewhere. - * - * @return bool false - */ - function trySubmit() { - return false; - } -} - -/** - * Quick helper class for SpecialPollAjaxUpload::loadRequest; this prefixes the - * filename with the timestamp. Yes, another class is needed for it. *sigh* - */ -class PollUpload extends UploadFromFile { - /** - * Create a form of UploadBase depending on wpSourceType and initializes it - */ - public static function createFromRequest( &$request, $type = null ) { - $handler = new self; - $handler->initializeFromRequest( $request ); - return $handler; - } - - function initializeFromRequest( &$request ) { - $upload = $request->getUpload( 'wpUploadFile' ); - - $desiredDestName = $request->getText( 'wpDestFile' ); - if ( !$desiredDestName ) { - $desiredDestName = $upload->getName(); - } - $desiredDestName = time() . '-' . $desiredDestName; - - $this->initialize( $desiredDestName, $upload ); - } -} \ No newline at end of file diff --git a/extension.json b/extension.json index cd116a0..ce8df8c 100644 --- a/extension.json +++ b/extension.json @@ -1,6 +1,6 @@ { "name": "PollNY", - "version": "3.3.6", + "version": "3.4.0", "author": [ "Aaron Wright", "David Pean", @@ -45,22 +45,22 @@ "pollny": "ApiPollNY" }, "ExtensionMessagesFiles": { - "PollNYAlias": "Poll.alias.php", - "PollNYNamespaces": "Poll.namespaces.php" + "PollNYAlias": "includes/PollNY.alias.php", + "PollNYNamespaces": "includes/PollNY.namespaces.php" }, "AutoloadClasses": { - "ApiPollNY": "ApiPollNY.php", - "AdminPoll": "SpecialAdminPoll.php", - "CreatePoll": "SpecialCreatePoll.php", - "Poll": "PollClass.php", - "PollAjaxUploadForm": "MiniAjaxUpload.php", - "PollNYHooks": "PollNYHooks.php", - "PollPage": "PollPage.php", - "PollUpload": "MiniAjaxUpload.php", - "RandomPoll": "SpecialRandomPoll.php", - "SpecialPollAjaxUpload": "MiniAjaxUpload.php", - "UpdatePoll": "SpecialUpdatePoll.php", - "ViewPoll": "SpecialViewPoll.php" + "ApiPollNY": "includes/api/ApiPollNY.php", + "AdminPoll": "includes/specials/SpecialAdminPoll.php", + "CreatePoll": "includes/specials/SpecialCreatePoll.php", + "Poll": "includes/Poll.class.php", + "PollAjaxUploadForm": "includes/upload/PollAjaxUploadForm.php", + "PollNYHooks": "includes/PollNY.hooks.php", + "PollPage": "includes/PollPage.class.php", + "PollUpload": "includes/upload/PollUpload.class.php", + "RandomPoll": "includes/specials/SpecialRandomPoll.php", + "SpecialPollAjaxUpload": "includes/specials/SpecialPollAjaxUpload.php", + "UpdatePoll": "includes/specials/SpecialUpdatePoll.php", + "ViewPoll": "includes/specials/SpecialViewPoll.php" }, "Hooks": { "TitleMoveComplete": [ @@ -92,7 +92,7 @@ }, "ResourceModules": { "ext.pollNY": { - "scripts": "Poll.js", + "scripts": "resources/js/Poll.js", "messages": [ "poll-open-message", "poll-close-message", "poll-flagged-message", "poll-finished", @@ -109,7 +109,7 @@ "position": "bottom" }, "ext.pollNY.css": { - "styles": "Poll.css", + "styles": "resources/css/Poll.css", "position": "top" } }, diff --git a/PollClass.php b/includes/Poll.class.php similarity index 100% rename from PollClass.php rename to includes/Poll.class.php diff --git a/Poll.alias.php b/includes/PollNY.alias.php similarity index 100% rename from Poll.alias.php rename to includes/PollNY.alias.php diff --git a/PollNYHooks.php b/includes/PollNY.hooks.php similarity index 98% rename from PollNYHooks.php rename to includes/PollNY.hooks.php index fe5c69a..8430aa1 100644 --- a/PollNYHooks.php +++ b/includes/PollNY.hooks.php @@ -310,7 +310,7 @@ */ public static function addTables( $updater ) { $dir = dirname( __FILE__ ); - $file = "$dir/poll.sql"; + $file = "$dir/../sql/poll.sql"; $updater->addExtensionUpdate( array( 'addTable', 'poll_choice', $file, true ) ); $updater->addExtensionUpdate( array( 'addTable', 'poll_question', $file, true ) ); diff --git a/Poll.namespaces.php b/includes/PollNY.namespaces.php similarity index 100% rename from Poll.namespaces.php rename to includes/PollNY.namespaces.php diff --git a/PollPage.php b/includes/PollPage.class.php similarity index 100% rename from PollPage.php rename to includes/PollPage.class.php diff --git a/ApiPollNY.php b/includes/api/ApiPollNY.php similarity index 100% rename from ApiPollNY.php rename to includes/api/ApiPollNY.php diff --git a/SpecialAdminPoll.php b/includes/specials/SpecialAdminPoll.php similarity index 100% rename from SpecialAdminPoll.php rename to includes/specials/SpecialAdminPoll.php diff --git a/SpecialCreatePoll.php b/includes/specials/SpecialCreatePoll.php similarity index 100% rename from SpecialCreatePoll.php rename to includes/specials/SpecialCreatePoll.php diff --git a/includes/specials/SpecialPollAjaxUpload.php b/includes/specials/SpecialPollAjaxUpload.php new file mode 100644 index 0000000..bab33a6 --- /dev/null +++ b/includes/specials/SpecialPollAjaxUpload.php @@ -0,0 +1,310 @@ +<?php +/** + * New version of that fucking AJAX upload form. + * Originally written as 1.16-compatible; this one's built against and tested + * with MW 1.21.1. + * + * wpThumbWidth is the width of the thumbnail that will be returned + * Also, to prevent overwriting uploads of files with popular names i.e. + * Image.jpg all the uploaded files are prepended with the current timestamp. + * + * @file + * @ingroup SpecialPage + * @ingroup Upload + * @author Jack Phoenix <j...@countervandalism.net> + * @date 21 July 2013 + * @note Based on 1.16 core SpecialUpload.php (GPL-licensed) by Bryan et al. + * @see http://bugzilla.shoutwiki.com/show_bug.cgi?id=22 + */ +class SpecialPollAjaxUpload extends SpecialUpload { + /** + * Constructor: initialise object + * Get data POSTed through the form and assign them to the object + * + * @param $request WebRequest: Data posted. + */ + public function __construct() { + SpecialPage::__construct( 'PollAjaxUpload', 'upload', false ); + } + + /** + * apparently you don't need to (re)declare the protected/public class + * member variables here, so I removed them. + */ + + /** + * Initialize instance variables from request and create an Upload handler + * + * What was changed here: $this->mIgnoreWarning is now unconditionally true + * and mUpload uses PollUpload instead of UploadBase + * + * @param $request WebRequest: The request to extract variables from + */ + protected function loadRequest() { + $this->mRequest = $request = $this->getRequest(); + $this->mSourceType = $request->getVal( 'wpSourceType', 'file' ); + $this->mUpload = PollUpload::createFromRequest( $request ); + $this->mUploadClicked = $request->wasPosted() + && ( $request->getCheck( 'wpUpload' ) + || $request->getCheck( 'wpUploadIgnoreWarning' ) ); + + // Guess the desired name from the filename if not provided + $this->mDesiredDestName = $request->getText( 'wpDestFile' ); + if( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) { + $this->mDesiredDestName = $request->getFileName( 'wpUploadFile' ); + } + $this->mComment = $request->getText( 'wpUploadDescription' ); + $this->mLicense = $request->getText( 'wpLicense' ); + + $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' ); + $this->mIgnoreWarning = true;//$request->getCheck( 'wpIgnoreWarning' ) || $request->getCheck( 'wpUploadIgnoreWarning' ); + $this->mWatchthis = $request->getBool( 'wpWatchthis' ) && $this->getUser()->isLoggedIn(); + $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' ); + $this->mCopyrightSource = $request->getText( 'wpUploadSource' ); + + $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file + $this->mCancelUpload = $request->getCheck( 'wpCancelUpload' ) + || $request->getCheck( 'wpReUpload' ); // b/w compat + + // If it was posted check for the token (no remote POST'ing with user credentials) + $token = $request->getVal( 'wpEditToken' ); + if( $this->mSourceType == 'file' && $token == null ) { + // Skip token check for file uploads as that can't be faked via JS... + // Some client-side tools don't expect to need to send wpEditToken + // with their submissions, as that's new in 1.16. + $this->mTokenOk = true; + } else { + $this->mTokenOk = $this->getUser()->matchEditToken( $token ); + } + } + + /** + * Special page entry point + * + * What was changed here: the setArticleBodyOnly() line below was added, + * and some bits of code were entirely removed. + */ + public function execute( $par ) { + // Disable the skin etc. + $this->getOutput()->setArticleBodyOnly( true ); + + // Allow framing so that after uploading an image, we can actually show + // it to the user :) + $this->getOutput()->allowClickjacking(); + + # Check that uploading is enabled + if( !UploadBase::isEnabled() ) { + throw new ErrorPageError( 'uploaddisabled', 'uploaddisabledtext' ); + } + + # Check permissions + $user = $this->getUser(); + $permissionRequired = UploadBase::isAllowed( $user ); + if( $permissionRequired !== true ) { + throw new PermissionsError( $permissionRequired ); + } + + # Check blocks + if( $user->isBlocked() ) { + throw new UserBlockedError( $user->getBlock() ); + } + + # Check whether we actually want to allow changing stuff + $this->checkReadOnly(); + + $this->loadRequest(); + + # Unsave the temporary file in case this was a cancelled upload + if ( $this->mCancelUpload ) { + if ( !$this->unsaveUploadedFile() ) { + # Something went wrong, so unsaveUploadedFile showed a warning + return; + } + } + + # Process upload or show a form + if ( $this->mTokenOk && !$this->mCancelUpload && ( $this->mUpload && $this->mUploadClicked ) ) { + $this->processUpload(); + } else { + $this->showUploadForm( $this->getUploadForm() ); + } + + # Cleanup + if ( $this->mUpload ) { + $this->mUpload->cleanupTempFile(); + } + } + + /** + * Get a PollAjaxUploadForm instance with title and text properly set. + * + * @param $message String: HTML string to add to the form + * @param $sessionKey String: session key in case this is a stashed upload + * @return PollAjaxUploadForm + */ + protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) { + # Initialize form + $form = new PollAjaxUploadForm( array( + 'watch' => $this->getWatchCheck(), + 'forreupload' => $this->mForReUpload, + 'sessionkey' => $sessionKey, + 'hideignorewarning' => $hideIgnoreWarning, + 'destwarningack' => (bool)$this->mDestWarningAck, + 'destfile' => $this->mDesiredDestName, + ) ); + $form->setTitle( $this->getPageTitle() ); + + # Check the token, but only if necessary + if( !$this->mTokenOk && !$this->mCancelUpload + && ( $this->mUpload && $this->mUploadClicked ) ) { + $form->addPreText( $this->msg( 'session_fail_preview' )->parse() ); + } + + # Add upload error message + $form->addPreText( $message ); + + return $form; + } + + /** + * Stashes the upload and shows the main upload form. + * + * Note: only errors that can be handled by changing the name or + * description should be redirected here. It should be assumed that the + * file itself is sane and has passed UploadBase::verifyFile. This + * essentially means that UploadBase::VERIFICATION_ERROR and + * UploadBase::EMPTY_FILE should not be passed here. + * + * @param $message String: HTML message to be passed to mainUploadForm + */ + protected function showRecoverableUploadError( $message ) { + $sessionKey = $this->mUpload->stashSession(); + $message = '<h2>' . $this->msg( 'uploaderror' )->escaped() . "</h2>\n" . + '<div class="error">' . $message . "</div>\n"; + + $form = $this->getUploadForm( $message, $sessionKey ); + $form->setSubmitText( $this->msg( 'upload-tryagain' )->escaped() ); + $this->showUploadForm( $form ); + } + + /** + * Show the upload form with error message, but do not stash the file. + * + * @param $message String: error message to show + */ + protected function showUploadError( $message ) { + $message = addslashes( $message ); + $message = str_replace( array( "\r\n", "\r", "\n" ), ' ', $message ); + $output = "<script language=\"javascript\"> + /*<![CDATA[*/ + window.parent.PollNY.uploadError( '{$message}' ); + /*]]>*/</script>"; + $this->showUploadForm( $this->getUploadForm( $output ) ); + } + + /** + * Do the upload. + * Checks are made in SpecialPollAjaxUpload::execute() + * + * What was changed here: one hook and the post-upload redirect were + * removed in favor of the code below the $this->mUploadSuccessful = true; + * line + */ + protected function processUpload() { + // Fetch the file if required + $status = $this->mUpload->fetchFile(); + if( !$status->isOK() ) { + $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) ); + return; + } + + // Upload verification + $details = $this->mUpload->verifyUpload(); + if ( $details['status'] != UploadBase::OK ) { + $this->processVerificationError( $details ); + return; + } + + // Verify permissions for this title + $permErrors = $this->mUpload->verifyTitlePermissions( $this->getUser() ); + if( $permErrors !== true ) { + $code = array_shift( $permErrors[0] ); + $this->showRecoverableUploadError( $this->msg( $code, $permErrors[0] )->parse() ); + return; + } + + $this->mLocalFile = $this->mUpload->getLocalFile(); + + // Check warnings if necessary + if( !$this->mIgnoreWarning ) { + $warnings = $this->mUpload->checkWarnings(); + if( $this->showUploadWarning( $warnings ) ) { + return; + } + } + + // Get the page text if this is not a reupload + if( !$this->mForReUpload ) { + $pageText = self::getInitialPageText( + $this->mComment, $this->mLicense, + $this->mCopyrightStatus, $this->mCopyrightSource ); + } else { + $pageText = false; + } + + $status = $this->mUpload->performUpload( + $this->mComment, $pageText, $this->mWatchthis, $this->getUser() + ); + + if ( !$status->isGood() ) { + $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) ); + return; + } + + // Success, redirect to description page + $this->mUploadSuccessful = true; + + $this->getOutput()->setArticleBodyOnly( true ); + $this->getOutput()->clearHTML(); + + $thumbWidth = $this->getRequest()->getInt( 'wpThumbWidth', 75 ); + + // The old version below, which initially used $this->mDesiredDestName + // instead of that getTitle() caused plenty o' fatals...the new version + // seems to be OK...I think. + //$img = wfFindFile( $this->mUpload->getTitle() ); + $img = $this->mLocalFile; + + if ( !$img ) { + // This should NOT be happening...the transform() call below + // will cause a fatal error if $img is not an object + error_log( + 'PollNY/MiniAjaxUpload FATAL! $this->mUpload is: ' . + print_r( $this->mUpload, true ) + ); + } + + $thumb = $img->transform( array( 'width' => $thumbWidth ) ); + $img_tag = $thumb->toHtml(); + $slashedImgTag = addslashes( $img_tag ); + + // $this->mDesiredDestName doesn't include the timestamp so we can't + // use it as the second param to the JS function... + // To explain this fucked up logic: here we pass the image name to the + // uploadComplete JS function (see Poll.js), and that function sets + // the value of the hidden <input> with the ID and name + // "poll_image_name" to the image's name. + // Somewhere something uses WebRequest to get the value of + // poll_image_name and inserts that into the database. + // If we don't pass the correct (timestamped) image name here, we + // <s>will end</s> used to end up with fatals that are pretty damn + // tricky to fix. + // This is no longer true since I've added the is_object() checks to + // all social extensions (IIRC) that call wfFindFile somewhere. + $imgName = $img->getTitle()->getDBkey(); + echo "<script language=\"javascript\"> + /*<![CDATA[*/ + window.parent.PollNY.uploadComplete(\"{$slashedImgTag}\", \"{$imgName}\", ''); + /*]]>*/</script>"; + } +} diff --git a/SpecialRandomPoll.php b/includes/specials/SpecialRandomPoll.php similarity index 100% rename from SpecialRandomPoll.php rename to includes/specials/SpecialRandomPoll.php diff --git a/SpecialUpdatePoll.php b/includes/specials/SpecialUpdatePoll.php similarity index 100% rename from SpecialUpdatePoll.php rename to includes/specials/SpecialUpdatePoll.php diff --git a/SpecialViewPoll.php b/includes/specials/SpecialViewPoll.php similarity index 100% rename from SpecialViewPoll.php rename to includes/specials/SpecialViewPoll.php diff --git a/create-poll.tmpl.php b/includes/templates/CreatePoll.template.php similarity index 100% rename from create-poll.tmpl.php rename to includes/templates/CreatePoll.template.php diff --git a/includes/upload/PollAjaxUploadForm.class.php b/includes/upload/PollAjaxUploadForm.class.php new file mode 100644 index 0000000..2e6cfbb --- /dev/null +++ b/includes/upload/PollAjaxUploadForm.class.php @@ -0,0 +1,229 @@ +<?php +class PollAjaxUploadForm extends UploadForm { + protected $mWatch; + protected $mForReUpload; + protected $mSessionKey; + protected $mHideIgnoreWarning; + protected $mDestWarningAck; + protected $mDestFile; + + protected $mSourceIds; + + public function __construct( $options = array() ) { + $this->mWatch = !empty( $options['watch'] ); + $this->mForReUpload = !empty( $options['forreupload'] ); + $this->mSessionKey = isset( $options['sessionkey'] ) + ? $options['sessionkey'] : ''; + $this->mHideIgnoreWarning = !empty( $options['hideignorewarning'] ); + $this->mDestWarningAck = !empty( $options['destwarningack'] ); + + $this->mDestFile = isset( $options['destfile'] ) ? $options['destfile'] : ''; + + $sourceDescriptor = $this->getSourceSection(); + $descriptor = $sourceDescriptor + + $this->getDescriptionSection() + + $this->getOptionsSection(); + + HTMLForm::__construct( $descriptor, 'upload' ); + + # Set some form properties + $this->setSubmitText( $this->msg( 'uploadbtn' )->text() ); + $this->setSubmitName( 'wpUpload' ); + $this->setSubmitTooltip( 'upload' ); + $this->setId( 'mw-upload-form' ); + + # Build a list of IDs for JavaScript insertion + $this->mSourceIds = array(); + foreach ( $sourceDescriptor as $key => $field ) { + if ( !empty( $field['id'] ) ) { + $this->mSourceIds[] = $field['id']; + } + } + } + + function displayForm( $submitResult ) { + parent::displayForm( $submitResult ); + if ( method_exists( $this->getOutput(), 'allowClickjacking' ) ) { + $this->getOutput()->allowClickjacking(); + } + } + + /** + * Wrap the form innards in an actual <form> element + * This is here because HTMLForm's default wrapForm() is so stupid that it + * doesn't let us add the onsubmit attribute...oh yeah, and because using + * $wgOut->addInlineScript in that addUploadJS() function doesn't work, + * either + * + * @param $html String: HTML contents to wrap. + * @return String: wrapped HTML. + */ + function wrapForm( $html ) { + # Include a <fieldset> wrapper for style, if requested. + if ( $this->mWrapperLegend !== false ) { + $html = Xml::fieldset( $this->mWrapperLegend, $html ); + } + # Use multipart/form-data + $encType = $this->mUseMultipart + ? 'multipart/form-data' + : 'application/x-www-form-urlencoded'; + # Attributes + $attribs = array( + 'action' => $this->getTitle()->getFullURL(), + 'method' => 'post', + 'class' => 'visualClear', + 'enctype' => $encType, + 'onsubmit' => 'submitForm()', // added + 'id' => 'upload', // added + 'name' => 'upload' // added + ); + + // fucking newlines... + return "<script type=\"text/javascript\"> + function submitForm() { + var valueToCheck = document.getElementById( 'wpUploadFile' ).value;//document.upload.wpUploadFile.value; + if( valueToCheck != '' ) { + //valueToCheck = '" . time() . "-' + valueToCheck; + window.parent.PollNY.completeImageUpload(); + return true; + } else { + // textError method is gone and I can't find it anywhere... + alert( '" . str_replace( array( "\r\n", "\r", "\n" ), ' ', wfMessage( 'emptyfile' )->plain() ) . "' ); + //window.parent.PollNY.textError( '" . str_replace( "\n", ' ', wfMessage( 'emptyfile' )->plain() ) . "' ); + return false; + } + } +</script>\n" . Html::rawElement( 'form', $attribs, $html ); + } + + /** + * Get the descriptor of the fieldset that contains the file source + * selection. The section is 'source' + * + * @return array Descriptor array + */ + protected function getSourceSection() { + if ( $this->mSessionKey ) { + return array( + 'wpSessionKey' => array( + 'type' => 'hidden', + 'default' => $this->mSessionKey, + ), + 'wpSourceType' => array( + 'type' => 'hidden', + 'default' => 'Stash', + ), + ); + } + + $canUploadByUrl = UploadFromUrl::isEnabled() && $this->getUser()->isAllowed( 'upload_by_url' ); + $radio = $canUploadByUrl; + $selectedSourceType = strtolower( $this->getRequest()->getText( 'wpSourceType', 'File' ) ); + + $descriptor = array(); + $descriptor['UploadFile'] = array( + 'class' => 'UploadSourceField', + 'section' => 'source', + 'type' => 'file', + 'id' => 'wpUploadFile', + 'label-message' => 'sourcefilename', + 'upload-type' => 'File', + 'radio' => &$radio, + // help removed, we don't need any tl,dr on this mini-upload form + 'checked' => $selectedSourceType == 'file', + ); + if ( $canUploadByUrl ) { + $descriptor['UploadFileURL'] = array( + 'class' => 'UploadSourceField', + 'section' => 'source', + 'id' => 'wpUploadFileURL', + 'label-message' => 'sourceurl', + 'upload-type' => 'url', + 'radio' => &$radio, + 'checked' => $selectedSourceType == 'url', + ); + } + + return $descriptor; + } + + /** + * Get the descriptor of the fieldset that contains the file description + * input. The section is 'description' + * + * @return array Descriptor array + */ + protected function getDescriptionSection() { + $descriptor = array( + 'DestFile' => array( + 'type' => 'hidden', + 'id' => 'wpDestFile', + 'size' => 60, + 'default' => $this->mDestFile, + # FIXME: hack to work around poor handling of the 'default' option in HTMLForm + 'nodata' => strval( $this->mDestFile ) !== '', + 'readonly' => true // users do not need to change the file name; normally this is true only when reuploading + ) + ); + + global $wgUseCopyrightUpload; + if ( $wgUseCopyrightUpload ) { + $descriptor['UploadCopyStatus'] = array( + 'type' => 'text', + 'section' => 'description', + 'id' => 'wpUploadCopyStatus', + 'label-message' => 'filestatus', + ); + $descriptor['UploadSource'] = array( + 'type' => 'text', + 'section' => 'description', + 'id' => 'wpUploadSource', + 'label-message' => 'filesource', + ); + } + + return $descriptor; + } + + /** + * Get the descriptor of the fieldset that contains the upload options, + * such as "watch this file". The section is 'options' + * + * @return array Descriptor array + */ + protected function getOptionsSection() { + $descriptor = array(); + + $descriptor['wpDestFileWarningAck'] = array( + 'type' => 'hidden', + 'id' => 'wpDestFileWarningAck', + 'default' => $this->mDestWarningAck ? '1' : '', + ); + + if ( $this->mForReUpload ) { + $descriptor['wpForReUpload'] = array( + 'type' => 'hidden', + 'id' => 'wpForReUpload', + 'default' => '1', + ); + } + + return $descriptor; + } + + /** + * Add the upload JS and show the form. + */ + public function show() { + HTMLForm::show(); + } + + /** + * Empty function; submission is handled elsewhere. + * + * @return bool false + */ + function trySubmit() { + return false; + } +} diff --git a/includes/upload/PollUpload.class.php b/includes/upload/PollUpload.class.php new file mode 100644 index 0000000..ca7db29 --- /dev/null +++ b/includes/upload/PollUpload.class.php @@ -0,0 +1,27 @@ +<?php +/** + * Quick helper class for SpecialPollAjaxUpload::loadRequest; this prefixes the + * filename with the timestamp. Yes, another class is needed for it. *sigh* + */ +class PollUpload extends UploadFromFile { + /** + * Create a form of UploadBase depending on wpSourceType and initializes it + */ + public static function createFromRequest( &$request, $type = null ) { + $handler = new self; + $handler->initializeFromRequest( $request ); + return $handler; + } + + function initializeFromRequest( &$request ) { + $upload = $request->getUpload( 'wpUploadFile' ); + + $desiredDestName = $request->getText( 'wpDestFile' ); + if ( !$desiredDestName ) { + $desiredDestName = $upload->getName(); + } + $desiredDestName = time() . '-' . $desiredDestName; + + $this->initialize( $desiredDestName, $upload ); + } +} diff --git a/Poll.css b/resources/css/Poll.css similarity index 100% rename from Poll.css rename to resources/css/Poll.css diff --git a/Poll.js b/resources/js/Poll.js similarity index 100% rename from Poll.js rename to resources/js/Poll.js diff --git a/poll.sql b/sql/poll.sql similarity index 100% rename from poll.sql rename to sql/poll.sql -- To view, visit https://gerrit.wikimedia.org/r/363761 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I86f0d0bef425f819b5d5ae6f591703cca2433f02 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/PollNY Gerrit-Branch: master Gerrit-Owner: SamanthaNguyen <samanthanguyen1...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits