Пример #1
0
 /**
  * This returns the list of available products for template output in a more useful way for templates.  
  * It is a simple list with each element being an associative array containing three keys: name status, and parent
  * 
  * @FIXME:  If a product has NO defined versions it should be REMOVED from this list.
  *
  * @return array  array of product arrays, keyed by shortname
  */
 public function getProductsForTemplate()
 {
     $product = PonyDocsProduct::GetProducts();
     $productAry = array();
     foreach ($product as $p) {
         // Only add product to list if it has versions visible to this user
         $valid = FALSE;
         $versions = PonyDocsProductVersion::LoadVersionsForProduct($p->getShortName());
         if (!empty($versions)) {
             $valid = TRUE;
         } elseif (empty($versions)) {
             // Check for children with visibile versions
             foreach (PonyDocsProduct::getChildProducts($p->getShortName()) as $childProductName) {
                 $childVersions = PonyDocsProductVersion::LoadVersionsForProduct($childProductName);
                 if (!empty($childVersions)) {
                     $valid = TRUE;
                     break;
                 }
             }
         }
         if ($valid) {
             $productAry[$p->getShortname()] = array('name' => $p->getShortName(), 'label' => $p->getLongName(), 'description' => $p->getDescription(), 'parent' => $p->getParent(), 'categories' => $p->getCategories());
         }
     }
     return $productAry;
 }
Пример #2
0
 /**
  * This is called upon loading the special page. It should write output to the page with $wgOut.
  * 
  * @param string $par The portion of the URI after Special:StaticDocServer/
  */
 public function execute($par)
 {
     #TODO: switch to $this->getOuput() and $this->getRequest() when we upgrade MW
     global $wgOut, $wgRequest;
     $wgOut->disable();
     $found = FALSE;
     list($productName, $versionName, $path) = explode('/', $par, 3);
     if (substr($par, -1, 1) == '/') {
         $par .= 'index.html';
     }
     // Validate parameters are set
     if (isset($productName) && isset($versionName) && PonyDocsProduct::GetProductByShortName($productName) && PonyDocsProductVersion::GetVersionByName($productName, $versionName)) {
         $filename = PONYDOCS_STATIC_DIR . "/{$par}";
         if (file_exists($filename)) {
             $found = TRUE;
         }
     }
     if (!$found) {
         $wgRequest->response()->header("HTTP/1.1 404 Not Found");
         echo "<html>\n";
         echo "<head><title>Not Found</title></head>\n";
         echo "<body>\n";
         echo "<h1>Bad Request</h1>\n";
         echo "<div>The documentation you have requested does not exist.</div>\n";
         echo "</body>\n";
         echo "</html>\n";
     } else {
         $mimeMagic = MimeMagic::singleton();
         $pathParts = pathinfo($filename);
         /* get mime-type for a specific file */
         header('Content-type: ' . $mimeMagic->guessTypesForExtension($pathParts['extension']));
         readfile($filename);
     }
 }
