howardjones/network-weathermap

View on GitHub
lib/Weathermap/Integrations/Cacti/WeatherMapCactiUserPlugin.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

namespace Weathermap\Integrations\Cacti;

require_once dirname(__FILE__) . "/database.php";

use Weathermap\UI\UIBase;
use Weathermap\Integrations\MapManager;

/**
 * The common parts of the Cacti 'user' plugin (map display)
 *
 * @package Weathermap\Integrations\Cacti
 */
class WeatherMapCactiUserPlugin extends UIBase
{
    /** @var MapManager $manager */
    public $manager;
    public $myURL;
    public $editorURL;
    public $managementURL;
    private $outputDirectory;
    private $imageFormat;
    public $cactiConfig;
    public $configPath;
    public $managementRealm;
    public $editorRealm;

    public $commands = array(
        'maplist' => array('handler' => 'handleMapListAPI', 'args' => array()),
        'settings' => array('handler' => 'handleSettingsAPI', 'args' => array()),

        'viewthumb' => array(
            'handler' => 'handleBigThumb',
            'args' => array(array("id", "maphash"), array("time", "int", true))
        ),
        'viewthumb48' => array('handler' => 'handleLittleThumb', 'args' => array(array("id", "maphash"))),
        'viewimage' => array('handler' => 'handleImage', 'args' => array(array("id", "maphash"))),
        'viewhtml' => array('handler' => 'handleHTML', 'args' => array(array("id", "maphash"))),

        'viewmap' => array(
            'handler' => 'handleViewMap',
            'args' => array(array("id", "maphash"), array("group_id", "int", true))
        ),

        'viewcycle_fullscreen' => array(
            'handler' => 'handleViewCycleFullscreen',
            'args' => array(array("id", "maphash"))
        ),
        'viewcycle_filtered_fullscreen' => array(
            'handler' => 'handleViewCycleFilteredFullscreen',
            'args' => array(array("id", "maphash"), array("group_id", "int", true))
        ),

        'viewcycle' => array('handler' => 'handleViewCycle', 'args' => array()),
        'viewcycle_filtered' => array(
            'handler' => 'handleViewCycleFiltered',
            'args' => array(array("group_id", "int", true))
        ),
        ':: DEFAULT ::' => array(
            'handler' => 'handleDefaultView',
            'args' => array(
                array("group_id", "int", true)
            )
        )
    );

    public function __construct($config, $imageFormat, $basePath)
    {
        parent::__construct();

        $this->cactiConfig = $config;
        $this->myURL = "SHOULD-BE-OVERRIDDEN";
        $this->managementURL = "SHOULD-BE-OVERRIDDEN";
        $this->editorURL = "SHOULD-BE-OVERRIDDEN";
        $this->managementRealm = "SHOULD-BE-OVERRIDDEN";
        $this->editorRealm = "SHOULD-BE-OVERRIDDEN";
        $this->configPath = $basePath . '/configs';
        $this->outputDirectory = $basePath . '/output/';
        $this->imageFormat = $imageFormat;
        $pdo = weathermap_get_pdo();
        $cactiInterface = new CactiApplicationInterface($pdo);
        $this->manager = new MapManager($pdo, $this->configPath, $cactiInterface);
    }

    public function main($request)
    {
        $action = ":: DEFAULT ::";
        if (isset($request['action'])) {
            $action = strtolower(trim($request['action']));
        }

        if ($this->validateRequest($action, $request)) {
            $this->dispatchRequest($action, $request, null);
        } else {
            print "INPUT VALIDATION FAIL";
        }
    }

    public function makeURL($params, $altURL = "")
    {
        $baseURL = $this->myURL;
        if ($altURL != "") {
            $baseURL = $altURL;
        }
        $url = $baseURL . (strpos($this->myURL, '?') === false ? '?' : '&');

        $parts = array();
        foreach ($params as $name => $value) {
            $parts [] = urlencode($name) . "=" . urlencode($value);
        }
        $url .= join("&", $parts);

        return $url;
    }

