From 75a730c369f1ece65925f21a0524ccb2659a5c08 Mon Sep 17 00:00:00 2001
From: leoncx <leoncx@gmail.com>
Date: Tue, 29 May 2018 11:16:37 +0200
Subject: [PATCH] feat(menu): Add REST Api for menu

* Rest API for menu

Refs: MON2703
---
 src/CentreonLegacy/Core/Menu/Menu.php         | 251 ++++++++++++
 .../php/CentreonLegacy/Core/Menu/MenuTest.php | 364 ++++++++++++++++++
 www/api/class/centreon_menu.class.php         | 132 +++++++
 3 files changed, 747 insertions(+)
 create mode 100644 src/CentreonLegacy/Core/Menu/Menu.php
 create mode 100644 tests/php/CentreonLegacy/Core/Menu/MenuTest.php
 create mode 100644 www/api/class/centreon_menu.class.php

diff --git a/src/CentreonLegacy/Core/Menu/Menu.php b/src/CentreonLegacy/Core/Menu/Menu.php
new file mode 100644
index 0000000000..e79f03620a
--- /dev/null
+++ b/src/CentreonLegacy/Core/Menu/Menu.php
@@ -0,0 +1,251 @@
+<?php
+/**
+ * Copyright 2005-2018 Centreon
+ * Centreon is developped by : Julien Mathis and Romain Le Merlus under
+ * GPL Licence 2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation ; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses>.
+ *
+ * Linking this program statically or dynamically with other modules is making a
+ * combined work based on this program. Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this program give Centreon
+ * permission to link this program with independent modules to produce an executable,
+ * regardless of the license terms of these independent modules, and to copy and
+ * distribute the resulting executable under terms of Centreon choice, provided that
+ * Centreon also meet, for each linked independent module, the terms  and conditions
+ * of the license of that module. An independent module is a module which is not
+ * derived from this program. If you modify this program, you may extend this
+ * exception to your version of the program, but you are not obliged to do so. If you
+ * do not wish to do so, delete this exception statement from your version.
+ *
+ * For more information : contact@centreon.com
+ *
+ */
+
+namespace CentreonLegacy\Core\Menu;
+
+class Menu
+{
+    /**
+     * @var CentreonDB The configuration database connection
+     */
+    protected $db;
+    /**
+     * @var string The query filter for ACL
+     */
+    protected $acl = null;
+
+    /**
+     * Constructor
+     *
+     * @param CentreonDB $db The configuration database connection
+     * @param CentreonUser $user The current user
+     */
+    public function __construct($db, $user = null)
+    {
+        $this->db = $db;
+        if (!is_null($user) && !$user->is_admin) {
+            $this->acl = ' AND topology_page IN (' . $user->access->getTopologyString() . ')';
+        }
+    }
+
+    /**
+     * Get the level one and level two parents for a page id
+     *
+     * For 20101 :
+     * array(
+     *   "levelTwo" => 201,
+     *   "levelOne" => 2
+     * )
+     *
+     * For 201 :
+     * array(
+     *   "levelTwo" => 201,
+     *   "levelOne" => 2
+     * )
+     *
+     * For 2 :
+     * array(
+     *   "levelTwo" => null,
+     *   "levelOne" => 2
+     * )
+     *
+     * @param int $pageId The page id to find parents
+     * @return array The parents
+     */
+    public function getParentsId($pageId)
+    {
+        $firstParent = $this->getParentId($pageId);
+        if (is_null($firstParent)) {
+            return array(
+                'levelOne' => $pageId,
+                'levelTwo' => null
+            );
+        }
+        $secondParent = $this->getParentId($firstParent);
+        if (is_null($secondParent)) {
+            return array(
+                'levelOne' => $firstParent,
+                'levelTwo' => $pageId
+            );
+        }
+        return array(
+            'levelOne' => $secondParent,
+            'levelTwo' => $firstParent
+        );
+    }
+
+    /**
+     * Get the parent id for a page
+     *
+     * @param int $pageId The page id to find parent
+     * @return int The parent page id
+     */
+    public function getParentId($pageId)
+    {
+        $query = 'SELECT topology_parent FROM topology WHERE topology_page = :page';
+        $stmt = $this->db->prepare($query);
+        $stmt->bindParam(':page', $pageId, \PDO::PARAM_INT);
+        $stmt->execute();
+        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+        $parent = null;
+        if ($row) {
+            $parent = $row['topology_parent'];
+        }
+        $stmt->closeCursor();
+        return $parent;
+    }
+
+    /**
+     * Get the level three menu
+     *
+     * Without groups
+     *
+     * array(
+     *   array(
+     *     "id" => "201",
+     *     "label" => "My menu",
+     *     "url" => "http://page"
+     *   )
+     * )
+     *
+     * With groups
+     *
+     * array(
+     *   array(
+     *     "id" => "212",
+     *     "label" => "",
+     *     "children" => array(
+     *       array(
+     *         "id" => "201",
+     *         "label" => "My menu",
+     *         "url" => "http://page"
+     *       )
+     *     )
+     *   )
+     * )
+     *
+     * @param int $parentId The parent id
+     * @return array The menu
+     */
+    public function getMenuChildren($parentId = null)
+    {
+        /* Load groups */
+        $groups = $this->getGroups($parentId);
+
+        $query = 'SELECT topology_name, topology_page, topology_url, topology_group FROM topology
+            WHERE topology_show = "1" AND topology_page IS NOT NULL';
+        if (is_null($parentId)) {
+            $query .= ' AND topology_parent IS NULL';
+        } else {
+            $query .= ' AND topology_parent = :parent';
+        }
+
+        if (!is_null($this->acl)) {
+            $query .= $this->acl;
+        }
+        $query .= ' ORDER BY topology_group, topology_order';
+        $stmt = $this->db->prepare($query);
+        if (!is_null($parentId)) {
+            $stmt->bindParam(':parent', $parentId, \PDO::PARAM_INT);
+        }
+
+        $stmt->execute();
+
+        $menu = array();
+
+        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+            $item = array(
+                'id' => $row['topology_page'],
+                'label' => $row['topology_name'],
+                'url' => $row['topology_url']
+            );
+            if (is_null($row['topology_group'])) {
+                $menu[] = $item;
+            } else {
+                /* Find the good group */
+                $found = false;
+                for ($i = 0; $i < count($menu); $i++) {
+                    if ($menu[$i]['id'] === $row['topology_group'] && isset($menu[$i]['children'])) {
+                        $found = true;
+                        $menu[$i]['children'][] = $item;
+                    }
+                }
+                /* If not found add the group with the menu item */
+                if (!$found) {
+                    if (isset($groups[$row['topology_group']])) {
+                        $menu[] = array(
+                            'id' => $row['topology_group'],
+                            'label' => $groups[$row['topology_group']],
+                            'children' => array($item)
+                        );
+                    } else {
+                        $menu[] = $item;
+                    }
+                }
+            }
+        }
+        $stmt->closeCursor();
+        return $menu;
+    }
+
+    /**
+     * Get the list of groups
+     *
+     * @param int $parentId The parent id
+     * @return array The list of groups
+     */
+    public function getGroups($parentId = null)
+    {
+        $query = 'SELECT topology_name, topology_group FROM topology
+            WHERE topology_show = "1" AND topology_page IS NULL AND topology_parent = :parent
+            ORDER BY topology_group, topology_order';
+        $stmt = $this->db->prepare($query);
+        if (is_null($parentId)) {
+            $stmt->bindValue(':parent', null, \PDO::PARAM_NULL);
+        } else {
+            $stmt->bindParam(':parent', $parentId, \PDO::PARAM_INT);
+        }
+
+        $stmt->execute();
+        $groups = array();
+
+        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+            $groups[$row['topology_group']] = $row['topology_name'];
+        }
+        $stmt->closeCursor();
+
+        return $groups;
+    }
+}
diff --git a/tests/php/CentreonLegacy/Core/Menu/MenuTest.php b/tests/php/CentreonLegacy/Core/Menu/MenuTest.php
new file mode 100644
index 0000000000..5a2c88b5d4
--- /dev/null
+++ b/tests/php/CentreonLegacy/Core/Menu/MenuTest.php
@@ -0,0 +1,364 @@
+<?php
+/**
+ * Copyright 2005-2018 Centreon
+ * Centreon is developped by : Julien Mathis and Romain Le Merlus under
+ * GPL Licence 2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation ; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses>.
+ *
+ * Linking this program statically or dynamically with other modules is making a
+ * combined work based on this program. Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this program give Centreon
+ * permission to link this program with independent modules to produce an executable,
+ * regardless of the license terms of these independent modules, and to copy and
+ * distribute the resulting executable under terms of Centreon choice, provided that
+ * Centreon also meet, for each linked independent module, the terms  and conditions
+ * of the license of that module. An independent module is a module which is not
+ * derived from this program. If you modify this program, you may extend this
+ * exception to your version of the program, but you are not obliged to do so. If you
+ * do not wish to do so, delete this exception statement from your version.
+ *
+ * For more information : contact@centreon.com
+ *
+ */
+
+namespace CentreonLegacy\Core\Menu;
+
+use \Centreon\Test\Mock\CentreonDB;
+
+class MenuTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var CentreonDb The database mock
+     */
+    private $db;
+
+    public function setUp()
+    {
+        $this->db = new CentreonDB();
+    }
+
+    public function testGetParentIdHasParent()
+    {
+        /* Test has a parent id */
+        $this->db->addResultSet(
+            'SELECT topology_parent FROM topology WHERE topology_page = :page',
+            array(
+                array(
+                    'topology_parent' => 2
+                )
+            ),
+            array(
+                ':page' => 201
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertEquals($menu->getParentId(201), 2);
+    }
+
+    public function testGetParentIdHasNotParent()
+    {
+        /* Test has a parent id */
+        $this->db->addResultSet(
+            'SELECT topology_parent FROM topology WHERE topology_page = :page',
+            array(
+                array(
+                    'topology_parent' => null
+                )
+            ),
+            array(
+                ':page' => 201
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertNull($menu->getParentId(201));
+    }
+
+    public function testGetParentsIdLevelThree()
+    {
+        $this->db->addResultSet(
+            'SELECT topology_parent FROM topology WHERE topology_page = :page',
+            array(
+                array(
+                    'topology_parent' => 201
+                )
+            ),
+            array(
+                ':page' => 20101
+            )
+        );
+        $this->db->addResultSet(
+            'SELECT topology_parent FROM topology WHERE topology_page = :page',
+            array(
+                array(
+                    'topology_parent' => 2
+                )
+            ),
+            array(
+                ':page' => 201
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertEquals(
+            $menu->getParentsId(20101),
+            array(
+                'levelOne' => 2,
+                'levelTwo' => 201
+            )
+        );
+    }
+
+    public function testGetParentsIdLevelTwo()
+    {
+        $this->db->addResultSet(
+            'SELECT topology_parent FROM topology WHERE topology_page = :page',
+            array(
+                array(
+                    'topology_parent' => 2
+                )
+            ),
+            array(
+                ':page' => 201
+            )
+        );
+        $this->db->addResultSet(
+            'SELECT topology_parent FROM topology WHERE topology_page = :page',
+            array(
+                array(
+                    'topology_parent' => null
+                )
+            ),
+            array(
+                ':page' => 2
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertEquals(
+            $menu->getParentsId(201),
+            array(
+                'levelOne' => 2,
+                'levelTwo' => 201
+            )
+        );
+    }
+
+    public function testGetParentsIdLevelOne()
+    {
+        $this->db->addResultSet(
+            'SELECT topology_parent FROM topology WHERE topology_page = :page',
+            array(
+                array(
+                    'topology_parent' => null
+                )
+            ),
+            array(
+                ':page' => 2
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertEquals(
+            $menu->getParentsId(2),
+            array(
+                'levelOne' => 2,
+                'levelTwo' => null
+            )
+        );
+    }
+
+    public function testGetGroupsWithParentNull()
+    {
+        $this->db->addResultSet(
+            'SELECT topology_name, topology_group FROM topology
+            WHERE topology_show = "1" AND topology_page IS NULL AND topology_parent = :parent
+            ORDER BY topology_group, topology_order',
+            array(
+                array(
+                    'topology_name' => 'By host',
+                    'topology_group' => 201
+                ),
+                array(
+                    'topology_name' => 'By services',
+                    'topology_group' => 202
+                )
+            ),
+            array(
+                ':parent' => null
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertEquals(
+            $menu->getGroups(),
+            array(
+                201 => 'By host',
+                202 => 'By services'
+            )
+        );
+    }
+
+    public function testGetGroupsWithParentNotNull()
+    {
+        $this->db->addResultSet(
+            'SELECT topology_name, topology_group FROM topology
+            WHERE topology_show = "1" AND topology_page IS NULL AND topology_parent = :parent
+            ORDER BY topology_group, topology_order',
+            array(
+                array(
+                    'topology_name' => 'By host',
+                    'topology_group' => 201
+                ),
+                array(
+                    'topology_name' => 'By services',
+                    'topology_group' => 202
+                )
+            ),
+            array(
+                ':parent' => 2
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertEquals(
+            $menu->getGroups(2),
+            array(
+                201 => 'By host',
+                202 => 'By services'
+            )
+        );
+    }
+
+    public function testGetMenuChildrenLevelOne()
+    {
+        $this->db->addResultSet(
+            'SELECT topology_name, topology_group FROM topology
+            WHERE topology_show = "1" AND topology_page IS NULL AND topology_parent = :parent
+            ORDER BY topology_group, topology_order',
+            array(),
+            array(
+                ':parent' => null
+            )
+        );
+        $this->db->addResultSet(
+            'SELECT topology_name, topology_page, topology_url, topology_group FROM topology
+            WHERE topology_show = "1" AND topology_page IS NOT NULL AND topology_parent IS NULL ORDER BY topology_group, topology_order',
+            array(
+                array(
+                    'topology_name' => 'Home',
+                    'topology_page' => 1,
+                    'topology_url' => 'main.php?p=1',
+                    'topology_group' => null
+                ),
+                array(
+                    'topology_name' => 'Monitoring',
+                    'topology_page' => 2,
+                    'topology_url' => 'main.php?p=2',
+                    'topology_group' => null
+                )
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertEquals(
+            $menu->getMenuChildren(),
+            array(
+                array(
+                    'id' => 1,
+                    'label' => 'Home',
+                    'url' => 'main.php?p=1'
+                ),
+                array(
+                    'id' => 2,
+                    'label' => 'Monitoring',
+                    'url' => 'main.php?p=2'
+                )
+            )
+        );
+    }
+
+    public function testGetMenuChildrenLevelThreeWithGroups()
+    {
+        $this->db->addResultSet(
+            'SELECT topology_name, topology_group FROM topology
+            WHERE topology_show = "1" AND topology_page IS NULL AND topology_parent = :parent
+            ORDER BY topology_group, topology_order',
+            array(
+                array(
+                    'topology_name' => 'By host',
+                    'topology_group' => 201
+                ),
+                array(
+                    'topology_name' => 'By services',
+                    'topology_group' => 202
+                )
+            ),
+            array(
+                ':parent' => 2
+            )
+        );
+        $this->db->addResultSet(
+            'SELECT topology_name, topology_page, topology_url, topology_group FROM topology
+            WHERE topology_show = "1" AND topology_page IS NOT NULL AND topology_parent = :parent ORDER BY topology_group, topology_order',
+            array(
+                array(
+                    'topology_name' => 'Status',
+                    'topology_page' => 20101,
+                    'topology_url' => 'main.php?p=20101',
+                    'topology_group' => 201
+                ),
+                array(
+                    'topology_name' => 'Status by group',
+                    'topology_page' => 20102,
+                    'topology_url' => 'main.php?p=20102',
+                    'topology_group' => 201
+                ),
+                array(
+                    'topology_name' => 'Status',
+                    'topology_page' => 20201,
+                    'topology_url' => 'main.php?p=20201',
+                    'topology_group' => 202
+                )
+            )
+        );
+        $menu = new Menu($this->db);
+        $this->assertEquals(
+            $menu->getMenuChildren(2),
+            array(
+                array(
+                    'id' => 201,
+                    'label' => 'By host',
+                    'children' => array(
+                        array(
+                            'id' => 20101,
+                            'label' => 'Status',
+                            'url' => 'main.php?p=20101'
+                        ),
+                        array(
+                            'id' => 20102,
+                            'label' => 'Status by group',
+                            'url' => 'main.php?p=20102'
+                        )
+                    )
+                ),
+                array(
+                    'id' => 202,
+                    'label' => 'By services',
+                    'children' => array(
+                        array(
+                            'id' => 20201,
+                            'label' => 'Status',
+                            'url' => 'main.php?p=20201'
+                        )
+                    )
+                )
+            )
+        );
+    }
+}
diff --git a/www/api/class/centreon_menu.class.php b/www/api/class/centreon_menu.class.php
new file mode 100644
index 0000000000..ffeca16eca
--- /dev/null
+++ b/www/api/class/centreon_menu.class.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * Copyright 2005-2018 Centreon
+ * Centreon is developped by : Julien Mathis and Romain Le Merlus under
+ * GPL Licence 2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation ; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses>.
+ *
+ * Linking this program statically or dynamically with other modules is making a
+ * combined work based on this program. Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this program give Centreon
+ * permission to link this program with independent modules to produce an executable,
+ * regardless of the license terms of these independent modules, and to copy and
+ * distribute the resulting executable under terms of Centreon choice, provided that
+ * Centreon also meet, for each linked independent module, the terms  and conditions
+ * of the license of that module. An independent module is a module which is not
+ * derived from this program. If you modify this program, you may extend this
+ * exception to your version of the program, but you are not obliged to do so. If you
+ * do not wish to do so, delete this exception statement from your version.
+ *
+ * For more information : contact@centreon.com
+ *
+ */
+
+use CentreonLegacy\Core\Menu\Menu;
+
+require_once dirname(__FILE__) . "/webService.class.php";
+
+class CentreonMenu extends CentreonWebService
+{
+    /**
+     * Get the init menu on loading page
+     *
+     * Argument:
+     *   page -> int - The current page
+     *
+     * Method: GET
+     */
+    public function getInitMenu()
+    {
+        if (!isset($_SESSION['centreon'])) {
+            throw new \RestUnauthorizedException('Session does not exists.');
+        }
+
+        if (!isset($this->arguments['page']) || !is_numeric($this->arguments['page'])) {
+            throw new \RestBadRequestException('Missing type argument or bad type page.');
+        }
+        $page = $this->arguments['page'];
+
+        $menu = new Menu($this->pearDB, $_SESSION['centreon']->user);
+
+        $parents = $menu->getParentsId($page);
+
+        /* Build the base menu tree on getting the menu level one */
+        $menuTree = $menu->getMenuChildren();
+        for ($i = 0; $i < count($menuTree); $i++) {
+            /* Default additional values */
+            $menuTree[$i]['children'] = array();
+            $menuTree[$i]['active'] = false;
+            if ($menuTree[$i]['id'] === $parents['levelOne']) {
+                $menuTree[$i]['active'] = true;
+                /* Get level two menu if page has level 2 */
+                if (!is_null($parents['levelTwo'])) {
+                    $menuTree[$i]['children'] = $menu->getMenuChildren($parents['levelOne']);
+                    for ($j = 0; $j < count($menuTree[$i]['children']); $j++) {
+                        /* Default additional values */
+                        $menuTree[$i]['children'][$j]['active'] = false;
+                        $menuTree[$i]['children'][$j]['children'] = array();
+                        if ($menuTree[$i]['children'][$j]['id'] === $parents['levelTwo']) {
+                            $menuTree[$i]['children'][$j]['active'] = true;
+                            $menuTree[$i]['children'][$j]['children'] = $menu->getMenuChildren($parents['levelTwo']);
+                            /* Search the current activated */
+                            for ($k = 0; $k < count($menuTree[$i]['children'][$j]['children']); $k++) {
+                                $active = false;
+                                /* Test if a group */
+                                if (is_array($menuTree[$i]['children'][$j]['children'][$k]['children'])) {
+                                    for ($l = 0;
+                                        $l < count($menuTree[$i]['children'][$j]['children'][$k]['children']);
+                                        $l++) {
+                                        if ($menuTree[$i]['children'][$j]['children'][$k]['children'][$l]['id'] === $page) {
+                                            $menuTree[$i]['children'][$j]['children'][$k]['children'][$l]['active'] = true;
+                                        } else {
+                                            $menuTree[$i]['children'][$j]['children'][$k]['children'][$l]['active'] = false;
+                                        }
+                                    }
+                                } else if ($menuTree[$i]['children'][$j]['children'][$k]['id'] === $page) {
+                                    $active = true;
+                                }
+                                $menuTree[$i]['children'][$j]['children'][$k]['active'] = $active;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return $menuTree;
+    }
+
+    /**
+     * Get menu children
+     *
+     * Argument:
+     *   parent -> int - The id of level parent
+     *
+     * Method: GET
+     */
+    public function getMenuChildren()
+    {
+        if (!isset($_SESSION['centreon'])) {
+            throw new \RestUnauthorizedException('Session does not exists.');
+        }
+
+        if (!isset($this->arguments['parent']) || !is_numeric($this->arguments['parent'])) {
+            throw new \RestBadRequestException('Missing type argument or bad type parent.');
+        }
+
+        $menu = new Menu($this->pearDB, $_SESSION['centreon']->user);
+
+        return $menu->getMenuChildren($this->arguments['parent']);
+    }
+}
-- 
GitLab