Пример #3
0
 /**
  * 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, $wgArticlePath;
     $dbr = wfGetDB(DB_SLAVE);
     $this->setHeaders();
     /**
      * We need to select ALL pages of the form:
      * 	Documentation:<productShortName>:<manualShortName>TOC*
      * We should group these by manual and then by descending version order.  The simplest way is by assuming that every TOC
      * page is linked to at least one version (category) and thus has an entry in the categorylinks table.  So to do this we
      * must run this query for each manual type, which involes getting the list of manuals defined.
      */
     $out = array();
     // Added for WEB-10802, looking for product name passed in
     // e.g. /Special:TOCList/Splunk
     $parts = explode('/', $par);
     if (isset($parts[0]) && is_string($parts[0]) and $parts[0] != '') {
         $productName = $parts[0];
     } else {
         $productName = PonyDocsProduct::GetSelectedProduct();
     }
     $manuals = PonyDocsProductManual::GetDefinedManuals($productName);
     $allowed_versions = array();
     $product = PonyDocsProduct::GetProductByShortName($productName);
     $wgOut->setPagetitle('Table of Contents Management');
     if ($product) {
         $wgOut->addHTML('<h2>Table of Contents Management Pages for ' . $product->getLongName() . '</h2>');
         foreach (PonyDocsProductVersion::GetVersions($productName) as $v) {
             $allowed_versions[] = $v->getVersionName();
         }
         foreach ($manuals as $pMan) {
             $res = $dbr->select(array('categorylinks', 'page'), array('page_title', 'GROUP_CONCAT( cl_to separator "|") categories'), array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "page_title LIKE '" . $dbr->strencode("{$productName}:" . $pMan->getShortName()) . "TOC%'", 'cl_to LIKE "V:%:%"', 'cl_type = "page"'), __METHOD__, array('GROUP BY' => 'page_title'));
             while ($row = $dbr->fetchObject($res)) {
                 $versions = array();
                 $categories = explode('|', $row->categories);
                 foreach ($categories as $category) {
                     $categoryParts = explode(':', $category);
                     if (in_array($categoryParts[2], $allowed_versions)) {
                         $versions[] = $categoryParts[2];
                     }
                 }
                 if (sizeof($versions)) {
                     $wgOut->addHTML('<a href="' . str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}", $wgArticlePath) . '">' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}" . '</a> - Versions: ' . implode(' | ', $versions) . '<br />');
                 }
             }
         }
         $html = '<h2>Other Useful Management Pages</h2>' . '<a href="' . str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productName . PONYDOCS_PRODUCTVERSION_SUFFIX, $wgArticlePath) . '">Version Management</a> - Define and update available ' . $productName . ' versions.<br />' . '<a href="' . str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productName . PONYDOCS_PRODUCTMANUAL_SUFFIX, $wgArticlePath) . '">Manuals Management</a> - Define the list of available manuals for the Documentation namespace.' . '<br/><br/>';
         $wgOut->addHTML($html);
     } else {
         $wgOut->addHTML("<h2>Table of Contents Management Page</h2>Error: Product {$productName} does not exist.");
     }
 }
 /**
  * Replace a version on an existing Topic
  *
  * @param $topicTitle string The internal mediawiki title of the article.
  * @param $sourceVersion PonyDocsVersion The source Version
  * @param $targetVersion PonyDocsVersion The target Version
  * @returns boolean
  */
 public static function changeVersionOnTopic($topicTitle, $sourceVersion, $targetVersion)
 {
     global $wgTitle;
     // Clear any hooks so no weirdness gets called after we save the change
     $wgHooks['ArticleSave'] = array();
     if (!preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':([^:]*):([^:]*):(.*):([^:]*)$/', $topicTitle, $match)) {
         throw new Exception("Invalid Title to Rename Version: {$topicTitle}");
     }
     $productName = $match[1];
     $title = $match[3];
     // Get PonyDocsProduct
     // TODO: Why don't we just pass the product in instead of re-deriving it from something else and then loading it?
     $product = PonyDocsProduct::GetProductByShortName($productName);
     $title = Title::newFromText($topicTitle);
     $wgTitle = $title;
     $article = new Article($title);
     if (!$article->exists()) {
         // No such title exists in the system
         throw new Exception("Invalid Title to Rename Version: {$topicTitle}");
     }
     $content = $article->getContent();
     $oldCategory = '[[Category:V:' . $product->getShortName() . ':' . $sourceVersion->getVersionName() . ']]';
     $newCategory = '[[Category:V:' . $product->getShortName() . ':' . $targetVersion->getVersionName() . ']]';
     $message = '';
     $editTopic = TRUE;
     // Get conflicts.
     $conflicts = PonyDocsBranchInheritEngine::getConflicts($product, $topicTitle, $targetVersion);
     if (!empty($conflicts)) {
         // If there's already a topic with the target version,
         // then we just want to remove the source version from the source topic
         foreach ($conflicts as $conflict) {
             $conflictingArticle = new Article(Title::newFromText($conflict));
             // No big deal.  A conflict no longer exists?  Continue.
             if (!$conflictingArticle->exists()) {
                 continue;
             }
             // Conflict was same as source material. Do nothing with it.
             if ($conflict == $topicTitle) {
                 continue;
                 // Remove source version from source article
             } else {
                 $content = str_replace($oldCategory, '', $content);
                 $message = "Removed version category {$oldCategory} via RenameVersion";
             }
         }
     }
     if (empty($message)) {
         // If the Topic doesn't contain the source version, it may have been branched, or already processed
         if (strpos($content, $oldCategory) === FALSE) {
             $lastColon = strrpos($topicTitle, ':');
             $baseTopic = substr_replace($topicTitle, '', $lastColon);
             $topicTitle = PonyDocsTopic::GetTopicNameFromBaseAndVersion($baseTopic, $productName);
             // We found an instance of this title with the source version! Let's recurse just this once to handle it.
             if ($topicTitle) {
                 $editTopic = FALSE;
                 $title = self::changeVersionOnTopic($topicTitle, $sourceVersion, $targetVersion);
                 // We can't find a topic with the source version, so something is odd. Let's complain
             } else {
                 throw new Exception("Topic {$topicTitle} does not contain source version " . $sourceVersion->getVersionName());
             }
             // If the Topic already has the new version, just remove the old version
         } elseif (strpos($content, $newCategory) !== FALSE) {
             $content = str_replace($oldCategory, '', $content);
             $message = "Removed version category {$oldCategory} via RenameVersion";
             // Otherwise replace old with new
         } else {
             $content = str_replace($oldCategory, $newCategory, $content, $count);
             $message = "Renamed version category {$oldCategory} to {$newCategory} in {$count} locations via RenameVersion";
         }
     }
     // Finally we can edit the topic
     if ($editTopic) {
         // TODO: doEdit returns a status that we should check
         $article->doEdit($content, $message, EDIT_UPDATE);
     }
     return $title;
 }
