/** * This is called upon loading the special page. It should write output to the page with $wgOut. * @param string $par the URL path following the special page name */ public function execute($par) { global $wgOut, $wgUser; $this->setHeaders(); $parts = explode('/', $par); $productName = isset($parts[0]) ? $parts[0] : PonyDocsProduct::GetSelectedProduct(); $manualName = isset($parts[1]) ? $parts[1] : NULL; // Security Check $authProductGroup = PonyDocsExtension::getDerivedGroup(PonyDocsExtension::ACCESS_GROUP_PRODUCT, $productName); $groups = $wgUser->getGroups(); if (!in_array($authProductGroup, $groups)) { $wgOut->addHTML('<p>Sorry, but you do not have permission to access this Special page.</p>'); return; } $product = PonyDocsProduct::GetProductByShortName($productName); $productLongName = $product->getLongName(); if (!is_null($manualName)) { $manual = PonyDocsProductManual::GetManualByShortName($productName, $manualName); $manualLongName = $manual->getLongName(); } else { $manual = NULL; } $wgOut->setPagetitle('Static Documentation Import Tool'); $h2 = "Static Documentation Import for {$productLongName}"; if (!is_null($manualName)) { $h2 .= ", {$manualLongName}"; } $wgOut->addHTML("<h2>{$h2}</h2>"); if ($this->validateProductAndManualAreStatic($product, $manual)) { if (isset($_POST['action'])) { $this->processImportForm($_POST['action'], $product, $manual); } else { $this->showImportForm($product, $manual); } } $this->showExistingVersions($product, $manual); $this->showHelpfulLinks($productName); }
public static function setSpeedProcessing($enabled) { PonyDocsExtension::$speedProcessingEnabled = $enabled; }
/** * Called when an unknown action occurs on url. We are only interested in zipmanual action. */ function onUnknownAction($action, $article) { global $wgOut, $wgUser, $wgTitle, $wgParser, $wgRequest; global $wgServer, $wgArticlePath, $wgScriptPath, $wgUploadPath, $wgUploadDirectory, $wgScript, $wgStylePath; // We don't do any processing unless it's zipmanual if ($action != 'zipmanual') { return true; } $zipAllowed = false; PonyDocsExtension::onUserCan($wgTitle, $wgUser, 'zipmanual', &$zipAllowed); if (!$zipAllowed) { error_log("WARNING [" . __METHOD__ . "] User attempted to perform a ZIP Export without permission."); $defaultRedirect = PonyDocsExtension::getDefaultUrl(); header("Location: " . $defaultRedirect); exit; } // Get the title and make sure we're in Documentation namespace $title = $article->getTitle(); if ($title->getNamespace() != NS_PONYDOCS) { return true; } // Grab parser options for the logged in user. $opt = ParserOptions::newFromUser($wgUser); // Any potential titles to exclude $exclude = array(); // Determine articles to gather $articles = array(); $pieces = explode(":", $wgTitle->__toString()); // Try and get rid of the TOC portion of the title if (strpos($pieces[2], "TOC") && count($pieces) == 3) { $pieces[2] = substr($pieces[2], 0, strpos($pieces[2], "TOC")); } else { if (count($pieces) != 5) { // something is wrong, let's get out of here $defaultRedirect = PonyDocsExtension::getDefaultUrl(); if (PONYDOCS_DEBUG) { error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}"); } header("Location: " . $defaultRedirect); exit; } } $productName = $pieces[1]; $ponydocs = PonyDocsWiki::getInstance($productName); $pProduct = PonyDocsProduct::GetProductByShortName($productName); if ($pProduct === NULL) { // product wasn't valid wfProfileOut(__METHOD__); $wgOut->setStatusCode(404); return FALSE; } $productLongName = $pProduct->getLongName(); if (PonyDocsProductManual::isManual($productName, $pieces[2])) { $pManual = PonyDocsProductManual::GetManualByShortName($productName, $pieces[2]); } $versionText = PonyDocsProductVersion::GetSelectedVersion($productName); if (!empty($pManual)) { // We should always have a pManual, if we're printing // from a TOC $v = PonyDocsProductVersion::GetVersionByName($productName, $versionText); $toc = new PonyDocsTOC($pManual, $v, $pProduct); list($manualtoc, $tocprev, $tocnext, $tocstart) = $toc->loadContent(); // We successfully got our table of contents. It's // stored in $manualtoc foreach ($manualtoc as $tocEntry) { if ($tocEntry['level'] > 0 && strlen($tocEntry['title']) > 0) { $title = Title::newFromText($tocEntry['title']); $articles[$tocEntry['section']][] = array('title' => $title, 'text' => $tocEntry['text']); } } } else { error_log("WARNING [" . __METHOD__ . "] " . php_uname('n') . ": User attempted to export ZIP from a non TOC page with path:" . $wgTitle->__toString()); } $html = self::getManualHTML($pProduct, $pManual, $v); $coverPageHTML = self::getCoverPageHTML($pProduct, $pManual, $v, false); // Make a temporary directory to store our archive contents. $tempDirPath = sys_get_temp_dir() . '/ponydocs-zip-export-' . time(); $success = @mkdir($tempDirPath); if (!$success) { error_log("FATAL [" . __METHOD__ . "] Failed to create temporary directory " . $tempDirPath . " for Zip Export."); throw new Exception('Failed to create temporary directory for Zip Export.'); } // Now, let's fetch all the img elements for both and grab them all in // parallel. $imgData = array(); // Initialize our RollingCurl instance $rollingCurl = new \RollingCurl\RollingCurl(); $mh = curl_multi_init(); $manualDoc = new DOMDocument(); @$manualDoc->loadHTML($html); $coverPageDoc = new DOMDocument(); @$coverPageDoc->loadHTML($coverPageHTML); self::prepareImageRequests($manualDoc, $rollingCurl, $tempDirPath, &$imgData); self::prepareImageRequests($coverPageDoc, $rollingCurl, $tempDirPath, &$imgData); // Execute the RollingCurl requests $rollingCurl->execute(); // Now update all our image elements in our appropriate DOMDocs. foreach ($imgData as $img) { // Put the data into it. file_put_contents($img['local_path'], $img['request']->getResponseText()); // Modify element $img['element']->setAttribute('src', $img['new_path']); // Do curl cleanup } $html = $manualDoc->saveHTML(); $coverPageHTML = $coverPageDoc->saveHTML(); // Write the HTML to a tmp file $file = tempnam($tempDirPath, "zipexport-"); $fh = fopen($file, 'w+'); fwrite($fh, $html); fclose($fh); // Okay, write the title page $titlepagefile = tempnam($tempDirPath, "zipexport-"); $fh = fopen($titlepagefile, 'w+'); fwrite($fh, $coverPageHTML); fclose($fh); // Disable output of our standard mediawiki output. We will be outputting a zip file instead. $wgOut->disable(); // Create ZIP Archive which contains a cover and manual html $zip = new ZipArchive(); $tempZipFilePath = tempnam($tempDirPath, "zipexport-"); $zipFileName = $productName . '-' . $versionText . '-' . $pManual->getShortName() . '.zip'; $zip->open($tempZipFilePath, ZipArchive::OVERWRITE); $zip->addFile($titlepagefile, 'cover.html'); $zip->addFile($file, 'manual.html'); // Iterate through all the images foreach ($imgData as $img) { $zip->addFile($img['local_path'], $img['new_path']); } $zip->close(); header("Content-Type: application/zip"); header("Content-Length: " . filesize($tempZipFilePath)); header("Content-Disposition: attachment; filename=\"" . $zipFileName . "\""); readfile($tempZipFilePath); // Now remove all temp files self::rrmdir($tempDirPath); // Okay, let's add an entry to the error log to dictate someone requested a pdf error_log("INFO [" . __METHOD__ . "] " . php_uname('n') . ": zip export serve username=\"" . $wgUser->getName() . "\" version=\"{$versionText}\" " . " manual=\"" . $pManual->getShortName() . "\""); // No more processing return false; }
/** * This is called upon loading the special page. It should write output to * the page with $wgOut */ public function execute() { global $wgOut, $wgArticlePath, $wgScriptPath, $wgUser; global $wgRequest; global $wgDBprefix; $currentProduct = ''; $currentVersion = ''; $collapseAll = FALSE; $dbr = wfGetDB(DB_SLAVE); // Set headers and title of the page, get value of "t" from GET/POST $this->setHeaders(); $title = $wgRequest->getVal('t'); if (empty($title)) { $wgOut->setPagetitle("Documentation Linkage"); $wgOut->addHTML('No topic specified.'); return; } $wgOut->setPagetitle("Documentation Linkage For " . $title); // Parse "t" (the title we're looking for inbound links to) // Find titles for all inherited versions, etc. $titlePieces = explode(':', $title); $plainTitle = $title; // Create a new Title from text, such as what one would find in a link. Decodes any HTML entities in the text. $title = Title::newFromText($title); $toUrls = array(); // Do PonyDocs-specific stuff (loop through all inherited versions) if ($titlePieces[0] == PONYDOCS_DOCUMENTATION_NAMESPACE_NAME) { // Get all the versions in the product $versions = PonyDocsProductVersion::LoadVersionsForProduct($titlePieces[1], true); if (empty($versions)) { error_log('WARNING [PonyDocs] [' . __CLASS__ . '] Unable to find product versions for this topic: ' . $title); } $currentProduct = $titlePieces[1]; $currentVersion = $titlePieces[4]; // Get the latest released version of this product $latestVersionObj = PonyDocsProductVersion::GetLatestReleasedVersion($titlePieces[1]); if (is_object($latestVersionObj)) { $latestVersion = $latestVersionObj->getVersionName(); } else { error_log('WARNING [PonyDocs] [' . __CLASS__ . '] Unable to find latest released version of ' . $titlePieces[1]); } // Generate a title without the version so we can dynamically generate a list of titles with all inherited versions $titleNoVersion = $titlePieces[0] . ":" . $titlePieces[1] . ":" . $titlePieces[2] . ":" . $titlePieces[3]; // Search the database for matching to_links for each inherited version if (is_array($versions)) { foreach ($versions as $ver) { // Add this URL to array of URLs to search db for $toUrls[] = PonyDocsExtension::translateTopicTitleForDocLinks($titleNoVersion, NULL, $ver); // Compare this version with latest version. If they're the same, add the URL with "latest" too. $thisVersion = $ver->getVersionName(); if ($thisVersion == $latestVersion) { $titleLatestVersion = $titlePieces[0] . ':' . $titlePieces[1] . ':' . $titlePieces[2] . ':' . $titlePieces[3] . ':latest'; $toUrls[] = PonyDocsExtension::translateTopicTitleForDocLinks($titleLatestVersion); } } } else { error_log('WARNING [PonyDocs] [' . __CLASS__ . '] Unable to find versions for ' . $title); } } else { // Do generic mediawiki stuff for non-PonyDocs namespaces $collapseAll = TRUE; $toUrls[] = PonyDocsExtension::translateTopicTitleForDocLinks($title); } // Query the database for the list of toUrls we've collated if (!empty($toUrls)) { foreach ($toUrls as &$toUrl) { $toUrl = $dbr->strencode($toUrl); } $inUrls = "'" . implode("','", $toUrls) . "'"; $query = "SELECT * FROM " . $wgDBprefix . "ponydocs_doclinks WHERE to_link IN ({$inUrls})"; $results = $dbr->query($query); } // Create array of links, sorted by product and version $links = array(); // Loop through results and save into handy dandy links array if (!empty($results)) { foreach ($results as $result) { $fromProduct = ''; $fromVersion = ''; $displayUrl = ''; if (strpos($result->from_link, PONYDOCS_DOCUMENTATION_NAMESPACE_NAME) !== false) { // If this is a PonyDocs style links, with slashes, // save product, version, display URL accordingly. $pieces = explode('/', $result->from_link); $fromProduct = $pieces[1]; $fromVersion = $pieces[2]; $displayUrl = $result->from_link; } else { // If this is a generic mediawiki style link, with colons (or not), // set product to the namespace, and remove namespace // from the display URL. Leave version blank. if (strpos($result->from_link, ':') !== false) { $pieces = explode(':', $result->from_link); $fromProduct = $pieces[0]; // The "product" will be the namespace $displayUrl = $pieces[1]; // So the namespace doesn't show in every URL } else { // it's possible to have a link with no colons $fromProduct = 'Other'; // No namespace, so the "product" will be the string "Other" $displayUrl = $result->from_link; } $fromVersion = 'None'; // No concept of versions outside of PonyDocs } // Put all this stuff in an array that we can use to generate HTML $links[$fromProduct][$fromVersion][] = array('from_link' => $result->from_link, 'to_link' => $result->to_link, 'display_url' => $displayUrl); } } // Make HTML go! ob_start(); ?> <div class="doclinks"> <h2>Inbound links to <?php echo $plainTitle; ?> from other topics.</h2> <?php // If there are no links, display a message saying as much if (empty($links)) { ?> <p>No links to <?php echo $plainTitle; ?> (and its inherited versions) from other topics.</p> <?php } else { // Display all links, ordered by product then version foreach ($links as $fromProduct => $fromVersions) { // If this is a PonyDocs Product if (PonyDocsProduct::IsProduct($fromProduct)) { // Get versions for this product, so we can display the versions in the correct order PonyDocsProductVersion::LoadVersionsForProduct($fromProduct, true); $fromProductVersions = PonyDocsProductVersion::GetVersions($fromProduct); // If there are no valid versions for this product/user, then skip the product name header. if (!count($fromProductVersions)) { continue; } ?> <h2><?php echo $fromProduct; ?> </h2> <?php foreach ($fromProductVersions as $fromProductVersionObj) { $fromProductVersionName = $fromProductVersionObj->getVersionName(); // If there are doclinks from this version, print them if (array_key_exists($fromProductVersionName, $fromVersions)) { // Expand containers of incoming links from the current Product and Version // Expand containers of incoming links from other Products // But don't expand any containers if this is not a PonyDocs product $selected = ''; if (($currentProduct != $fromProduct || $currentVersion == $fromProductVersionName) && !$collapseAll) { $selected = 'selected'; } ?> <h3 class="doclinks-collapsible <?php print $selected; ?> "> <?php echo $fromProduct . ' ' . $fromProductVersionName; ?> </h3> <ul> <?php foreach ($fromVersions[$fromProductVersionName] as $linkAry) { ?> <li> <a href="<?php echo str_replace('$1', $linkAry['from_link'], $wgArticlePath); ?> "> <?php echo $linkAry['display_url']; ?> </a> </li> <?php } ?> </ul> <?php } } } else { ?> <h2><?php echo $fromProduct; ?> </h2> <h3 class="doclinks-collapsible selected">Latest</h3> <?php // This is not a PonyDocs product, don't worry about sorting foreach ($fromVersions as $fromVersion => $fromVersionData) { ?> <ul> <?php foreach ($fromVersionData as $linkAry) { ?> <li> <a href="<?php echo str_replace('$1', $linkAry['from_link'], $wgArticlePath); ?> "> <?php echo $linkAry['display_url']; ?> </a> </li> <?php } ?> </ul> <?php } } } } ?> </div> <?php $htmlContent = ob_get_contents(); ob_end_clean(); $wgOut->addHTML($htmlContent); return true; }
/** * This expects to find: * {{#manualDescription:Text Description}} * * @param Parser $parser * @param string $param1 Full text of manual description, must be converted to rendered format. * @return mixed This returns TRUE if PonyDocsExtension::isSpeedProcessingEnabled() is TRUE, FALSE if we are not on a TOC page and returns a formated string if we are. */ function efManualDescriptionParserFunction_Render(&$parser, $param1 = '') { global $wgTitle; if (PonyDocsExtension::isSpeedProcessingEnabled()) { return TRUE; } /** * We ignore this parser function if not in a TOC management page. */ if (!preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':([' . PONYDOCS_PRODUCT_LEGALCHARS . ']*):([' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']*)TOC([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']*)/i', $wgTitle->__toString(), $matches)) { return FALSE; } return '<h3>Manual Description: </h3><h4>' . $param1 . '</h4>'; // Return formated output }
/** * This is called upon loading the special page. It should write output to the page with $wgOut. */ public function execute() { global $wgOut, $wgArticlePath, $wgScriptPath; global $wgUser; $dbr = wfGetDB(DB_SLAVE); $this->setHeaders(); $wgOut->setPagetitle('Documentation Rename Version'); $forceProduct = PonyDocsProduct::GetSelectedProduct(); $ponydocs = PonyDocsWiki::getInstance($forceProduct); $products = $ponydocs->getProductsForTemplate(); // Security Check $authProductGroup = PonyDocsExtension::getDerivedGroup(PonyDocsExtension::ACCESS_GROUP_PRODUCT, $forceProduct); $groups = $wgUser->getGroups(); if (!in_array($authProductGroup, $groups)) { $wgOut->addHTML('<p>Sorry, but you do not have permission to access this Special page.</p>'); return; } ob_start(); // Grab all versions available for product // We need to get all versions from PonyDocsProductVersion $versions = PonyDocsProductVersion::GetVersions($forceProduct); ?> <input type="hidden" id="force_product" value="<?php echo $forceProduct; ?> " /> <div id="renameversion"> <a name="top"></a> <div class="versionselect"> <h1>Rename Version Console</h1> Select product, source version, and target version. You will be able to approve the list of manuals to rename before you launch the process. <h2>Choose a Product</h2> <?php if (!count($products)) { print "<p>No products defined.</p>"; } else { ?> <div class="product"> <select id="docsProductSelect1" name="selectedProduct" onChange="AjaxChangeProduct1();"> <?php foreach ($products as $idx => $data) { echo '<option value="' . $data['name'] . '" '; if (!strcmp($data['name'], $forceProduct)) { echo 'selected'; } echo '>' . $data['label'] . '</option>'; } ?> </select> </div> <script language="javascript"> function AjaxChangeProduct1_callback( o ) { document.getElementById( 'docsProductSelect1' ).disabled = true; var s = new String( o.responseText ); document.getElementById( 'docsProductSelect1' ).disabled = false; window.location.href = s; } function AjaxChangeProduct1() { var productIndex = document.getElementById( 'docsProductSelect1' ).selectedIndex; var product = document.getElementById( 'docsProductSelect1' )[productIndex].value; var title = '<?php echo $_SERVER['REQUEST_URI']; ?> '; // TODO fix this title var force = true; sajax_do_call( 'efPonyDocsAjaxChangeProduct', [product, title, force], AjaxChangeProduct1_callback, true); } </script> <?php } ?> <h2>Choose a Source Version</h2> <select name="version" id="versionselect_sourceversion"> <?php foreach ($versions as $version) { ?> <option value="<?php echo $version->getVersionName(); ?> "> <?php echo $version->getVersionName() . " - " . $version->getVersionStatus(); ?> </option> <?php } ?> </select> <h2>Choose a Target Version</h2> <select name="version" id="versionselect_targetversion"> <?php foreach ($versions as $version) { ?> <option value="<?php echo $version->getVersionName(); ?> "> <?php echo $version->getVersionName() . " - " . $version->getVersionStatus(); ?> </option> <?php } ?> </select> <div> <input type="button" id="versionselect_submit" value="Fetch Manuals" /> </div> </div> <div class="submitrequest" style="display: none;"> <div id="manuallist"></div> <input type="button" id="renameversion_submit" value="Rename Version" /> <div id="progressconsole"></div> </div> <div class="completed" style="display: none;"> <p class="summary"> <strong>Source Version:</strong> <span class="sourceversion"></span> <strong>Target Version:</strong> <span class="targetversion"></span> </p> <h2>Process Complete</h2> The following is the log of the processed job. Look it over for any potential issues that may have occurred during the Rename Version job. <div> <div class="logconsole" style="font-family: monospace; font-size: 10px;"></div> </div> </div> </div> <?php $buffer = ob_get_clean(); $wgOut->addHTML($buffer); return TRUE; }
/** * Populate toolbox link set and return. Should be based on user groups/access. Only used if MediaWiki:Sidebar is EMPTY. * * @return array */ public function generateSideBar() { global $wgArticlePath, $wgScriptPath, $wgUser, $wgPonyDocsEmployeeGroup; $authProductGroup = PonyDocsExtension::getDerivedGroup(PonyDocsExtension::ACCESS_GROUP_PRODUCT); $g = $wgUser->getAllGroups(); $sidebar = array('navigation' => array(array('text' => 'Main Page', 'href' => str_replace('$1', 'Main_Page', $wgArticlePath)), array('text' => 'Help', 'href' => str_replace('$1', 'helppage', $wgArticlePath)))); /** * Show Special pages if employee or author. */ if (in_array($authProductGroup, $g) || in_array($wgPonyDocsEmployeeGroup, $g)) { $sidebar['navigation'][] = array('text' => 'Special Pages', 'href' => str_replace('$1', 'Special:Specialpages', $wgArticlePath)); } /** * TOC List Mgmt if author. */ if (in_array($authorGroupByProduct, $g)) { $sidebar['navigation'][] = array('text' => 'TOC List Mgmt', 'href' => str_replace('$1', 'Special:TOCList', $wgArticlePath)); } //echo '<pre>'; print_r( $sidebar ); die( ); return $sidebar; }
/** * Return an array listing versions in ascending order that the current user has access to based on group membership. * - sysop/author/employee: All. * - user: All released and preview versions. * - anon: All released versions. * * Result is a mapping of version name to PonyDocsProductVersion objects. * * @FIXME: I don't think we need this? * The LoadVersions() method only loads versions from the defined list based on the user's permissions anyway. * * @static * @return array Map of PonyDocsProductVersion instances (name => object). */ public static function GetVersionsForUser($productName) { global $wgPonyDocsEmployeeGroup, $wgUser; $groups = $wgUser->getGroups(); $authProductGroup = PonyDocsExtension::getDerivedGroup(PonyDocsExtension::ACCESS_GROUP_PRODUCT, $productName); $authPreviewGroup = PonyDocsExtension::getDerivedGroup(PonyDocsExtension::ACCESS_GROUP_VERSION, $productName); if (in_array($authProductGroup, $groups) || in_array($wgPonyDocsEmployeeGroup, $groups) || PonyDocsCrawlerPassthrough::isAllowedCrawler()) { return self::$sVersionMap[$productName]; } elseif (in_array($authPreviewGroup, $groups)) { $retList = array(); foreach (self::$sVersionMap[$productName] as $pVersion) { if ($pVersion->getStatusCode() == self::STATUS_RELEASED || $pVersion->getStatusCode() == self::STATUS_PREVIEW) { $retList[] = $pVersion; } } return $retList; } else { return self::$sVersionMapReleased[$productName]; } }
/** * Update the nav URLs (toolbox) to include certain special pages for authors and bureaucrats. */ private function navURLS() { global $wgArticlePath, $wgTitle, $wgUser; $groups = $wgUser->getGroups(); $authProductGroup = PonyDocsExtension::getDerivedGroup(); if (in_array('bureaucrat', $groups) || in_array($authProductGroup, $groups)) { $this->data['nav_urls']['special_doctopics'] = array('href' => str_replace('$1', 'Special:DocTopics', $wgArticlePath), 'text' => 'Document Topics'); $this->data['nav_urls']['special_tocmgmt'] = array('href' => str_replace('$1', 'Special:TOCList', $wgArticlePath), 'text' => 'TOC Management'); $this->data['nav_urls']['documentation_manuals'] = array('href' => str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':Manuals', $wgArticlePath), 'text' => 'Manuals'); $partialUrl = SpecialDocumentLinks::getDocumentLinksArticle(); $this->data['nav_urls']['document_links'] = array('href' => str_replace('$1', 'Special:SpecialDocumentLinks?t=' . $wgTitle->getNsText() . ':' . $partialUrl, $wgArticlePath), 'text' => 'Document Links'); } }
/** * Called when an unknown action occurs on url. We are only interested in pdfbook action. */ function onUnknownAction($action, $article) { global $wgOut, $wgUser, $wgTitle, $wgParser, $wgRequest; global $wgServer, $wgArticlePath, $wgScriptPath, $wgUploadPath, $wgUploadDirectory, $wgScript, $wgStylePath; // We don't do any processing unless it's pdfbook if ($action != 'pdfbook') { return true; } // Get the title and make sure we're in Documentation namespace $title = $article->getTitle(); if ($title->getNamespace() != NS_PONYDOCS) { return true; } // Grab parser options for the logged in user. $opt = ParserOptions::newFromUser($wgUser); // Log the export $msg = $wgUser->getUserPage()->getPrefixedText() . ' exported as a PonyDocs PDF Book'; $log = new LogPage('ponydocspdfbook', false); $log->addEntry('book', $wgTitle, $msg); // Initialise PDF variables $layout = '--firstpage p1'; $x_margin = '1.25in'; $y_margin = '1in'; $font = 'Arial'; $size = '12'; $linkcol = '4d9bb3'; $levels = '2'; $exclude = array(); $width = '1024'; $width = "--browserwidth 1024"; // Determine articles to gather $articles = array(); $pieces = explode(":", $wgTitle->__toString()); // Try and get rid of the TOC portion of the title if (strpos($pieces[2], "TOC") && count($pieces) == 3) { $pieces[2] = substr($pieces[2], 0, strpos($pieces[2], "TOC")); } else { if (count($pieces) != 5) { // something is wrong, let's get out of here $defaultRedirect = PonyDocsExtension::getDefaultUrl(); if (PONYDOCS_DEBUG) { error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}"); } header("Location: " . $defaultRedirect); exit; } } $productName = $pieces[1]; $ponydocs = PonyDocsWiki::getInstance($productName); $pProduct = PonyDocsProduct::GetProductByShortName($productName); if ($pProduct === NULL) { // product wasn't valid wfProfileOut(__METHOD__); $wgOut->setStatusCode(404); return FALSE; } $productLongName = $pProduct->getLongName(); if (PonyDocsProductManual::isManual($productName, $pieces[2])) { $pManual = PonyDocsProductManual::GetManualByShortName($productName, $pieces[2]); } $versionText = PonyDocsProductVersion::GetSelectedVersion($productName); if (!empty($pManual)) { // We should always have a pManual, if we're printing from a TOC $v = PonyDocsProductVersion::GetVersionByName($productName, $versionText); // We have our version and our manual Check to see if a file already exists for this combination $pdfFileName = "{$wgUploadDirectory}/ponydocspdf-" . $productName . "-" . $versionText . "-" . $pManual->getShortName() . "-book.pdf"; // Check first to see if this PDF has already been created and is up to date. If so, serve it to the user and stop // execution. if (file_exists($pdfFileName)) { error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": cache serve username=\"" . $wgUser->getName() . "\" product=\"" . $productName . "\" version=\"" . $versionText . "\" " . " manual=\"" . $pManual->getShortName() . "\""); PonyDocsPdfBook::servePdf($pdfFileName, $productName, $versionText, $pManual->getShortName()); // No more processing return false; } } else { error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": User attempted to print a pdfbook from a non TOC page with path:" . $wgTitle->__toString()); } $html = self::getManualHTML($pProduct, $pManual, $v); // HTMLDOC does not care for utf8. $html = utf8_decode("{$html}\n"); // Write the HTML to a tmp file $file = "{$wgUploadDirectory}/" . uniqid('ponydocs-pdf-book'); $fh = fopen($file, 'w+'); fwrite($fh, $html); fclose($fh); // Okay, create the title page $titlepagefile = "{$wgUploadDirectory}/" . uniqid('ponydocs-pdf-book-title'); $fh = fopen($titlepagefile, 'w+'); $coverPageHTML = self::getCoverPageHTML($pProduct, $pManual, $v); fwrite($fh, $coverPageHTML); fclose($fh); $format = 'manual'; /* @todo Modify so single topics can be printed in pdf */ $footer = $format == 'single' ? '...' : '.1.'; $toc = $format == 'single' ? '' : " --toclevels {$levels}"; // Send the file to the client via htmldoc converter $wgOut->disable(); $cmd = " --left {$x_margin} --right {$x_margin} --top {$y_margin} --bottom {$y_margin}"; $cmd .= " --header ... --footer {$footer} --tocfooter .i. --quiet --jpeg --color"; $cmd .= " --bodyfont {$font} --fontsize {$size} --linkstyle plain --linkcolor {$linkcol}"; $cmd .= "{$toc} --format pdf14 {$layout} {$width} --titlefile {$titlepagefile} --size letter"; $cmd = "htmldoc -t pdf --book --charset iso-8859-1 --no-numbered {$cmd} {$file} > {$pdfFileName}"; putenv("HTMLDOC_NOCGI=1"); $output = array(); $returnVar = 1; exec($cmd, $output, $returnVar); if ($returnVar != 0) { // 0 is success error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to run htmldoc (" . $returnVar . ") Output is as follows: " . implode("-", $output)); print "Failed to create PDF. Our team is looking into it."; } // Delete the htmlfile and title file from the filesystem. @unlink($file); if (file_exists($file)) { error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to delete temp file {$file}"); } @unlink($titlepagefile); if (file_exists($titlepagefile)) { error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to delete temp file {$titlepagefile}"); } // Okay, let's add an entry to the error log to dictate someone requested a pdf error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": fresh serve username=\"" . $wgUser->getName() . "\" version=\"{$versionText}\" " . " manual=\"" . $pManual->getLongName() . "\""); PonyDocsPdfBook::servePdf($pdfFileName, $productName, $versionText, $pManual->getLongName()); // No more processing return false; }
/** * This is called upon loading the special page. It should write output to the page with $wgOut. */ public function execute() { global $wgOut, $wgArticlePath, $wgScriptPath; global $wgUser; $dbr = wfGetDB(DB_SLAVE); $this->setHeaders(); $wgOut->setPagetitle('Documentation Branch And Inheritance'); // if title is set we have our product and manual, else take selected product if (isset($_GET['titleName'])) { if (!preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*):(.*):(.*)/', $_GET['titleName'], $match)) { throw new Exception("Invalid Title to Branch From"); } $forceProduct = $match[1]; $forceManual = $match[2]; } else { $forceProduct = PonyDocsProduct::GetSelectedProduct(); $ponydocs = PonyDocsWiki::getInstance($forceProduct); $products = $ponydocs->getProductsForTemplate(); } // Security Check $authProductGroup = PonyDocsExtension::getDerivedGroup(PonyDocsExtension::ACCESS_GROUP_PRODUCT, $forceProduct); $groups = $wgUser->getGroups(); if (!in_array($authProductGroup, $groups)) { $wgOut->addHTML("<p>Sorry, but you do not have permission to access this Special page.</p>"); return; } // Static product check if (PonyDocsProduct::GetProductByShortName($forceProduct)->isStatic()) { $wgOut->addHTML("<p>Sorry, but you cannot branch/inherit a static product.</p>"); return; } ob_start(); // Grab all versions available for product // We need to get all versions from PonyDocsProductVersion $versions = PonyDocsProductVersion::GetVersions($forceProduct); if (isset($_GET['titleName'])) { ?> <input type="hidden" id="force_titleName" value="<?php echo $_GET['titleName']; ?> " /> <input type="hidden" id="force_sourceVersion" value="<?php echo PonyDocsProductVersion::GetVersionByName($forceProduct, PonyDocsProductVersion::GetSelectedVersion($forceProduct))->getVersionName(); ?> " /> <input type="hidden" id="force_manual" value="<?php echo $forceManual; ?> " /> <?php } ?> <input type="hidden" id="force_product" value="<?php echo $forceProduct; ?> " /> <div id="docbranchinherit"> <a name="top"></a> <div class="versionselect"> <h1>Branch and Inheritance Console</h1> Begin by selecting your product, source version material and a target version below. You will then be presented with additional screens to specify branch and inherit behavior. <?php if (isset($_GET['titleName'])) { ?> <p> Requested Operation on Single Topic: <strong><?php echo $_GET['titleName']; ?> </strong> </p> <?php } ?> <h2>Choose a Product</h2> <?php if (isset($_GET['titleName'])) { ?> You have selected a product: <?php echo $forceProduct; ?> <?php } else { if (!count($products)) { print "<p>No products defined.</p>"; } else { ?> <div class="product"> <select id="docsProductSelect1" name="selectedProduct" onChange="AjaxChangeProduct1();"> <?php foreach ($products as $idx => $data) { echo '<option value="' . $data['name'] . '" '; if (!strcmp($data['name'], $forceProduct)) { echo 'selected'; } echo '>' . $data['label'] . '</option>'; } ?> </select> </div> <script language="javascript"> function AjaxChangeProduct1_callback( o ) { document.getElementById('docsProductSelect1').disabled = true; var s = new String( o.responseText ); document.getElementById('docsProductSelect1').disabled = false; window.location.href = s; } function AjaxChangeProduct1( ) { var productIndex = document.getElementById('docsProductSelect1').selectedIndex; var product = document.getElementById('docsProductSelect1')[productIndex].value; var title = '<?php echo $_SERVER['REQUEST_URI']; ?> '; // TODO fix this title var force = true; sajax_do_call( 'efPonyDocsAjaxChangeProduct', [product,title,force], AjaxChangeProduct1_callback,true); } </script> <?php } } ?> <h2>Choose a Source Version</h2> <?php // Determine if topic was set, if so, we should fetch version from currently selected version. if (isset($_GET['titleName'])) { $version = PonyDocsProductVersion::GetVersionByName($forceProduct, PonyDocsProductVersion::GetSelectedVersion($forceProduct)); ?> You have selected a topic. We are using the version you are currently browsing: <?php echo $version->getVersionName(); ?> <?php } else { ?> <select name="version" id="versionselect_sourceversion"> <?php foreach ($versions as $version) { ?> <option value="<?php echo $version->getVersionName(); ?> "><?php echo $version->getVersionName() . " - " . $version->getVersionStatus(); ?> </option> <?php } ?> </select> <?php } ?> <h2>Choose a Target Version</h2> <select name="version" id="versionselect_targetversion"> <?php foreach ($versions as $version) { ?> <option value="<?php echo $version->getVersionName(); ?> "><?php echo $version->getVersionName() . " - " . $version->getVersionStatus(); ?> </option> <?php } ?> </select> <p> <input type="button" id="versionselect_submit" value="Continue to Manuals" /> </p> </div> <div class="manualselect" style="display: none;"> <?php if (isset($_GET['titleName'])) { ?> <p> Requested Operation on Single Topic: <strong><?php echo $_GET['titleName']; ?> </strong> </p> <?php } ?> <p class="summary"> <strong>Source Version:</strong> <span class="sourceversion"></span> <strong>Target Version:</strong> <span class="targetversion"></span> </p> <h1>Choose Manuals To Branch/Inherit From</h1> <div id="manualselect_manuals"> </div> <h1>Choose Default Action For Topics</h1> <input type="radio" selected="selected" name="manualselect_action" value="ignore" id="manualselect_action_ignore"><label for="manualselect_action_ignore">Ignore - Do Nothing</label><br /> <input type="radio" name="manualselect_action" value="inherit" id="manualselect_action_inherit"><label for="manualselect_action_inherit">Inherit - Add Target Version to Existing Topic</label><br /> <input type="radio" name="manualselect_action" value="branch" id="manualselect_action_branch"><label for="manualselect_action_branch">Branch - Create a copy of existing topic with Target Version</label><br /> <br /> <input type="button" id="manualselect_submit" value="Continue to Topics" /> </div> <div class="topicactions" style="display: none;"> <?php if (isset($_GET['titleName'])) { ?> <p> Requested Operation on Single Topic: <strong><?php echo $_GET['titleName']; ?> </strong> </p> <?php } ?> <p class="summary"> <strong>Source Version:</strong> <span class="sourceversion"></span> <strong>Target Version:</strong> <span class="targetversion"></span> </p> <h1>Specify Topic Actions</h1> <div class="container"> </div> <br /> <br /> <input type="button" id="topicactions_submit" value="Process Request" /> <div id="progressconsole"></div> </div> <div class="completed" style="display: none;"> <p class="summary"> <strong>Source Version:</strong> <span class="sourceversion"></span> <strong>Target Version:</strong> <span class="targetversion"></span> </p> <h2>Process Complete</h2> The following is the log of the processed job. Look it over for any potential issues that may have occurred during the branch/inherit job. <div> <div class="logconsole" style="font-family: monospace; font-size: 10px;"> </div> </div> </div> </div> <?php $buffer = ob_get_clean(); $wgOut->addHTML($buffer); return true; }