    public function handleMapListAPI($request, $appObject)
    {
        header('Content-type: application/json');

        $userId = $this->manager->application->getCurrentUserId();
        $mapList = $this->manager->getMapsForUser($userId);
        $groups = $this->manager->getGroups();

        // filter groups to only contain groups used in $mapList
        // (no leaking other groups - could be things like customer or project names)

        $seenGroup = array();
        foreach ($mapList as $map) {
            $seenGroup[$map->group_id] = 1;
        }
        $newGroups = array();
        foreach ($groups as $group) {
            if (array_key_exists($group->id, $seenGroup)) {
                $newGroups [] = $group;
            }
        }

        $data = array(
            'maps' => $mapList,
            'groups' => $newGroups
        );

        print json_encode($data);
    }

    public function handleSettingsAPI($request, $appObject)
    {
        header('Content-type: application/json');

        $styleTextOptions = array("thumbs", "full", "full-first-only");
        $trueFalseLookup = array(false, true);

        $style = $this->manager->application->getAppSetting("weathermap_pagestyle", 0);

        $cycleTime = $this->manager->application->getAppSetting("weathermap_cycle_refresh", 0);
        if ($cycleTime == 0) {
            $cycleTime = 'auto';
        }

        $showAllMapsTab = $this->manager->application->getAppSetting("weathermap_all_tab", 0);
        $showMapSelector = $this->manager->application->getAppSetting("weathermap_map_selector", 0);

        $data = array(
            'wm_version' => WEATHERMAP_VERSION,
            'page_style' => $styleTextOptions[$style],
            'cycle_time' => (string)$cycleTime,
            'show_all_tab' => $trueFalseLookup[$showAllMapsTab],
            'map_selector' => $trueFalseLookup[$showMapSelector],
            'thumb_url' => $this->makeURL(array("action" => "viewthumb")) . "&id=",
            'image_url' => $this->makeURL(array("action" => "viewimage")) . "&id=",
            'html_url' => $this->makeURL(array("action" => "viewhtml")) . "&id=",
            'editor_url' => $this->editorURL,
            'maps_url' => $this->makeURL(array("action" => "maplist")),
            'docs_url' => 'docs/index.html',
            'management_url' => null
        );

        // only pass the managementURL if the user can manage
        if ($this->isWeathermapAdmin()) {
            $data['management_url'] = $this->managementURL;
        }

        print json_encode($data);
    }

    public function handleBigThumb($request, $appObject)
    {
        $this->outputMapImage($request['id'], ".thumb.");
    }

    public function handleLittleThumb($request, $appObject)
    {
        $this->outputMapImage($request['id'], ".thumb48.");
    }

    public function handleImage($request, $appObject)
    {
        $this->outputMapImage($request['id'], ".");
    }

    public function handleHTML($request, $appObject)
    {
        $this->outputMapHTML($request['id']);
    }

    protected function isWeathermapAdmin()
    {
        global $user_auth_realm_filenames;

        $realmId = 0;
        $realmName = $this->managementRealm;

        if (isset($user_auth_realm_filenames[$realmName])) {
            $realmId = $user_auth_realm_filenames[$realmName];
        }
        $userid = (isset($_SESSION["sess_user_id"]) ? intval($_SESSION["sess_user_id"]) : 1);
        $allowed = $this->manager->application->checkUserAccess($userid, $realmId);

        if ($allowed || (empty($realmId))) {
            return true;
        }

        return false;
    }