Пример #5
0
    /**
     * 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;
    }
Пример #6
0
 /**
  * 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;
 }
Пример #7
0
/**
 * This is called when {{#manual:short|long}} is found in an article content. It should produce an output
 * set of HTML which provides the name (long) as a link to the most recent (based on version tags) TOC
 * management page for that manual.
 *
 * @param Parser $parser
 * @param string $shortName Short name of the Manual used in links.
 * @param string $longName Long/display name of Manual.
 * @param string $categories The categories for the Manual, in a comma-separated list
 * @return array
 */
function efManualParserFunction_Render(&$parser, $shortName = '', $longName = '', $categories = '')
{
    global $wgArticlePath;
    $valid = TRUE;
    if (!preg_match(PONYDOCS_PRODUCTMANUAL_REGEX, $shortName) || !strlen($shortName) || !strlen($longName)) {
        return $parser->insertStripItem('', $parser->mStripState);
    }
    $manualName = preg_replace('/([^' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']+)/', '', $shortName);
    // TODO: It's silly to do this twice (the other is in LoadManualsForProduct().
    //       We should get the manual object from PonyDocsProductManual
    $static = FALSE;
    if (strpos($shortName, PONYDOCS_PRODUCT_STATIC_PREFIX) === 0) {
        $static = TRUE;
        $manualName = substr($manualName, strlen(PONYDOCS_PRODUCT_STATIC_PREFIX));
    }
    $productName = PonyDocsProduct::GetSelectedProduct();
    $version = PonyDocsProductVersion::GetSelectedVersion($productName);
    // Don't cache Documentation:[product]:Manuals pages because when we switch selected version the content will come from cache
    $parser->disableCache();
    // If static, link to Special:StaticDocImport
    if ($static) {
        $output = "<p><a href=\"" . str_replace('$1', "Special:StaticDocImport/{$productName}/{$manualName}", $wgArticlePath) . "\" style=\"font-size: 1.3em;\">{$longName}</a></p>\n" . "<span style=\"padding-left: 20px;\">Click manual to manage static documentation.</span>\n";
        // Otherwise, link to TOC for current Version OR add a link to create a new TOC if none exists
    } else {
        // TODO: We should call PonyDocsTOC.php or maybe PonyDocsProductManual to see if there's a TOC in this manual
        //       or maybe actually get the manual object and query it
        $dbr = wfGetDB(DB_SLAVE);
        $res = $dbr->select(array('categorylinks', 'page'), 'page_title', array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "cl_to = 'V:{$productName}:{$version}'", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper($productName)) . ':' . $dbr->strencode(strtoupper($manualName)) . "TOC%'"), __METHOD__);
        if (!$res->numRows()) {
            /**
             * Link to create new TOC page -- should link to current version TOC and then add message to explain.
             */
            $output = '<p><a href="' . str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productName . ':' . $manualName . 'TOC' . $version, $wgArticlePath) . '" style="font-size: 1.3em;">' . $longName . "</a></p>\n <span style=\"padding-left: 20px;\">Click manual to create TOC for current version (" . $version . ").</span>\n";
        } else {
            $row = $dbr->fetchObject($res);
            $output = '<p><a href="' . str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}", $wgArticlePath) . '" style="font-size: 1.3em;">' . $longName . "</a></p>\n";
        }
    }
    if ($categories != '') {
        $output .= "<br>Categories: {$categories}";
    }
    return $parser->insertStripItem($output, $parser->mStripState);
}
 /**
  * Have an existing Topic "inherit" a new version by applying a category 
  * version tag to it.
  *
  * @param $topicTitle string The internal mediawiki title of the article.
  * @param $version PonyDocsVersion The target Version
  * @param $tocSection The TOC section this title resides in.
  * @param $tocTitle The toc title that references this topic.
  * @param $deleteExisting boolean Should we purge any existing conflicts?
  * @returns boolean
  */
 static function inheritTopic($topicTitle, $version, $tocSection, $tocTitle, $deleteExisting)
 {
     global $wgTitle;
     // Clear any hooks so no weirdness gets called after we save the inherit
     $wgHooks['ArticleSave'] = array();
     if (!preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':([^:]*):([^:]*):(.*):([^:]*)$/', $topicTitle, $match)) {
         throw new Exception("Invalid Title to Inherit From: " . $topicTitle);
     }
     $productName = $match[1];
     $manual = $match[2];
     $title = $match[3];
     // Get PonyDocsProduct
     $product = PonyDocsProduct::GetProductByShortName($productName);
     // Get conflicts.
     $conflicts = self::getConflicts($product, $topicTitle, $version);
     if (!empty($conflicts)) {
         if (!$deleteExisting) {
             throw new Exception("When calling inheritTitle, there were conflicts and deleteExisting was false.");
         }
         // We want to purge each conflicting title completely.
         foreach ($conflicts as $conflict) {
             $article = new Article(Title::newFromText($conflict));
             if (!$article->exists()) {
                 // No big deal. A conflict no longer exists? Continue.
                 continue;
             }
             if ($conflict == $topicTitle) {
                 // Conflict was same as source material. Do nothing with it.
                 continue;
             } else {
                 $article->doDelete("Requested purge of conficting article when inheriting topic " . $topicTitle . " with version: " . $version->getVersionName(), false);
             }
         }
     }
     $title = Title::newFromText($topicTitle);
     $wgTitle = $title;
     $existingArticle = new Article($title);
     if (!$existingArticle->exists()) {
         // No such title exists in the system
         throw new Exception("Invalid Title to Inherit From: " . $topicTitle);
     }
     // Okay, source article exists.
     // Add the appropriate version cateogry.
     // Check for existing category.
     $content = $existingArticle->getContent();
     if (!preg_match("/\\[\\[Category:V:" . preg_quote($productName . ":" . $version->getVersionName()) . "\\]\\]/", $content)) {
         $content .= "[[Category:V:" . $productName . ":" . $version->getVersionName() . "]]";
         // Save the article as an edit
         $existingArticle->doEdit($content, "Inherited topic " . $topicTitle . " with version: " . $productName . ":" . $version->getVersionName(), EDIT_UPDATE);
     }
     return $title;
 }
