* @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->loadConfigFromDB();
$this->app->setTimezone();
$this->loadCustomFromDB();
if(!$this->checkIP()) die($this->lang->ipLimited);
$this->app->loadLang('company');
}
}
/**
* Set the header info.
*
* @access public
* @return void
*/
public function sendHeader()
{
header("Content-Type: text/html; Language={$this->config->charset}");
header("Cache-control: private");
if($this->loadModel('setting')->getItem('owner=system&module=sso&key=turnon'))
{
if(isset($_SERVER["HTTPS"]) && $_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->role = 'guest';
$user->admin = false;
$user->rights = $this->loadModel('user')->authorize('guest');
$user->groups = array('group');
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;
}
}
/**
* 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');
}
/**
* 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($module == 'user' and strpos('login|logout|deny|reset', $method) !== false) return true;
if($module == 'api' and $method == 'getsessionid') return true;
if($module == 'misc' and $method == 'checktable') return true;
if($module == 'misc' and $method == 'qrcode') return true;
if($module == 'misc' and $method == 'about') return true;
if($module == 'misc' and $method == 'checkupdate') return true;
if($module == 'misc' and $method == 'ping') return true;
if($module == 'sso' and $method == 'login') return true;
if($module == 'sso' and $method == 'logout') return true;
if($module == 'sso' and $method == 'bind') return true;
if($module == 'sso' and $method == 'gettodolist') return true;
if($module == 'block' and $method == 'main' and isset($_GET['hash'])) return true;
if($module == 'file' and $method == 'read') 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 == '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 == 'block' and $method == 'admin') return true;
if($module == 'block' and $method == 'set') return true;
if($module == 'block' and $method == 'sort') return true;
if($module == 'block' and $method == 'resize') return true;
if($module == 'block' and $method == 'dashboard') return true;
if($module == 'block' and $method == 'printblock') return true;
if($module == 'block' and $method == 'main') return true;
if($module == 'block' and $method == 'delete') return true;
if($module == 'product' and $method == 'showerrornone') return true;
if($module == 'report' and $method == 'annualdata') return true;
}
return false;
}
/**
* Deny access.
*
* @access public
* @return mixed
*/
public function deny($module, $method)
{
/* Get authorize again. */
$user = $this->app->user;
$user->rights = $this->loadModel('user')->authorize($user->account);
$user->groups = $this->user->getGroups($user->account);
$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);
}
exit;
}
/**
* 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 "" . (empty($app->user->realname) ? $app->user->account : $app->user->realname) . '';
echo "";
echo '';
echo "
';
}
}
/**
* Print about bar.
*
* @static
* @access public
* @return void
*/
public static function printAboutBar()
{
global $app, $config, $lang;
echo "\n";
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'") . '';
}
/**
* Create menu item link
*
* @param object $menuItem
*
* @static
* @access public
* @return string
*/
public static function createMenuLink($menuItem)
{
$link = $menuItem->link;
if(is_array($menuItem->link))
{
$vars = isset($menuItem->link['vars']) ? $menuItem->link['vars'] : '';
if(isset($menuItem->tutorial) && $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 createSubMenu($items, $replace)
{
$subMenu = array();
foreach($items as $subMenuKey => $subMenuLink)
{
if(is_array($subMenuLink) and isset($subMenuLink['link'])) $subMenuLink = $subMenuLink['link'];
if(is_array($replace))
{
$subMenuLink = vsprintf($subMenuLink, $replace);
}
else
{
$subMenuLink = sprintf($subMenuLink, $replace);
}
list($subMenuName, $subMenuModule, $subMenuMethod, $subMenuParams) = explode('|', $subMenuLink);
$link = array();
$link['module'] = $subMenuModule;
$link['method'] = $subMenuMethod;
$link['vars'] = $subMenuParams;
$subMenuItem = isset($items->$subMenuKey) ? $items->$subMenuKey : array();
$menu = new stdclass();
$menu->name = $subMenuKey;
$menu->link = $link;
$menu->text = $subMenuName;
$menu->subModule = isset($subMenuItem['subModule']) ? $subMenuItem['subModule'] : '';
$menu->alias = isset($subMenuItem['alias']) ? $subMenuItem['alias'] : '';
$menu->hidden = false;
$subMenu[$subMenuKey] = $menu;
}
return $subMenu;
}
/**
* Print admin subMenu.
*
* @param string $subMenu
* @static
* @access public
* @return void
*/
public static function printAdminSubMenu($subMenu)
{
global $app, $lang;
$currentModule = $app->getModuleName();
$currentMethod = $app->getMethodName();
if(isset($lang->admin->subMenuOrder->$subMenu))
{
ksort($lang->admin->subMenuOrder->$subMenu);
foreach($lang->admin->subMenuOrder->$subMenu as $type)
{
if(isset($lang->admin->subMenu->$subMenu->$type))
{
$subModule = '';
$alias = '';
$link = $lang->admin->subMenu->$subMenu->$type;
if(is_array($lang->admin->subMenu->$subMenu->$type))
{
$subMenuType = $lang->admin->subMenu->$subMenu->$type;
if(isset($subMenuType['subModule'])) $subModule = $subMenuType['subModule'];
if(isset($subMenuType['alias'])) $alias = $subMenuType['alias'];
if(isset($subMenuType['link'])) $link = $subMenuType['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 menu.
*
* @param string $moduleName
* @param string $methodName
*
* @static
* @access public
* @return void
*/
public static function printMainmenu($moduleName, $methodName = '')
{
global $app, $lang;
/* Set the main main menu. */
$mainMenu = $moduleName;
if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName;
/* Print all main menus. */
$menu = customModel::getMainMenu();
$activeName = 'active';
$lastMenu = end($menu);
echo "\n";
foreach($menu as $menuItem)
{
if(empty($menuItem->hidden))
{
$active = $menuItem->name == $mainMenu ? "class='$activeName'" : '';
$link = commonModel::createMenuLink($menuItem);
echo "- $menuItem->text
\n";
if(($lastMenu->name != $menuItem->name) && strpos($lang->dividerMenu, ",{$menuItem->name},") !== false) echo "";
}
}
echo "
\n";
}
/**
* Print the search box.
*
* @static
* @access public
* @return void
*/
public static function printSearchBox()
{
global $app, $config, $lang;
$moduleName = $app->getModuleName();
$methodName = $app->getMethodName();
$searchObject = $moduleName;
if($moduleName == 'product')
{
if($methodName == 'browse') $searchObject = 'story';
}
elseif($moduleName == 'project')
{
if(strpos('task|story|bug|build', $methodName) !== false) $searchObject = $methodName;
}
elseif($moduleName == 'my' or $moduleName == 'user')
{
$searchObject = $methodName;
}
if(empty($lang->searchObjects[$searchObject]))
{
$searchObject = 'bug';
if($config->global->flow == 'onlyStory') $searchObject = 'story';
if($config->global->flow == 'onlyTask') $searchObject = 'task';
}
echo "";
echo "
';
echo "
GO!";
echo "
\n";
}
/**
* Print the module menu.
*
* @param string $moduleName
* @static
* @access public
* @return void
*/
public static function printModuleMenu($moduleName)
{
global $config, $lang, $app;
if(!isset($lang->$moduleName->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') $moduleName = $app->rawModule;
$menu = customModel::getModuleMenu($moduleName);
/* 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";
if(isset($lang->menugroup->$moduleName)) $moduleName = $lang->menugroup->$moduleName;
/* Cycling to print every sub menu. */
foreach($menu as $menuItem)
{
if(isset($menuItem->hidden) && $menuItem->hidden) continue;
if($isMobile and empty($menuItem->link)) continue;
if(isset($lang->$moduleName->dividerMenu) and strpos($lang->$moduleName->dividerMenu, ",{$menuItem->name},") !== false) 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 : '';
$active = '';
if($subModule and in_array($currentModule, $subModule)) $active = 'active';
if($alias and $moduleName == $currentModule and strpos(",$alias,", ",$currentMethod,") !== false) $active = 'active';
if($menuItem->link)
{
$target = '';
$module = '';
$method = '';
$link = commonModel::createMenuLink($menuItem);
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)) $active = 'active';
/* Avoid user thinking the page is shaking when the menu toggle class 'active' */
if($config->global->flow == 'onlyTest')
{
if($currentModule == 'bug' && $currentMethod == 'browse') $active = '';
if($currentModule == 'testcase' && $currentMethod == 'browse') $active = '';
if($currentModule == 'testtask' && $currentMethod == 'browse') $active = '';
if($currentModule == 'caselib' && $currentMethod == 'browse') $active = '';
}
$label = $menuItem->text;
$subMenu = '';
/* Print sub menus. */
if(isset($menuItem->subMenu))
{
foreach($menuItem->subMenu as $subMenuItem)
{
if($subMenuItem->hidden) continue;
$subActive = '';
$subModule = '';
$subMethod = '';
$subParams = '';
$subLabel = $subMenuItem->text;
if(isset($subMenuItem->link['module'])) $subModule = $subMenuItem->link['module'];
if(isset($subMenuItem->link['method'])) $subMethod = $subMenuItem->link['method'];
if(isset($subMenuItem->link['vars'])) $subParams = $subMenuItem->link['vars'];
$subLink = helper::createLink($subModule, $subMethod, $subParams);
if($config->global->flow != 'onlyTest' && $currentModule == strtolower($subModule) && $currentMethod == strtolower($subMethod)) $subActive = 'active';
$subMenu .= "- " . html::a($subLink, $subLabel) . '
';
}
if(empty($subMenu)) continue;
$label .= "";
$subMenu = "";
}
$menuItemHtml = "- " . html::a($link, $label, $target) . $subMenu . "
\n";
if($isMobile) $menuItemHtml = html::a($link, $menuItem->text, $target, "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;
if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName;
echo "";
echo '- ' . html::a(helper::createLink('my', 'index'), $lang->zentaoPMS) . '
';
if($moduleName != 'index')
{
if(!isset($lang->menu->$mainMenu)) return print("
");
$menuLink = $lang->menu->$mainMenu;
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 $lang;
echo html::a(helper::createLink('misc', 'downloadClient', '', '', true), $lang->downloadClient, '', "title='$lang->downloadClient' class='text-primary iframe' data-width='600'") . html::a($lang->clientHelpLink, "", '', "title='$lang->clientHelp' target='_blank'") . ' ';
}
/**
* Print QR code Link.
*
* @param string $color
*
* @static
* @access public
* @return void
*/
public static function printQRCodeLink($color = '')
{
global $lang;
echo html::a('javascript:;', "", '', "class='qrCode $color' id='qrcodeBtn' title='{$lang->user->mobileLogin}'");
echo "{$lang->user->mobileLogin}
";
echo '';
echo '';
}
/**
* Print the link contains orderBy field.
*
* This method will auto set the orderby param according the params. Fox example, if the order by is desc,
* will be changed to asc.
*
* @param string $fieldName the field name to sort by
* @param string $orderBy the order by string
* @param string $vars the vars to be passed
* @param string $label the label of the link
* @param string $module the module name
* @param string $method the method name
*
* @access public
* @return void
*/
public static function printOrderLink($fieldName, $orderBy, $vars, $label, $module = '', $method = '')
{
global $lang, $app;
if(empty($module)) $module = isset($app->rawModule) ? $app->rawModule : $app->getModuleName();
if(empty($method)) $method = isset($app->rawMethod) ? $app->rawMethod : $app->getMethodName();
$className = 'header';
$isMobile = $app->viewType === 'mhtml';
$order = explode('_', $orderBy);
$order[0] = trim($order[0], '`');
if($order[0] == $fieldName)
{
if(isset($order[1]) and $order[1] == 'asc')
{
$orderBy = "{$order[0]}_desc";
$className = $isMobile ? 'SortUp' : 'sort-up';
}
else
{
$orderBy = "{$order[0]}_asc";
$className = $isMobile ? 'SortDown' : 'sort-down';
}
}
else
{
$orderBy = "" . trim($fieldName, '`') . "" . '_' . 'asc';
$className = 'header';
}
$link = helper::createLink($module, $method, sprintf($vars, $orderBy));
echo $isMobile ? html::a($link, $label, '', "class='$className'") : html::a($link, $label, '', "class='$className'");
}
/**
*
* Print link to an modules' methd.
*
* Before printing, check the privilege first. If no privilege, return fasle. Else, print the link, return true.
*
* @param string $module the module name
* @param string $method the method
* @param string $vars vars to be passed
* @param string $label the label of the link
* @param string $target the target of the link
* @param string $misc others
* @param bool $newline
* @param bool $onlyBody
* @param $object
*
* @static
* @access public
* @return bool
*/
public static function printLink($module, $method, $vars = '', $label, $target = '', $misc = '', $newline = true, $onlyBody = false, $object = null)
{
if(!commonModel::hasPriv($module, $method, $object)) return false;
echo html::a(helper::createLink($module, $method, $vars, '', $onlyBody), $label, $target, $misc, $newline);
return true;
}
/**
* Print icon of split line.
*
* @static
* @access public
* @return void
*/
public static function printDivider()
{
echo " ";
}
/**
* Print icon of comment.
*
* @param string $commentFormLink
* @param object $object
*
* @static
* @access public
* @return mixed
*/
public static function printCommentIcon($commentFormLink, $object = null)
{
global $lang;
if(!commonModel::hasPriv('action', 'comment', $object)) return false;
echo html::commonButton(' ' . $lang->action->create, '', 'btn btn-link pull-right btn-comment');
echo <<