    public function handleDefaultView($request, $appObject)
    {
        global $wm_showOldUI, $config;

        $weathermapPath = $config['url_path'] . 'plugins/weathermap/';
        $cactiResourcePath = $weathermapPath . 'cacti-resources/';

        $this->cactiHeader();

        if ($wm_showOldUI) {
            print "This will all be replaced.";

            $pageStyle = $this->manager->application->getAppSetting("weathermap_pagestyle", 0);
            $userId = $this->manager->application->getCurrentUserId();
            $limitToGroup = $this->getGroupFilter($request);

            $mapList = $this->manager->getMapsForUser($userId, $limitToGroup);

            // "First-only" style
            if ($pageStyle == 2) {
                $mapList = array($mapList[0]);
            }
            $mapCount = count($mapList);

            $this->outputMapHeader($mapList, false, $limitToGroup);

            if ($pageStyle == 0 && $mapCount > 1) {
                $this->drawThumbnailView($mapList);
            } else {
                $this->drawFullMapView($mapList);
            }

            if ($mapCount == 0) {
                print "<div align=\"center\" style=\"padding:20px\"><em>You Have No Maps</em></div>\n";
            }
        }

        // get the locale from host app
        $locale = $this->manager->application->getLocale();

        print "<small>This is the React UI below here</small>";
        print "<h1>INCOMPLETE</h1>";
        print '<style>@import "' . $cactiResourcePath . 'user/main.css"</style>';
        print '<script type="text/javascript" src="' . $weathermapPath . 'overlib.js"></script>';

        print "<div id='weathermap-user-root' data-locale='" . $locale . "' data-url='" . $this->makeURL(array("action" => "settings")) . "'></div>";
        print '<script type="text/javascript" src="' . $cactiResourcePath . 'user/main.js"></script>';

        print "<hr />";

        if ($wm_showOldUI) {
            $this->outputVersionBox();
        }

        $this->cactiFooter();
    }


    // ***********************************************************************************************
    // Below here are the old server-side functions that are replaced by client components


    public function handleViewMap($request, $appObject)
    {
        print "Unimplemented map view";
    }

    public function handleViewCycleFullscreen($request, $appObject)
    {
        print "Unimplemented handleViewCycleFullscreen";
    }

    public function handleViewCycleFilteredFullscreen($request, $appObject)
    {
        print "Unimplemented handleViewCycleFilteredFullscreen";
    }

    public function handleViewCycle($request, $appObject)
    {
        print "Unimplemented handleViewCycle";
    }

    public function handleViewCycleFiltered($request, $appObject)
    {
        print "Unimplemented handleViewCycleFiltered";
    }


    /**
     * Figure out which tab to show in the main view. If one was requested, use that. Otherwise use the first one.
     *
     * @param $request
     * @return int
     */
    protected function getGroupFilter($request)
    {
        $tabs = $this->getValidTabs();
        $tabIDs = array_keys($tabs);

        $limitToGroup = $this->getRequiredGroup($request);
        // XXX - will this ever be true?
        if (($limitToGroup == -1) && (count($tabIDs) > 0)) {
            $limitToGroup = $tabIDs[0];
        }
        return $limitToGroup;
    }

    /**
     * If a request has a group specified, use it.
     * If it doesn't see if we have stored a previously requested group.
     *
     * @param $request
     * @return int
     */
    protected function getRequiredGroup($request)
    {
        $groupID = -1;
        if (isset($request['group_id'])) {
            $groupID = $request['group_id'];
            $this->manager->application->setAppSetting("wm_last_group", $groupID);
            return $groupID;
        }

        return $this->manager->application->getAppSetting("wm_last_group", $groupID);
    }

    protected function getValidTabs()
    {
        $tabs = array();

        $maps = $this->manager->getMapsWithAccessAndGroups($this->manager->application->getCurrentUserId());

        foreach ($maps as $map) {
            $tabs[$map->group_id] = $map->name;
        }

        return $tabs;
    }


    protected function outputVersionBox()
    {
        $pageFooter = "Powered by <a href=\"http://www.network-weathermap.com/?v=" . WEATHERMAP_VERSION . "\">"
            . "PHP Weathermap version " . WEATHERMAP_VERSION . "</a>";

        $isAdmin = $this->isWeathermapAdmin();

        if ($isAdmin) {
            $pageFooter .= ' --- <a href="' . $this->managementURL . '" title="Go to the map management page">';
            $pageFooter .= 'Weathermap Management</a> | <a target="_blank" href="docs/index.html">Local Documentation</a>';
            $pageFooter .= ' | <a target="_blank" href="' . $this->editorURL . '">Editor</a>';
        }


        \html_start_box('Weathermap Info', '100%', '', '3', 'center', '');
        ?>
        <tr class='even'>
            <td>
                <table width='100%' cellpadding='0' cellspacing='0'>
                    <tr>
                        <td class='textHeader' nowrap> <?php print $pageFooter; ?> </td>
                    </tr>
                </table>
            </td>
        </tr>
        <?php
        \html_end_box();
    }