Пример #9
0
 /**
  * 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;
 }
Пример #10
0
    /**
     * 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;
    }
Пример #11
0
 /**
  * This function returns information about the versions on this topic.
  * - Version permissions: unreleased, preview, or released
  * - Version age: older, latest, or newer
  * Since a Topic can have multiple versions, it's possible for a single topic to be in unreleased, preview, released, older, 
  * latest, AND newer versions AT THE SAME TIME!
  * This information can be used by skins to change UI based on the version features.
  *  
  * @return array
  */
 public function getVersionClasses()
 {
     $productName = PonyDocsProduct::getSelectedProduct();
     $versionClasses = array();
     $releasedVersions = PonyDocsProductVersion::GetReleasedVersions($productName);
     // Just the names of our released versions
     $releasedNames = array();
     foreach ($releasedVersions as $ver) {
         $releasedNames[] = strtolower($ver->getVersionName());
     }
     $previewVersions = PonyDocsProductVersion::GetPreviewVersions($productName);
     // Just the names of our preview versions
     $previewNames = array();
     foreach ($previewVersions as $ver) {
         $previewNames[] = strtolower($ver->getVersionName());
     }
     $latestVersion = PonyDocsProductVersion::GetLatestReleasedVersion($productName);
     foreach ($this->versions as $version) {
         $versionName = strtolower($version->getVersionName());
         // Is this version released, preview, or unreleased?
         if (in_array($versionName, $releasedNames)) {
             $versionClasses['released'] = TRUE;
         } elseif (in_array($versionName, $previewNames)) {
             $versionClasses['preview'] = TRUE;
         } else {
             $versionClasses['unreleased'] = TRUE;
         }
         // Is this version older or later or equal to the current version?
         if ($latestVersion) {
             if (PonyDocs_ProductVersionCmp($version, $latestVersion) < 0) {
                 $versionClasses['older'] = TRUE;
             } elseif (PonyDocs_ProductVersionCmp($version, $latestVersion) > 0) {
                 $versionClasses['newer'] = TRUE;
             } else {
                 $versionClasses['latest'] = TRUE;
             }
         }
     }
     return array_keys($versionClasses);
 }
