* @package common
* @version $Id$
* @link http://www.zentao.net
*/
class commonModel extends model
{
static public $requestErrors = array();
/**
* The construc method, to do some auto things.
*
* @access public
* @return void
*/
public function __construct()
{
parent::__construct();
if(!defined('FIRST_RUN'))
{
define('FIRST_RUN', true);
$this->sendHeader();
$this->setCompany();
$this->setUser();
$this->setApproval();
$this->loadConfigFromDB();
$this->app->setTimezone();
$this->loadCustomFromDB();
if(!$this->checkIP()) return print($this->lang->ipLimited);
$this->app->loadLang('company');
}
}
/**
* Set the status of execution, project, and program to doing.
*
* @param int $objectID
* @access public
* @return void
*/
public function syncPPEStatus($objectID)
{
global $app;
$rawModule = $app->rawModule;
if($rawModule == 'task' or $rawModule == 'effort')
{
$taskID = $objectID;
$execution = $this->syncExecutionStatus($taskID);
$project = $this->syncProjectStatus($execution);
$this->syncProgramStatus($project);
}
if($rawModule == 'execution')
{
$executionID = $objectID;
$execution = $this->dao->select('id, project, grade, parent, status, deleted')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->fetch();
$this->syncExecutionByChild($execution);
$project = $this->syncProjectStatus($execution);
$this->syncProgramStatus($project);
}
if($rawModule == 'project')
{
$projectID = $objectID;
$project = $this->dao->select('id, parent, path')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetch();
$this->syncProgramStatus($project);
}
if($rawModule == 'program' and $this->config->systemMode == 'ALM')
{
$programID = $objectID;
$program = $this->dao->select('id, parent, path')->from(TABLE_PROGRAM)->where('id')->eq($programID)->fetch();
$this->syncProgramStatus($program);
}
}
/**
* Set the status of the program to which theproject is linked as Ongoing.
*
* @param object $project
* @access public
* @return void
*/
public function syncProgramStatus($project)
{
if($project->parent == 0) return;
$parentPath = str_replace(",{$project->id},", '', $project->path);
$parentPath = explode(',', trim($parentPath, ','));
$waitList = $this->dao->select('id')->from(TABLE_PROGRAM)
->where('id')->in($parentPath)
->andWhere('status')->eq('wait')
->orderBy('id_desc')
->fetchPairs();
$now = helper::now();
$this->dao->update(TABLE_PROGRAM)->set('status')->eq('doing')->set('realBegan')->eq($now)->where('id')->in($waitList)->exec();
foreach($waitList as $programID)
{
$this->loadModel('action')->create('program', $programID, 'syncprogram');
}
}
/**
* Set the status of the project to which the execution is linked as Ongoing.
*
* @param object $execution
* @access public
* @return object $project
*/
public function syncProjectStatus($execution)
{
$projectID = $execution->project;
$project = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetch();
$today = helper::today();
if($project->status == 'wait')
{
$this->dao->update(TABLE_PROJECT)
->set('status')->eq('doing')
->beginIf(helper::isZeroDate($project->realBegan))->set('realBegan')->eq($today)->fi()
->where('id')->eq($projectID)
->exec();
$actionType = $project->multiple ? 'syncproject' : 'syncmultipleproject';
$this->loadModel('action')->create('project', $projectID, $actionType);
}
return $project;
}
/**
* Set the status of the execution to which the sub execution is linked as Ongoing.
*
* @param object $execution
* @access public
* @return object $parentExecution
*/
public function syncExecutionByChild($execution)
{
if($execution->grade == 1) return false;
$parentExecutionID = $execution->parent;
$today = helper::today();
$parentExecution = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->eq($parentExecutionID)->fetch();
if($execution->deleted == '0' and $execution->status == 'doing' and in_array($parentExecution->status, array('wait', 'closed')))
{
$this->dao->update(TABLE_EXECUTION)
->set('status')->eq('doing')
->beginIf(helper::isZeroDate($parentExecution->realBegan))->set('realBegan')->eq($today)->fi()
->where('id')->eq($parentExecutionID)
->exec();
$this->loadModel('action')->create('execution', $parentExecutionID, 'syncexecutionbychild');
}
$project = $this->loadModel('project')->getByID($execution->project);
if($project->model == 'waterfall' or $project->model == 'waterfallplus') $this->loadModel('programplan')->computeProgress($execution->id);
return $parentExecution;
}
/**
* Set the status of the execution to which the task is linked as Ongoing.
*
* @param int $taskID
* @access public
* @return object $execution
*/
public function syncExecutionStatus($taskID)
{
$execution = $this->dao->select('t1.*')->from(TABLE_EXECUTION)->alias('t1')
->leftJoin(TABLE_TASK)->alias('t2')->on('t1.id=t2.execution')
->where('t2.id')->eq($taskID)
->fetch();
$today = helper::today();
if($execution->status == 'wait')
{
$this->dao->update(TABLE_EXECUTION)->set('status')->eq('doing')->set('realBegan')->eq($today)->where('id')->eq($execution->id)->exec();
$this->loadModel('action')->create('execution', $execution->id, 'syncexecution');
if($execution->parent)
{
$execution = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->eq($execution->id)->fetch(); // Get updated execution.
$this->syncExecutionByChild($execution);
}
}
return $execution;
}
/**
* Set the header info.
*
* @access public
* @return void
*/
public function sendHeader()
{
header("Content-Type: text/html; Language={$this->config->charset}");
header("Cache-control: private");
/* Send HTTP header. */
if($this->config->framework->sendXCTO) header("X-Content-Type-Options: nosniff");
if($this->config->framework->sendXXP) header("X-XSS-Protection: 1; mode=block");
if($this->config->framework->sendHSTS) header("Strict-Transport-Security: max-age=3600; includeSubDomains");
if($this->config->framework->sendRP) header("Referrer-Policy: no-referrer-when-downgrade");
if($this->config->framework->sendXPCDP) header("X-Permitted-Cross-Domain-Policies: master-only");
if($this->config->framework->sendXDO) header("X-Download-Options: noopen");
/* Set Content-Security-Policy header. */
if($this->config->CSPs)
{
foreach($this->config->CSPs as $CSP) header("Content-Security-Policy: $CSP;");
}
if($this->loadModel('setting')->getItem('owner=system&module=sso&key=turnon'))
{
if(isset($_SERVER["HTTPS"]) and $_SERVER["HTTPS"] == 'on')
{
$session = $this->config->sessionVar . '=' . session_id();
header("Set-Cookie: $session; SameSite=None; Secure=true", false);
}
}
else
{
if(!empty($this->config->xFrameOptions)) header("X-Frame-Options: {$this->config->xFrameOptions}");
}
}
/**
* Set the commpany.
*
* First, search company by the http host. If not found, search by the default domain. Last, use the first as the default.
* After get the company, save it to session.
* @access public
* @return void
*/
public function setCompany()
{
$httpHost = $this->server->http_host;
if($this->session->company)
{
$this->app->company = $this->session->company;
}
else
{
$company = $this->loadModel('company')->getFirst();
if(!$company) $this->app->triggerError(sprintf($this->lang->error->companyNotFound, $httpHost), __FILE__, __LINE__, $exit = true);
$this->session->set('company', $company);
$this->app->company = $company;
}
}
/**
* Set the user info.
*
* @access public
* @return void
*/
public function setUser()
{
if($this->session->user)
{
if(!defined('IN_UPGRADE')) $this->session->user->view = $this->loadModel('user')->grantUserView();
$this->app->user = $this->session->user;
}
elseif($this->app->company->guest or PHP_SAPI == 'cli')
{
$user = new stdClass();
$user->id = 0;
$user->account = 'guest';
$user->realname = 'guest';
$user->dept = 0;
$user->avatar = '';
$user->role = 'guest';
$user->admin = false;
$user->rights = $this->loadModel('user')->authorize('guest');
$user->groups = array('group');
$user->visions = $this->config->vision;
if(!defined('IN_UPGRADE')) $user->view = $this->user->grantUserView($user->account, $user->rights['acls']);
$this->session->set('user', $user);
$this->app->user = $this->session->user;
}
}
/**
* Set approval config.
*
* @access public
* @return void
*/
public function setApproval()
{
$this->config->openedApproval = false;
if($this->config->edition == 'max' && $this->config->vision == 'rnd') $this->config->openedApproval = true;
}
/**
* Load configs from database and save it to config->system and config->personal.
*
* @access public
* @return void
*/
public function loadConfigFromDB()
{
/* Get configs of system and current user. */
$account = isset($this->app->user->account) ? $this->app->user->account : '';
if($this->config->db->name) $config = $this->loadModel('setting')->getSysAndPersonalConfig($account);
$this->config->system = isset($config['system']) ? $config['system'] : array();
$this->config->personal = isset($config[$account]) ? $config[$account] : array();
/* Overide the items defined in config/config.php and config/my.php. */
if(isset($this->config->system->common)) $this->app->mergeConfig($this->config->system->common, 'common');
if(isset($this->config->personal->common)) $this->app->mergeConfig($this->config->personal->common, 'common');
$this->config->disabledFeatures = $this->config->disabledFeatures . ',' . $this->config->closedFeatures;
}
/**
* Load custom lang from db.
*
* @access public
* @return void
*/
public function loadCustomFromDB()
{
$this->loadModel('custom');
if(defined('IN_UPGRADE')) return;
if(!$this->config->db->name) return;
$records = $this->custom->getAllLang();
if(!$records) return;
$this->lang->db = new stdclass();
$this->lang->db->custom = $records;
}
/**
* Juage a method of one module is open or not?
*
* @param string $module
* @param string $method
* @access public
* @return bool
*/
public function isOpenMethod($module, $method)
{
if(in_array("$module.$method", $this->config->openMethods)) return true;
if($module == 'block' and $method == 'main' and isset($_GET['hash'])) return true;
if($this->loadModel('user')->isLogon() or ($this->app->company->guest and $this->app->user->account == 'guest'))
{
if(stripos($method, 'ajax') !== false) return true;
if($module == 'block') return true;
if($module == 'my' and $method == 'guidechangetheme') return true;
if($module == 'misc' and $method == 'downloadclient') return true;
if($module == 'misc' and $method == 'changelog') return true;
if($module == 'tutorial' and $method == 'start') return true;
if($module == 'tutorial' and $method == 'index') return true;
if($module == 'tutorial' and $method == 'quit') return true;
if($module == 'tutorial' and $method == 'wizard') return true;
if($module == 'product' and $method == 'showerrornone') return true;
}
return false;
}
/**
* Deny access.
*
* @param string $module
* @param string $method
* @param bool $reload
* @access public
* @return mixed
*/
public function deny($module, $method, $reload = true)
{
if($reload)
{
/* Get authorize again. */
$user = $this->app->user;
$user->rights = $this->loadModel('user')->authorize($user->account);
$user->groups = $this->user->getGroups($user->account);
$user->admin = strpos($this->app->company->admins, ",{$user->account},") !== false;
$this->session->set('user', $user);
$this->app->user = $this->session->user;
if(commonModel::hasPriv($module, $method)) return true;
}
$vars = "module=$module&method=$method";
if(isset($this->server->http_referer))
{
$referer = helper::safe64Encode($this->server->http_referer);
$vars .= "&referer=$referer";
}
$denyLink = helper::createLink('user', 'deny', $vars);
/* Fix the bug of IE: use js locate, can't get the referer. */
if(strpos($this->server->http_user_agent, 'Trident') !== false)
{
echo "deny";
echo "";
}
else
{
echo js::locate($denyLink);
}
helper::end();
}
/**
* Print the run info.
*
* @param mixed $startTime the start time.
* @access public
* @return array the run info array.
*/
public function printRunInfo($startTime)
{
$info['timeUsed'] = round(getTime() - $startTime, 4) * 1000;
$info['memory'] = round(memory_get_peak_usage() / 1024, 1);
$info['querys'] = count(dao::$querys);
vprintf($this->lang->runInfo, $info);
return $info;
}
/**
* Print top bar.
*
* @static
* @access public
* @return void
*/
public static function printUserBar()
{
global $lang, $app;
if(isset($app->user))
{
$isGuest = $app->user->account == 'guest';
echo "
';
echo "";
echo html::avatar($app->user);
echo '';
echo '';
}
}
/**
* Print vision switcher.
*
* @static
* @access public
* @return void
*/
public static function printVisionSwitcher()
{
global $lang, $app, $config;
if(isset($app->user))
{
if(!isset($app->user->visions)) $app->user->visions = trim($config->visions, ',');
$currentVision = $app->config->vision;
$userVisions = array_filter(explode(',', $app->user->visions));
$configVisions = array_filter(explode(',', trim($config->visions, ',')));
/* The standalone lite version removes the lite interface button */
if(trim($config->visions, ',') == 'lite') return true;
if(count($userVisions) < 2) return print("{$lang->visionList[$currentVision]}
");
if(count($configVisions) < 2) return print("{$lang->visionList[$currentVision]}
");
echo "';
echo "";
echo "{$lang->visionList[$currentVision]}
";
echo '';
}
}
/**
* Print create button list.
*
* @static
* @access public
* @return void
*/
public static function printCreateList()
{
global $app, $config, $lang;
$html = "";
$html .= "";
$html .= "";
$html .= "";
echo $html;
}
/**
* Print about bar.
*
* @static
* @access public
* @return void
*/
public static function printAboutBar()
{
global $app, $config, $lang;
echo "\n";
self::printClientLink();
echo '' . html::a(helper::createLink('misc', 'about'), " " . $lang->aboutZenTao, '', "class='about iframe' data-width='1050' data-headerless='true' data-backdrop='true' data-keyboard='true' data-class='modal-about'") . '';
echo '' . $lang->designedByAIUX . '';
}
/**
* Create menu item link
*
* @param object $menuItem
*
* @static
* @access public
* @return string
*/
public static function createMenuLink($menuItem, $group)
{
global $app;
$link = $menuItem->link;
if(is_array($menuItem->link))
{
$vars = isset($menuItem->link['vars']) ? $menuItem->link['vars'] : '';
if(isset($menuItem->tutorial) and $menuItem->tutorial)
{
if(!empty($vars)) $vars = helper::safe64Encode($vars);
$link = helper::createLink('tutorial', 'wizard', "module={$menuItem->link['module']}&method={$menuItem->link['method']}¶ms=$vars");
}
else
{
$link = helper::createLink($menuItem->link['module'], $menuItem->link['method'], $vars);
}
}
return $link;
}
/**
* Create sub menu by settings in lang files.
*
* @param array $items
* @param mixed $replace
* @static
* @access public
* @return array
*/
public static function createDropMenu($items, $replace)
{
$dropMenu = array();
foreach($items as $dropMenuKey => $dropMenuLink)
{
if(is_array($dropMenuLink) and isset($dropMenuLink['link'])) $dropMenuLink = $dropMenuLink['link'];
if(is_array($replace))
{
$dropMenuLink = vsprintf($dropMenuLink, $replace);
}
else
{
$dropMenuLink = sprintf($dropMenuLink, $replace);
}
list($dropMenuName, $dropMenuModule, $dropMenuMethod, $dropMenuParams) = explode('|', $dropMenuLink);
$link = array();
$link['module'] = $dropMenuModule;
$link['method'] = $dropMenuMethod;
$link['vars'] = $dropMenuParams;
$dropMenuItem = isset($items->$dropMenuKey) ? $items->$dropMenuKey : array();
$menu = new stdclass();
$menu->name = $dropMenuKey;
$menu->link = $link;
$menu->text = $dropMenuName;
$menu->subModule = isset($dropMenuItem['subModule']) ? $dropMenuItem['subModule'] : '';
$menu->alias = isset($dropMenuItem['alias']) ? $dropMenuItem['alias'] : '';
$menu->hidden = false;
$dropMenu[$dropMenuKey] = $menu;
}
return $dropMenu;
}
/**
* Print admin dropMenu.
*
* @param string $dropMenu
* @static
* @access public
* @return void
*/
public static function printAdminDropMenu($dropMenu)
{
global $app, $lang;
$currentModule = $app->getModuleName();
$currentMethod = $app->getMethodName();
if(isset($lang->admin->dropMenuOrder->$dropMenu))
{
ksort($lang->admin->dropMenuOrder->$dropMenu);
foreach($lang->admin->dropMenuOrder->$dropMenu as $type)
{
if(isset($lang->admin->dropMenu->$dropMenu->$type))
{
$subModule = '';
$alias = '';
$link = $lang->admin->dropMenu->$dropMenu->$type;
if(is_array($lang->admin->dropMenu->$dropMenu->$type))
{
$dropMenuType = $lang->admin->dropMenu->$dropMenu->$type;
if(isset($dropMenuType['subModule'])) $subModule = $dropMenuType['subModule'];
if(isset($dropMenuType['alias'])) $alias = $dropMenuType['alias'];
if(isset($dropMenuType['link'])) $link = $dropMenuType['link'];
}
list($text, $moduleName, $methodName)= explode('|', $link);
if(!common::hasPriv($moduleName, $methodName)) continue;
$active = ($currentModule == $moduleName and $currentMethod == $methodName) ? 'btn-active-text' : '';
if($subModule and strpos(",{$subModule}," , ",{$currentModule},") !== false) $active = 'btn-active-text';
if($alias and $currentModule == $moduleName and strpos(",$alias,", ",$currentMethod,") !== false) $active = 'btn-active-text';
echo html::a(helper::createLink($moduleName, $methodName), "$text", '', "class='btn btn-link {$active}' id='{$type}Tab'");
}
}
}
}
/**
* Print the main nav.
*
* @param string $moduleName
*
* @static
* @access public
* @return void
*/
public static function printMainNav($moduleName)
{
$items = common::getMainNavList($moduleName);
foreach($items as $item)
{
if($item == 'divider')
{
echo "";
}
else
{
$active = $item->active ? ' class="active"' : '';
echo "" . html::a($item->url, $item->title) . '';
}
}
}
/**
* Print upper left corner home button.
*
* @param string $tab
* @static
* @access public
* @return void
*/
public static function printHomeButton($tab)
{
global $lang, $config, $app;
if(!$tab) return;
if($tab == 'admin' and method_exists($app->control, 'loadModel')) $app->control->loadModel('admin')->setMenu();
$icon = zget($lang->navIcons, $tab, '');
if(!in_array($tab, array('program', 'product', 'project')))
{
$nav = $lang->mainNav->$tab;
list($title, $currentModule, $currentMethod, $vars) = explode('|', $nav);
if($tab == 'execution') $currentMethod = 'all';
}
else
{
$currentModule = $tab;
if($tab == 'program' or $tab == 'project') $currentMethod = 'browse';
if($tab == 'product') $currentMethod = 'all';
}
$btnTitle = isset($lang->db->custom['common']['mainNav'][$tab]) ? $lang->db->custom['common']['mainNav'][$tab] : $lang->$tab->common;
$commonKey = $tab . 'Common';
if(isset($lang->$commonKey) and $tab != 'execution') $btnTitle = $lang->$commonKey;
$link = helper::createLink($currentModule, $currentMethod);
$className = $tab == 'devops' ? 'btn num' : 'btn';
$html = $link ? html::a($link, "$icon $btnTitle", '', "class='$className' style='padding-top: 2px'") : "$icon $btnTitle";
echo "';
}
/**
* Format the date to YYYY-mm-dd, format the datetime to YYYY-mm-dd HH:ii:ss.
*
* @param int $date
* @param string $type date|datetime|''
* @access public
* @return string
*/
public function formatDate($date, $type = '')
{
$datePattern = '\w{4}(\/|-)\w{1,2}(\/|-)\w{1,2}';
$datetimePattern = $datePattern . ' \w{1,2}\:\w{1,2}\:\w{1,2}';
if(empty($type))
{
if(!preg_match("/$datePattern/", $date) and !preg_match("/$datetimePattern/", $date)) return $date;
if(preg_match("/$datePattern/", $date) === 1) $type = 'date';
if(preg_match("/$datetimePattern/", $date) === 1) $type = 'datetime';
}
if(helper::isZeroDate($date))
{
if($type == 'date') return '0000-00-00';
if($type == 'datetime') return '0000-00-00 00:00:00';
}
if($type == 'date') $format = 'Y-m-d';
if($type == 'datetime') $format = 'Y-m-d H:i:s';
return date($format, strtotime($date));
}
/**
* Get main nav items list
*
* @param string $moduleName
*
* @static
* @access public
* @return array
*/
public static function getMainNavList($moduleName)
{
global $lang;
global $app;
$app->loadLang('my');
$menuOrder = $lang->mainNav->menuOrder;
ksort($menuOrder);
$items = array();
$lastItem = end($menuOrder);
$printDivider = false;
foreach($menuOrder as $key => $group)
{
$nav = $lang->mainNav->$group;
list($title, $currentModule, $currentMethod, $vars) = explode('|', $nav);
/* When last divider is not used in mainNav, use it next menu. */
$printDivider = ($printDivider or ($lastItem != $key) and strpos($lang->dividerMenu, ",{$group},") !== false) ? true : false;
if($printDivider and !empty($items))
{
$items[] = 'divider';
$printDivider = false;
}
/**
* Judget the module display or not.
*
*/
$display = false;
/* 1. The default rule. */
if(common::hasPriv($currentModule, $currentMethod)) $display = true;
/* 2. If the module is assetLib, need judge more methods. */
if($currentModule == 'assetlib' and $display == false)
{
$methodList = array('caselib', 'issuelib', 'risklib', 'opportunitylib', 'practicelib', 'componentlib');
foreach($methodList as $method)
{
if(common::hasPriv($currentModule, $method))
{
$display = true;
$currentMethod = $method;
break;
}
}
}
/* Check whether other preference item under the module have permissions. If yes, point to other methods. */
$moduleLinkList = $currentModule . 'LinkList';
if(!$display and isset($lang->my->$moduleLinkList))
{
foreach($lang->my->$moduleLinkList as $key => $linkList)
{
$moduleMethodList = explode('-', $key);
$method = $moduleMethodList[1];
if(common::hasPriv($currentModule, $method))
{
$display = true;
$currentMethod = $method;
break;
}
}
}
/* Check whether other methods under the module have permissions. If yes, point to other methods. */
if($display == false and isset($lang->$currentModule->menu) and !in_array($currentModule, array('program', 'product', 'project', 'execution')))
{
foreach($lang->$currentModule->menu as $menu)
{
if(!isset($menu['link'])) continue;
$linkPart = explode('|', $menu['link']);
if(!isset($linkPart[2])) continue;
$method = $linkPart[2];
/* Skip some pages that do not require permissions.*/
if($currentModule == 'report' and $method == 'annualData') continue;
if($currentModule == 'my' and $currentMethod == 'team') continue;
if(common::hasPriv($currentModule, $method))
{
$display = true;
$currentMethod = $method;
if(!isset($menu['target'])) break; // Try to jump to the method without opening a new window.
}
}
}
if(!$display) continue;
/* Assign vars. */
$item = new stdClass();
$item->group = $group;
$item->code = $group;
$item->active = zget($lang->navGroup, $moduleName, '') == $group or $moduleName != 'program' and $moduleName == $group;
$item->title = $title;
$item->moduleName = $currentModule;
$item->methodName = $currentMethod;
$item->vars = $vars;
$isTutorialMode = commonModel::isTutorialMode();
if($isTutorialMode and $currentModule == 'project')
{
if(!empty($vars)) $vars = helper::safe64Encode($vars);
$item->url = helper::createLink('tutorial', 'wizard', "module={$currentModule}&method={$currentMethod}¶ms=$vars", '', 0, 0, 1);
}
else
{
$item->url = helper::createLink($currentModule, $currentMethod, $vars, '', 0, 0, 1);
}
$items[] = $item;
}
/* Fix bug 14574. */
if(end($items) == 'divider') array_pop($items);
return $items;
}
/**
* Print the main menu.
*
* @static
* @access public
* @return string
*/
public static function printMainMenu()
{
global $app, $lang, $config;
/* Set main menu by app tab and module. */
static::replaceMenuLang();
static::setMainMenu();
static::checkMenuVarsReplaced();
$activeMenu = '';
$tab = $app->tab;
$isTutorialMode = commonModel::isTutorialMode();
$currentModule = $app->rawModule;
$currentMethod = $app->rawMethod;
if($isTutorialMode and defined('WIZARD_MODULE')) $currentModule = WIZARD_MODULE;
if($isTutorialMode and defined('WIZARD_METHOD')) $currentMethod = WIZARD_METHOD;
/* Print all main menus. */
$menu = customModel::getMainMenu();
$lastMenu = end($menu);
echo "\n";
foreach($menu as $menuItem)
{
if(isset($menuItem->hidden) and $menuItem->hidden and (!isset($menuItem->tutorial) or !$menuItem->tutorial)) continue;
if(empty($menuItem->link)) continue;
if($menuItem->divider) echo "";
/* Init the these vars. */
$alias = isset($menuItem->alias) ? $menuItem->alias : '';
$subModule = isset($menuItem->subModule) ? explode(',', $menuItem->subModule) : array();
$class = isset($menuItem->class) ? $menuItem->class : '';
$exclude = isset($menuItem->exclude) ? $menuItem->exclude : '';
$active = '';
if($menuItem->name == $currentModule and strpos(",$exclude,", ",$currentModule-$currentMethod,") === false)
{
$activeMenu = $menuItem->name;
$active = 'active';
}
if($subModule and in_array($currentModule, $subModule) and strpos(",$exclude,", ",$currentModule-$currentMethod,") === false)
{
$activeMenu = $menuItem->name;
$active = 'active';
}
if($menuItem->link['module'] == 'execution' and $menuItem->link['method'] == 'more')
{
$executionID = $menuItem->link['vars'];
commonModel::buildMoreButton($executionID);
}
elseif($menuItem->link['module'] == 'app' and $menuItem->link['method'] == 'serverlink')
{
commonModel::buildAppButton();
}
else
{
if($menuItem->link)
{
$target = '';
$module = '';
$method = '';
$link = commonModel::createMenuLink($menuItem, $tab);
if($menuItem->link['module'] == 'project' and $menuItem->link['method'] == 'other') $link = 'javascript:void(0);';
if(is_array($menuItem->link))
{
if(isset($menuItem->link['target'])) $target = $menuItem->link['target'];
if(isset($menuItem->link['module'])) $module = $menuItem->link['module'];
if(isset($menuItem->link['method'])) $method = $menuItem->link['method'];
}
if($module == $currentModule and ($method == $currentMethod or strpos(",$alias,", ",$currentMethod,") !== false) and strpos(",$exclude,", ",$currentMethod,") === false)
{
$activeMenu = $menuItem->name;
$active = 'active';
}
$label = $menuItem->text;
$dropMenu = '';
$misc = (isset($lang->navGroup->$module) and $tab != $lang->navGroup->$module) ? "data-app='$tab'" : '';
/* Print drop menus. */
if(isset($menuItem->dropMenu))
{
foreach($menuItem->dropMenu as $dropMenuName => $dropMenuItem)
{
if(empty($dropMenuItem)) continue;
if(isset($dropMenuItem->hidden) and $dropMenuItem->hidden) continue;
/* Parse drop menu link. */
$dropMenuLink = zget($dropMenuItem, 'link', $dropMenuItem);
list($subLabel, $subModule, $subMethod, $subParams) = explode('|', $dropMenuLink);
if(!common::hasPriv($subModule, $subMethod)) continue;
$subLink = helper::createLink($subModule, $subMethod, $subParams);
$subActive = '';
$activeMainMenu = false;
if($currentModule == strtolower($subModule) and $currentMethod == strtolower($subMethod))
{
$activeMainMenu = true;
}
else
{
$subModule = isset($dropMenuItem['subModule']) ? explode(',', $dropMenuItem['subModule']) : array();
$subExclude = isset($dropMenuItem['exclude']) ? $dropMenuItem['exclude'] : $exclude;
if($subModule and in_array($currentModule, $subModule) and strpos(",$subExclude,", ",$currentModule-$currentMethod,") === false) $activeMainMenu = true;
}
if($activeMainMenu)
{
$activeMenu = $dropMenuName;
$active = 'active';
$subActive = 'active';
$label = $subLabel;
}
$dropMenu .= "- " . html::a($subLink, $subLabel, '', "data-app='$tab'") . '
';
}
if(empty($dropMenu)) continue;
$label .= "";
$dropMenu = "";
echo "- " . html::a($link, $label, $target, $misc) . $dropMenu . "
\n";
}
else
{
echo "- " . html::a($link, $label, $target, $misc) . "
\n";
}
}
else
{
echo "- $menuItem->text
\n";
}
}
}
echo "
\n";
return $activeMenu;
}
/**
* Print the search box.
*
* @static
* @access public
* @return void
*/
public static function printSearchBox()
{
global $lang;
global $config;
$searchObject = 'bug';
echo "";
echo html::hidden('searchType', $searchObject);
echo "
';
}
/**
* Print the module menu.
*
* @param string $activeMenu
* @static
* @access public
* @return void
*/
public static function printModuleMenu($activeMenu)
{
global $app, $lang;
$moduleName = $app->rawModule;
$methodName = $app->rawMethod;
$tab = $app->tab;
if(!isset($lang->$tab->menu))
{
echo "";
return;
}
/* get current module and method. */
$isTutorialMode = commonModel::isTutorialMode();
$currentModule = $app->getModuleName();
$currentMethod = $app->getMethodName();
$isMobile = $app->viewType === 'mhtml';
/* When use workflow then set rawModule to moduleName. */
if($moduleName == 'flow') $activeMenu = $app->rawModule;
$menu = customModel::getModuleMenu($activeMenu);
/* If this is not workflow then use rawModule and rawMethod to judge highlight. */
if($app->isFlow)
{
$currentModule = $app->rawModule;
$currentMethod = $app->rawMethod;
}
if($isTutorialMode and defined('WIZARD_MODULE')) $currentModule = WIZARD_MODULE;
if($isTutorialMode and defined('WIZARD_METHOD')) $currentMethod = WIZARD_METHOD;
/* The beginning of the menu. */
echo $isMobile ? '' : "\n";
/* Cycling to print every sub menu. */
foreach($menu as $menuItem)
{
if(isset($menuItem->hidden) and $menuItem->hidden) continue;
if($isMobile and empty($menuItem->link)) continue;
if($menuItem->divider) echo "";
/* Init the these vars. */
$alias = isset($menuItem->alias) ? $menuItem->alias : '';
$subModule = isset($menuItem->subModule) ? explode(',', $menuItem->subModule) : array();
$class = isset($menuItem->class) ? $menuItem->class : '';
$exclude = isset($menuItem->exclude) ? $menuItem->exclude : '';
$active = '';
if($subModule and in_array($currentModule, $subModule)) $active = 'active';
if($menuItem->link)
{
$target = '';
$module = '';
$method = '';
$link = commonModel::createMenuLink($menuItem, $tab);
if(is_array($menuItem->link))
{
if(isset($menuItem->link['target'])) $target = $menuItem->link['target'];
if(isset($menuItem->link['module'])) $module = $menuItem->link['module'];
if(isset($menuItem->link['method'])) $method = $menuItem->link['method'];
}
if($module == $currentModule and $method == $currentMethod) $active = 'active';
if($module == $currentModule and strpos(",$alias,", ",$currentMethod,") !== false) $active = 'active';
if(strpos(",$exclude,", ",$currentModule-$currentMethod,") !== false or strpos(",$exclude,", ",$currentModule,") !== false) $active = '';
$label = $menuItem->text;
$dropMenu = '';
/* Print sub menus. */
if(isset($menuItem->dropMenu))
{
foreach($menuItem->dropMenu as $dropMenuKey => $dropMenuItem)
{
if(isset($dropMenuItem->hidden) and $dropMenuItem->hidden) continue;
$subActive = '';
$subModule = '';
$subMethod = '';
$subParams = '';
$subLabel = '';
list($dropMenuName, $dropMenuModule, $dropMenuMethod, $dropMenuParams) = explode('|', $dropMenuItem['link']);
if(isset($dropMenuModule)) $subModule = $dropMenuModule;
if(isset($dropMenuMethod)) $subMethod = $dropMenuMethod;
if(isset($dropMenuParams)) $subParams = $dropMenuParams;
if(isset($dropMenuName)) $subLabel = $dropMenuName;
$subLink = helper::createLink($subModule, $subMethod, $subParams);
if($currentModule == strtolower($subModule) and $currentMethod == strtolower($subMethod)) $subActive = 'active';
$misc = (isset($lang->navGroup->$subModule) and $tab != $lang->navGroup->$subModule) ? "data-app='$tab'" : '';
$dropMenu .= "- " . html::a($subLink, $subLabel, '', $misc) . '
';
}
if(empty($dropMenu)) continue;
$label .= "";
$dropMenu = "";
}
$misc = (isset($lang->navGroup->$module) and $tab != $lang->navGroup->$module) ? "data-app='$tab'" : '';
$menuItemHtml = "- " . html::a($link, $label, $target, $misc) . $dropMenu . "
\n";
if($isMobile) $menuItemHtml = html::a($link, $menuItem->text, $target, $misc . " class='$class $active'") . "\n";
echo $menuItemHtml;
}
else
{
echo $isMobile ? $menuItem->text : "- $menuItem->text
\n";
}
}
echo $isMobile ? '' : "
\n";
}
/**
* Print the bread menu.
*
* @param string $moduleName
* @param string $position
* @static
* @access public
* @return void
*/
public static function printBreadMenu($moduleName, $position)
{
global $lang;
$mainMenu = $moduleName;
echo "";
echo '- ' . html::a(helper::createLink('my', 'index'), $lang->zentaoPMS) . '
';
if($moduleName != 'index')
{
if(isset($lang->menu->$mainMenu))
{
$menuLink = $lang->menu->$mainMenu;
if(is_array($menuLink)) $menuLink = $menuLink['link'];
list($menuLabel, $module, $method) = explode('|', $menuLink);
echo '- ' . html::a(helper::createLink($module, $method), $menuLabel) . '
';
}
}
else
{
echo '- ' . $lang->index->common . '
';
}
if(empty($position))
{
echo '
';
return;
}
if(is_array($position))
{
foreach($position as $key => $link) echo "" . $link . '';
}
echo '';
}
/**
* Print the link for notify file.
*
* @static
* @access public
* @return void
*/
public static function printNotifyLink()
{
if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows') !== false)
{
global $lang;
echo html::a(helper::createLink('misc', 'downNotify'), "", '', "title='$lang->downNotify' class='text-primary'") . ' ';
}
}
/**
* Print the link for zentao client.
*
* @static
* @access public
* @return void
*/
public static function printClientLink()
{
global $config, $lang;
if(isset($config->xxserver->installed) and $config->xuanxuan->turnon)
{
echo "