    protected function outputMapViewHeader($pageTitle, $isCycling, $limitingToGroup)
    {
        \html_start_box($pageTitle, '100%', '', '3', 'center', '');
        ?>
        <tr class="even">
            <td>
                <table width="100%" cellpadding="0" cellspacing="0">
                    <tr>
                        <td class="textHeader" nowrap> <?php print $pageTitle; ?> </td>
                        <td align="right">
                            <?php
                            if (!$isCycling) {
                                ?>
                                (automatically cycle between full-size maps (<?php

                                if ($limitingToGroup > 0) {
                                    $this->makeURL(
                                        array(
                                            "action" => "viewcycle_filtered",
                                            "group" => $limitingToGroup
                                        )
                                    );
                                    print '<a href = "' . $this->makeURL(
                                            array(
                                                "action" => "viewcycle_filtered",
                                                "group" => $limitingToGroup
                                            )
                                        ) . '">within this group</a>, or ';
                                }
                                print ' <a href = "' . $this->makeURL(array("action" => "viewcycle")) . '">all maps</a>';
                                ?>)
                                <?php
                            }
                            ?>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
        <?php
        \html_end_box();

        $this->outputGroupTabs($limitingToGroup);
    }

    protected function outputGroupTabs($currentTab)
    {
        $tabs = $this->getValidTabs();

        if (count($tabs) > 1) {
            /* draw the categories tabs on the top of the page */
            print "<p></p><table class='tabs' width='100%' cellspacing='0' cellpadding='3' align='center'><tr>\n";

            if (count($tabs) > 0) {
                $showAll = intval($this->manager->application->getAppSetting("weathermap_all_tab", 0));
                if ($showAll == 1) {
                    $tabs['-2'] = "All Maps";
                }

                foreach (array_keys($tabs) as $tabShortName) {
                    print "<td " . (($tabShortName == $currentTab) ? "bgcolor='silver'" : "bgcolor='#DFDFDF'") . " nowrap='nowrap' width='" . (strlen($tabs[$tabShortName]) * 9) . "' align='center' class='tab'>                    <span class='textHeader'><a                    href='" . $this->makeURL(array("group_id" => $tabShortName)) . "'>$tabs[$tabShortName]</a></span>                    </td>\n                    <td width='1'></td>\n";
                }
            }

            print "<td></td>\n</tr></table>\n";

            return true;
        }

        return false;
    }

    private function drawThumbnailView($mapList)
    {
        if (count($mapList) > 0) {
            \html_start_box("", '100%', '', '3', 'center', '');

            print "<tr><td class='wm_gallery'>";
            foreach ($mapList as $map) {
                $this->drawOneThumbnail($map);
            }
            print "</td></tr>";
            \html_end_box();
        }
    }

    private function drawFullMapView($mapList)
    {
        // make sure that we use the Cacti refresh meta tags
        $this->cactiEnableGraphRefresh();

        if (count($mapList) == 0) {
            return;
        }

        print "<div class='all_map_holder'>";

        foreach ($mapList as $map) {
            $this->drawOneFullMap($map);
        }

        print "</div>";
    }

    /**
     * @param $map
     */
    private function drawOneThumbnail($map)
    {
        $imgSize = "";
        $thumbnailFilename = $this->outputDirectory . DIRECTORY_SEPARATOR . $map->filehash . ".thumb." . $this->imageFormat;
        $thumbnailImageURL = $this->makeURL(array("action" => "viewthumb", "id" => $map->filehash, "time" => time()));

        if ($map->thumb_width > 0) {
            $imgSize = sprintf(' WIDTH="%d" HEIGHT="%d" ', $map->thumb_width, $map->thumb_height);
        }
        $mapTitle = $this->getMapTitle($map);
        print '<div class="wm_thumbcontainer" style="margin: 2px; border: 1px solid #bbbbbb; padding: 2px; float:left;">';
        if (file_exists($thumbnailFilename)) {
            print '<div class="wm_thumbtitle" style="font-size: 1.2em; font-weight: bold; text-align: center">' . $mapTitle;

            print '</div><a href="' . $this->makeURL(array("action" => "viewmap", "id" => $map->filehash));
            print '"><img class="wm_thumb" ' . $imgSize . 'src="' . $thumbnailImageURL . '" alt="' . $mapTitle;
            print '" border="0" hspace="5" vspace="5" title="' . $mapTitle . '"/></a>';
        } else {
            print "(thumbnail for map not created yet)";
        }

        print '</div> ';
    }

    private function drawOneFullMap($map)
    {
        $htmlFileName = $this->outputDirectory . DIRECTORY_SEPARATOR . $map->filehash . ".html";
        $mapTitle = $this->getMapTitle($map);
        print '<div class="weathermapholder" id="mapholder_' . $map->filehash . '">';

        \html_start_box(__($mapTitle), '100%', '', '3', 'center', '');

        ?>
        <tr class="even">
            <td colspan="3">
                <table width="100%" cellspacing="0" cellpadding="3" border="0">
                    <tr>
                        <td align="left" class="textHeaderDark">
                            <a name="map_<?php echo $map->filehash; ?>">
                            </a><?php print htmlspecialchars($mapTitle); ?>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
        <tr>
            <td>
        <?php

        if (file_exists($htmlFileName)) {
            readfile($htmlFileName);
        } else {
            print "<div align=\"center\" style=\"padding:20px\"><em>This map hasn't been created yet.</em></div>";
        }

        print '</td></tr>';
        \html_end_box();

        print '</div>';
    }

    private function getMapTitle($map)
    {
        $mapTitle = $map->titlecache;
        if ($mapTitle == '') {
            $mapTitle = "Map for config file: " . $map->configfile;
        }
        return $mapTitle;
    }

    /**
     * @param $mapList
     */
    protected function outputMapHeader($mapList, $cycle, $limitToGroup)
    {
        $pageTitle = __n("Network Weathermap", "Network Weathermaps", count($mapList));

        $this->outputMapViewHeader($pageTitle, $cycle, $limitToGroup);
    }

    /**
     * @param $filehash
     */
    private function outputMapHTML($filehash)
    {
        $mapId = $this->manager->translateFileHash($filehash);
        $userId = $this->manager->application->getCurrentUserId();

        $map = $this->manager->getMapWithAccess($mapId, $userId);

        header('Content-type: text/html');
        if (null === $map) {
            // in the management view, a disabled map will fail the query above, so generate *something*
            print "--";
            return;
        }

        $htmlFileName = $this->outputDirectory . '/' . $filehash . ".html";

        if (file_exists($htmlFileName)) {
            readfile($htmlFileName);
            return;
        }
        print "--";
        return;
    }

    /**
     * @param $filehash
     * @param $fileNameInsert
     */
    private function outputMapImage($filehash, $fileNameInsert)
    {
        $mapId = $this->manager->translateFileHash($filehash);
        $userId = $this->manager->application->getCurrentUserId();

        $map = $this->manager->getMapWithAccess($mapId, $userId);

        header('Content-type: image/png');

        if (null === $map) {
            // in the management view, a disabled map will fail the query above, so generate *something*
            header('Content-type: image/png');
            $this->outputGreyPNG(48, 48);
        }

        $imageFileName = $this->outputDirectory . '/' . $filehash . $fileNameInsert . $this->imageFormat;

        header('Content-type: image/png');

        if (file_exists($imageFileName)) {
            readfile($imageFileName);
            return;
        }

        $this->outputGreyPNG(48, 48);
    }

    private function outputGreyPNG($width, $height)
    {
        $imageRef = imagecreate($width, $height);
        $shade = 240;
        // The first colour allocated becomes the background colour of the image. No need to fill
        imagecolorallocate($imageRef, $shade, $shade, $shade);
        imagepng($imageRef);
    }

    public function cactiEnableGraphRefresh()
    {
        $_SESSION['custom'] = false;
    }

    public function cactiFooter()
    {
        print "OVERRIDE ME";
    }

    public function cactiHeader()
    {
        print "OVERRIDE ME";
    }

    public function cactiRowStart($i)
    {
    }
}