Пример #12
0
 /**
  * This function will take the constant for the base author group and concatinate
  * it with the current product.  It accepts either the type of "product" or "preview"
  * 
  * This same formula is used to define the groups per
  * product, thus you can check if the current author in the current product has permission
  * to edit, branch or inherit with:
  * 	$groups = $wgUser->getAllGroups( );
  * 	if( in_array( getDerivedGroup(), $groups ){
  * 		//do something protected here
  * 	}
  *
  * @param int $type access group to retrieve (either for product or version)
  * @param string $productName short name of product
  * @return string or boolean false on failure
  */
 public static function getDerivedGroup($type = self::ACCESS_GROUP_PRODUCT, $productName = NULL)
 {
     global $wgPonyDocsBaseAuthorGroup, $wgPonyDocsBasePreviewGroup;
     // if product not specified, take product from session
     if (is_null($productName)) {
         $product = PonyDocsProduct::GetSelectedProduct();
     } else {
         $product = $productName;
     }
     switch ($type) {
         case self::ACCESS_GROUP_PRODUCT:
             $group = $product . '-' . $wgPonyDocsBaseAuthorGroup;
             break;
         case self::ACCESS_GROUP_VERSION:
             $group = $product . '-' . $wgPonyDocsBasePreviewGroup;
             break;
         default:
             // if we're here we failed
             $group = false;
     }
     return $group;
 }
Пример #13
0
 /**
  * Show existing versions and remove form
  * 
  * @global OutputPage $wgOut
  * @param PonyDocsProduct $product
  * @param mixed $manual PonyDocsManual or NULL
  */
 private function showExistingVersions($product, $manual)
 {
     global $wgOut;
     $productName = $product->getShortName();
     if (!is_null($manual)) {
         $manualName = $manual->getShortName();
     }
     // Display existing versions
     $wgOut->addHTML('<h3>Existing Content</h3>');
     if (is_null($manual)) {
         $existingVersions = $product->getStaticVersionNames();
     } else {
         $existingVersions = $manual->getStaticVersionNames();
     }
     if (count($existingVersions) > 0) {
         $wgOut->addHTML('<script type="text/javascript">function verify_delete() {return confirm("Are you sure?");}</script>');
         $wgOut->addHTML('<table>');
         $wgOut->addHTML('<tr><th>Version</th><th></th></tr>');
         foreach ($existingVersions as $versionName) {
             $wgOut->addHTML("<tr>\n" . "<td>{$versionName}</td>\n" . "<td>\n" . '<form method="POST" onsubmit="return verify_delete()">' . "\n" . '<input type="submit" name="action" value="remove"/>' . "\n" . '<input type="hidden" name="product" value="' . $productName . '"/>' . "\n" . '<input type="hidden" name="version" value="' . $versionName . '"/>' . "\n");
             if (!is_null($manual)) {
                 $wgOut->addHTML('<input type="hidden" name="manual" value="' . $manualName . '"/>' . "\n");
             }
             $wgOut->addHTML("</form>\n</td>\n</tr>\n");
         }
         $wgOut->addHTML('</tr></table>');
     } else {
         $wgOut->addHTML('<p>No existing version defined.</p>');
     }
 }
Пример #14
0
 /**
  * Return the current product object based on the title object;  returns null otherwise.
  *
  * @static
  * @return PonyDocsProduct
  */
 public static function GetCurrentProduct($title = NULL)
 {
     global $wgTitle;
     $targetTitle = $title == NULL ? $wgTitle : $title;
     $pcs = explode(':', $targetTitle->__toString());
     if (!PonyDocsProduct::IsProduct($pcs[1])) {
         return NULL;
     }
     return PonyDocsProduct::GetProductByShortName($pcs[1]);
 }
Пример #15
0
 /**
  * Create a URL path (e.g. Documentation/Foo/latest) for a ProductVersion
  * 
  * @param string $productName - Optional. We'll get the selected product (which defaults to the default product) if empty
  * @param string $versionName - Optional. We'll get the selected version (which defaults to the latest release) if empty
  * 
  * @return string
  */
 public static function getVersionURLPath($productName = NULL, $versionName = NULL)
 {
     global $wgArticlePath;
     if (!isset($productName) || !PonyDocsProduct::isProduct($productName)) {
         $productName = getSelectedProduct()->getShortName();
     }
     if (!isset($versionName)) {
         $versionName = self::GetSelectedVersion($productName);
     }
     $latestVersion = PonyDocsProductVersion::GetLatestReleasedVersion($productName);
     if ($latestVersion) {
         if ($versionName == $latestVersion->getVersionName()) {
             $versionName = 'latest';
         }
     }
     $base = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME, $wgArticlePath);
     return "{$base}/{$productName}/{$versionName}";
 }
Пример #16
0
/**
 * This is called when a version change occurs in the select box.  It should update the version
 * only;  to update the page the Ajax function in JS should then refresh by using history.go(0)
 * or something along those lines, otherwise the content may reflect the old version selection.
 * 
 * @param string $version New version tag to set as current.  Should be some checking.
 * @param string $title The current title that the person resides in, if any.
 * @param boolean $force Force the change, no matter if a doc is in the same version or not
 * @return AjaxResponse
 */
function efPonyDocsAjaxChangeVersion($product, $version, $title, $force = false)
{
    global $wgArticlePath;
    $dbr = wfGetDB(DB_SLAVE);
    PonyDocsProduct::SetSelectedProduct($product);
    PonyDocsProductVersion::SetSelectedVersion($product, $version);
    $response = new AjaxResponse();
    if ($force) {
        // This is coming from the search page.  let's not do any title look up,
        // and instead just pass back the same url.
        $leadingSlash = "/";
        if (substr($title, 0, 1) == "/") {
            $leadingSlash = "";
        }
        $response->addText($leadingSlash . $title);
        // Need to make the url non-relative
        return $response;
    }
    $defaultTitle = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME;
    if (preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*):(.*):(.*)/i', $title, $match)) {
        $res = $dbr->select('categorylinks', 'cl_from', array("cl_to = 'V:" . $dbr->strencode($product . ":" . $version) . "'", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper($product . ':' . $match[2] . ':' . $match[3])) . ":%'"), __METHOD__);
        if ($res->numRows()) {
            $response->addText(str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/' . $product . '/' . $version . '/' . $match[2] . '/' . $match[3], $wgArticlePath));
            if (PONYDOCS_DEBUG) {
                error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] ajax redirect rule 1");
            }
        } else {
            // same manual/topic doesn't exist for newly selected version, redirect to default
            $response->addText(str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/' . $product . '/' . $version, $wgArticlePath));
            if (PONYDOCS_DEBUG) {
                error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] ajax redirect rule 2");
            }
        }
    } elseif (preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(Manuals|Versions)/i', $title, $match)) {
        // this is a manuals or versions page
        $add_text = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $product . ':' . $match[2], $wgArticlePath);
        /// FIXME we probably need to clear objectcache for this [product]:Manuals page, or even better, do not cache it(?)
        $response->addText($add_text);
        if (PONYDOCS_DEBUG) {
            error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] ajax redirect rule 3");
        }
    } elseif (preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/(.*)\\/(.*)\\/(.*)\\/(.*)/i', $title, $match)) {
        /**
         * Just swap out the source version tag ($match[2]) with the selected version in the output URL.
         */
        $response->addText(str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/' . $product . '/' . $version . '/' . $match[3] . '/' . $match[4], $wgArticlePath));
        if (PONYDOCS_DEBUG) {
            error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] ajax redirect rule 4");
        }
    } elseif (preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/(.*)\\/(.*)\\/(.*)/i', $title, $match)) {
        //Redirection for WEB-10264
        $response->addText(str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/' . $product . '/' . $version . '/' . $match[3], $wgArticlePath));
        if (PONYDOCS_DEBUG) {
            error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] ajax redirect rule to switch versions on a static manual");
        }
    } else {
        $add_text = str_replace('$1', $defaultTitle . '/' . $product . '/' . $version, $wgArticlePath);
        $response->addText($add_text);
        if (PONYDOCS_DEBUG) {
            error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] ajax redirect rule 5");
        }
    }
    if (PONYDOCS_DEBUG) {
        error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] ajax redirect result " . print_r($response, true));
    }
    return $response;
}
Пример #17
0
 public function prepareDocumentation()
 {
     global $wgOut, $wgParser, $wgScriptPath, $wgTitle, $wgUser;
     /**
      * We need a lot of stuff from our PonyDocs extension!
      */
     $ponydocs = PonyDocsWiki::getInstance($this->data['selectedProduct']);
     $this->data['manuals'] = $ponydocs->getManualsForProduct($this->data['selectedProduct']);
     /**
      * Adjust content actions as needed, such as add 'view all' link.
      */
     $this->contentActions();
     $this->navURLS();
     /**
      * Possible topic syntax we must handle:
      * 
      * Documentation:<topic> *Which may include a version tag at the end, we don't care about this.
      * Documentation:<productShortName>:<manualShortName>:<topic>:<version>
      * Documentation:<productShortName>:<manualShortName>
      */
     /**
      * Based on the name; i.e. 'Documentation:Product:Manual:Topic' we need to parse it out and store the manual name and
      * the topic name as parameters. We store manual in 'manualname' and topic in 'topicname'. Special handling
      * needs to be done for versions and TOC?
      *
      * 	0=NS (Documentation)
      *  1=Product (Short name)
      *  2=Manual (Short name)
      *  3=Topic
      *  4=Version
      */
     $pManual = null;
     $pieces = explode(':', $wgTitle->__toString());
     $helpClass = '';
     /**
      * This isn't a specific topic+version -- handle appropriately.
      */
     if (sizeof($pieces) < 4) {
         if (!strcmp(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $this->data['selectedProduct'] . PONYDOCS_PRODUCTVERSION_SUFFIX, $wgTitle->__toString())) {
             $this->data['titletext'] = 'Versions Management - ' . $this->data['selectedProduct'];
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>* Use {{#version:name|status}} to define a new version,' . ' where status is released, unreleased, or preview.' . ' Valid chars in version name are A-Z, 0-9, period, comma, and dash.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>* Use {{#versiongroup:name|message}} to set a banner' . ' message that will appear on every topic in every version following the versiongroup.</i></span>');
         } elseif (!strcmp(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $this->data['selectedProduct'] . PONYDOCS_PRODUCTMANUAL_SUFFIX, $wgTitle->__toString())) {
             $this->data['titletext'] = 'Manuals Management - ' . $this->data['selectedProduct'];
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Use {{#manual:manualShortName|displayName|categories}} to define a new manual.');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Prepend manual short name with ' . PONYDOCS_PRODUCT_STATIC_PREFIX . ' to define a static manual.' . '</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* If you omit display name, the short name will be used in links.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Categories is a comma-separated list of categories</i></span>');
         } elseif (!strcmp(PONYDOCS_DOCUMENTATION_PRODUCTS_TITLE, $wgTitle->__toString())) {
             $this->data['titletext'] = 'Products Management';
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Use {{#product:productShortName|displayName|description|parent|categories}} to define a new product.' . '</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Prepend product short name with ' . PONYDOCS_PRODUCT_STATIC_PREFIX . ' to define a static product.' . '</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* displayName, description, parent, and categories can be left empty.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* If you leave displayName empty, productShortName will be used in links.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Categories is a comma-separated list of categories.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Each product here <b>MUST</b> also be listed in $ponyDocsProductsList,' . ' usually configured in LocalSettings.php.</i></span>');
         } elseif (preg_match('/(.*)TOC(.*)/', $pieces[2], $matches)) {
             $this->data['titletext'] = $matches[1] . ' Table of Contents Page';
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Optionally start this page with {{#manualDescription:Manual Description.}}' . ' followed by two line-breaks to set a manual description for the Manual this TOC belongs to.' . '</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Topics are grouped into sections by section headers.' . ' Any line without markup is considered a section header.' . ' A section header is required before the the first topic tag.</i></span>');
             $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Topic tags must be part of an unordered list.' . ' Use {{#topic:Display Name}} after a * (list item markup) to create topics.</i></span>');
         } elseif (sizeof($pieces) >= 2 && PonyDocsProductManual::IsManual($pieces[1], $pieces[2])) {
             $pManual = PonyDocsProductManual::GetManualByShortName($pieces[1], $pieces[2]);
             if ($pManual) {
                 $this->data['manualname'] = $pManual->getLongName();
             } else {
                 $this->data['manualname'] = $pieces[2];
             }
             $this->data['topicname'] = $pieces[3];
             $this->data['titletext'] = $pieces[2];
         } else {
             $this->data['topicname'] = $pieces[2];
         }
     } else {
         $pManual = PonyDocsProductManual::GetManualByShortName($pieces[1], $pieces[2]);
         if ($pManual) {
             $this->data['manualname'] = $pManual->getLongName();
         } else {
             $this->data['manualname'] = $pieces[2];
         }
         $this->data['topicname'] = $pieces[3];
         $h1 = PonyDocsTopic::FindH1ForTitle($wgTitle->__toString());
         if ($h1 !== FALSE) {
             $this->data['titletext'] = $h1;
         }
     }
     /**
      * Get current topic, passing it our global Article object.
      * From this, generate our TOC based on the current topic selected.
      * This generates our left sidebar TOC plus our prev/next/start navigation links.
      * This should ONLY be done if we actually are WITHIN a manual, so special pages like TOC, etc. should not do this!
      */
     if ($pManual) {
         $p = PonyDocsProduct::GetProductByShortName($this->data['selectedProduct']);
         $v = PonyDocsProductVersion::GetVersionByName($this->data['selectedProduct'], $this->data['selectedVersion']);
         $toc = new PonyDocsTOC($pManual, $v, $p);
         list($this->data['manualtoc'], $this->data['tocprev'], $this->data['tocnext'], $this->data['tocstart']) = $toc->loadContent();
         $this->data['toctitle'] = $toc->getTOCPageTitle();
     }
     /**
      * Create a PonyDocsTopic from our article. From this we populate:
      *
      * topicversions:  List of version names topic is tagged with.
      * inlinetoc:  Inline TOC shown above article body.
      * catcode:  Special category code.
      * cattext:  Category description.
      * basetopicname:  Base topic name (w/o :<version> at end).
      * basetopiclink:  Link to special TopicList page to view all same topics.
      */
     $context = $this->skin->getContext();
     $article = Article::newFromTitle($context->getTitle(), $context);
     $topic = new PonyDocsTopic($article);
     if (preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*):(.*):(.*)/', $wgTitle->__toString()) || preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':.*:.*TOC.*/', $wgTitle->__toString())) {
         $this->data['topicversions'] = PonyDocsWiki::getVersionsForTopic($topic);
         $this->data['inlinetoc'] = $topic->getSubContents();
         $this->data['versionclasses'] = $topic->getVersionClasses();
         $this->data['versionGroupMessage'] = $this->data['pVersion']->getVersionGroupMessage();
         /**
          * Sort of a hack -- we only use this right now when loading a TOC page which is new/does not exist.
          * When this happens a hook (AlternateEdit) adds an inline script to define this JS function,
          * which populates the edit box with the proper Category tag based on the currently selected version.
          */
         $this->data['body_onload'] = 'ponyDocsOnLoad();';
         switch ($this->data['catcode']) {
             case 0:
                 $this->data['cattext'] = 'Applies to latest version which is currently unreleased.';
                 break;
             case 1:
                 $this->data['cattext'] = 'Applies to latest version.';
                 break;
             case 2:
                 $this->data['cattext'] = 'Applies to released version(s) but not the latest.';
                 break;
             case 3:
                 $this->data['cattext'] = 'Applies to latest preview version.';
                 break;
             case 4:
                 $this->data['cattext'] = 'Applies to one or more preview version(s) only.';
                 break;
             case 5:
                 $this->data['cattext'] = 'Applies to one or more unreleased version(s) only.';
                 break;
             case -2:
                 /** Means its not a a title name which should be checked. */
                 break;
             default:
                 $this->data['cattext'] = 'Does not apply to any version of PonyDocs.';
                 break;
         }
     }
     $this->data['basetopicname'] = $topic->getBaseTopicName();
     if (strlen($this->data['basetopicname'])) {
         $this->data['basetopiclink'] = '<a href="' . $wgScriptPath . '/index.php?title=Special:TopicList&topic=' . $this->data['basetopicname'] . '">View All</a>';
     }
     $temp = PonyDocsTopic::FindH1ForTitle(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $topic->getTitle()->getText());
     if ($temp !== false) {
         // We got an H1!
         $this->data['pagetitle'] = $temp;
     }
 }
 /**
  * Get the query string to append to feed link URLs.
  * This is overridden by RCL to add the target parameter
  */
 public function getFeedQuery()
 {
     return 'product=' . urlencode(isset($_GET['product']) ? $_GET['product'] : PonyDocsProduct::GetSelectedProduct());
 }
Пример #19
0
    /**
     * 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;
    }