1438 lines
52 KiB
PHP
1438 lines
52 KiB
PHP
<?php
|
|
/**
|
|
* The model file of common module of ZenTaoPMS.
|
|
*
|
|
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
|
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
|
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
|
* @package common
|
|
* @version $Id$
|
|
* @link http://www.zentao.net
|
|
*/
|
|
class commonModel extends model
|
|
{
|
|
/**
|
|
* 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->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");
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
$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');
|
|
$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()
|
|
{
|
|
if(defined('IN_UPGRADE')) return;
|
|
if(!$this->config->db->name) return;
|
|
$records = $this->loadModel('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 == 'ping') 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 == 'changelog') 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') 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(stripos($method, 'downnotify') !== false) return true;
|
|
if($module == 'tutorial') return true;
|
|
if($module == 'block') return true;
|
|
if($module == 'product' and $method == 'showerrornone') return true;
|
|
if($module == 'score' and $method == 'browse') return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Deny access.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
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 "<a href='$denyLink' id='denylink' style='display:none'>deny</a>";
|
|
echo "<script language='javascript'>document.getElementById('denylink').click();</script>";
|
|
}
|
|
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 printTopBar()
|
|
{
|
|
global $lang, $app;
|
|
|
|
if(isset($app->user))
|
|
{
|
|
$isGuest = $app->user->account == 'guest';
|
|
|
|
echo "<div class='dropdown' id='userMenu'>";
|
|
echo "<a href='javascript:;' data-toggle='dropdown'><i class='icon-user'></i> " . $app->user->realname . " <span class='caret'></span></a>";
|
|
|
|
echo "<ul class='dropdown-menu'>";
|
|
|
|
if(!$isGuest)
|
|
{
|
|
echo '<li>' . html::a(helper::createLink('my', 'profile', '', '', true), $lang->profile, '', "class='iframe' data-width='600'") . '</li>';
|
|
echo '<li>' . html::a(helper::createLink('my', 'changepassword', '', '', true), $lang->changePassword, '', "class='iframe' data-width='500'") . '</li>';
|
|
|
|
echo "<li class='divider'></li>";
|
|
}
|
|
|
|
echo "<li class='dropdown-submenu left'>";
|
|
echo "<a href='javascript:;'>" . $lang->theme . "</a><ul class='dropdown-menu'>";
|
|
foreach ($app->lang->themes as $key => $value)
|
|
{
|
|
echo "<li class='theme-option" . ($app->cookie->theme == $key ? " active" : '') . "'><a href='javascript:selectTheme(\"$key\");' data-value='" . $key . "'>" . $value . "</a></li>";
|
|
}
|
|
echo '</ul></li>';
|
|
|
|
echo "<li class='dropdown-submenu left'>";
|
|
echo "<a href='javascript:;'>" . $lang->lang . "</a><ul class='dropdown-menu'>";
|
|
foreach ($app->config->langs as $key => $value)
|
|
{
|
|
echo "<li class='lang-option" . ($app->cookie->lang == $key ? " active" : '') . "'><a href='javascript:selectLang(\"$key\");' data-value='" . $key . "'>" . $value . "</a></li>";
|
|
}
|
|
echo '</ul></li>';
|
|
|
|
echo '</ul></div>';
|
|
|
|
if($isGuest)
|
|
{
|
|
echo html::a(helper::createLink('user', 'login'), $lang->login);
|
|
}
|
|
else
|
|
{
|
|
echo html::a(helper::createLink('user', 'logout'), $lang->logout);
|
|
}
|
|
}
|
|
|
|
if($app->company->website) echo html::a($app->company->website, $lang->company->website, '_blank');
|
|
if($app->company->backyard) echo html::a($app->company->backyard, $lang->company->backyard, '_blank');
|
|
|
|
echo "<div class='dropdown'>";
|
|
echo "<a href='javascript:;' data-toggle='dropdown'>" . $lang->help . " <span class='caret'></span></a>";
|
|
echo "<ul class='dropdown-menu pull-right'>";
|
|
echo '<li>' . html::a('javascript:;', $lang->manual, '', "class='open-help-tab'") . '</li>';
|
|
if(!commonModel::isTutorialMode() and $app->user->account != 'guest') echo '<li>' . html::a(helper::createLink('tutorial', 'start'), $lang->tutorial, '', "class='iframe' data-width='800' data-headerless='true' data-backdrop='true' data-keyboard='true'") . "</li>";
|
|
echo '<li>' . html::a(helper::createLink('misc', 'changeLog'), $lang->changeLog, '', "class='iframe' data-width='800' data-headerless='true' data-backdrop='true' data-keyboard='true'") . '</li>';
|
|
echo "</ul></div>";
|
|
echo html::a(helper::createLink('misc', 'about'), $lang->aboutZenTao, '', "class='about iframe' data-width='900' data-headerless='true' data-backdrop='true' data-keyboard='true' data-class='modal-about'");
|
|
}
|
|
|
|
/**
|
|
* Create menu item link
|
|
*
|
|
* @param object $menuItemLink
|
|
* @param boolean $isTutorialMode
|
|
* @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;
|
|
}
|
|
|
|
/**
|
|
* Print the main menu.
|
|
*
|
|
* @param string $moduleName
|
|
* @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';
|
|
|
|
echo "<ul class='nav'>\n";
|
|
foreach($menu as $menuItem)
|
|
{
|
|
if(isset($menuItem->hidden) && $menuItem->hidden) continue;
|
|
$active = $menuItem->name == $mainMenu ? "class='$activeName'" : '';
|
|
$link = commonModel::createMenuLink($menuItem);
|
|
echo "<li $active data-id='$menuItem->name'><a href='$link' $active>$menuItem->text</a></li>\n";
|
|
}
|
|
$customLink = helper::createLink('custom', 'ajaxMenu', "module={$app->getModuleName()}&method={$app->getMethodName()}", '', true);
|
|
if(!commonModel::isTutorialMode() and $app->viewType != 'mhtml' and $app->user->account != 'guest') echo "<li class='custom-item'><a href='$customLink' data-toggle='modal' data-type='iframe' title='$lang->customMenu' data-icon='cog' data-width='80%'><i class='icon icon-cog'></i></a></li>";
|
|
echo "</ul>\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 "<div class='input-group input-group-sm' id='searchbox'>";
|
|
echo "<div class='input-group-btn' id='typeSelector'>";
|
|
echo "<button type='button' class='btn dropdown-toggle' data-toggle='dropdown'><span id='searchTypeName'>" . $lang->searchObjects[$searchObject] . "</span> <span class='caret'></span></button>";
|
|
echo html::hidden('searchType', $searchObject);
|
|
echo "<ul class='dropdown-menu'>";
|
|
foreach ($lang->searchObjects as $key => $value)
|
|
{
|
|
echo "<li><a href='javascript:;' data-value='{$key}'>{$value}</a></li>";
|
|
}
|
|
echo '</ul></div>';
|
|
echo html::input('searchQuery', '', "onclick='this.value=\"\"' onkeydown='if(event.keyCode==13) shortcut()' class='form-control' placeholder='" . $lang->searchTips . "'");
|
|
echo "<div id='objectSwitcher' class='input-group-btn'><a href='javascript:shortcut();' class='btn'>GO! </a></div>";
|
|
echo "</div>\n";
|
|
}
|
|
|
|
/**
|
|
* Print the module menu.
|
|
*
|
|
* @param string $moduleName
|
|
* @static
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public static function printModuleMenu($moduleName)
|
|
{
|
|
global $lang, $app;
|
|
|
|
if(!isset($lang->$moduleName->menu))
|
|
{
|
|
echo "<ul></ul>";
|
|
return;
|
|
}
|
|
|
|
/* get current module and method. */
|
|
$isTutorialMode = commonModel::isTutorialMode();
|
|
$currentModule = ($isTutorialMode and defined('WIZARD_MODULE')) ? WIZARD_MODULE : $app->getModuleName();
|
|
$currentMethod = ($isTutorialMode and defined('WIZARD_METHOD')) ? WIZARD_METHOD : $app->getMethodName();
|
|
$menu = customModel::getModuleMenu($moduleName);
|
|
$isMobile = $app->viewType === 'mhtml';
|
|
|
|
/* The beginning of the menu. */
|
|
echo $isMobile ? '' : "<ul class='nav'>\n";
|
|
|
|
/* Cycling to print every sub menus. */
|
|
foreach($menu as $menuItem)
|
|
{
|
|
if(isset($menuItem->hidden) && $menuItem->hidden) continue;
|
|
if($isMobile and empty($menuItem->link)) continue;
|
|
|
|
/* Init the these vars. */
|
|
if($menuItem->link)
|
|
{
|
|
$active = '';
|
|
$float = isset($menuItem->float) ? $menuItem->float : '';
|
|
$alias = '';
|
|
$target = '';
|
|
$module = '';
|
|
$method = '';
|
|
$link = commonModel::createMenuLink($menuItem);
|
|
if(is_array($menuItem->link))
|
|
{
|
|
if(isset($menuItem->link['subModule']))
|
|
{
|
|
$subModules = explode(',', $menuItem->link['subModule']);
|
|
if(in_array($currentModule, $subModules) and $float != 'right') $active = 'active';
|
|
}
|
|
if(isset($menuItem->link['alias'])) $alias = $menuItem->link['alias'];
|
|
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($float != 'right' and $module == $currentModule and ($method == $currentMethod or strpos(",$alias,", ",$currentMethod,") !== false)) $active = 'active';
|
|
|
|
$menuItemHtml = "<li class='$float $active' data-id='$menuItem->name'>" . html::a($link, $menuItem->text, $target) . "</li>\n";
|
|
if($isMobile) $menuItemHtml = html::a($link, $menuItem->text, $target, "class='$active'") . "\n";
|
|
echo $menuItemHtml;
|
|
}
|
|
else
|
|
{
|
|
echo $isMobile ? $menuItem->text : "<li data-id='$menuItem->name'>$menuItem->text</li>\n";
|
|
}
|
|
}
|
|
echo $isMobile ? '' : "</ul>\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 html::a(helper::createLink('my', 'index'), $lang->zentaoPMS) . $lang->arrow;
|
|
if($moduleName != 'index')
|
|
{
|
|
if(!isset($lang->menu->$mainMenu)) return;
|
|
list($menuLabel, $module, $method) = explode('|', $lang->menu->$mainMenu);
|
|
echo html::a(helper::createLink($module, $method), $menuLabel);
|
|
}
|
|
else
|
|
{
|
|
echo $lang->index->common;
|
|
}
|
|
if(empty($position)) return;
|
|
echo $lang->arrow;
|
|
foreach($position as $key => $link)
|
|
{
|
|
echo $link;
|
|
if(isset($position[$key + 1])) echo $lang->arrow;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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'), "<i class='icon-bell'></i>", '', "title='$lang->downNotify'") . ' ';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print QR code Link.
|
|
*
|
|
* @static
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public static function printQRCodeLink($color = '')
|
|
{
|
|
global $lang;
|
|
echo html::a('javascript:;', "<i class='icon-qrcode'></i>", '', "class='qrCode $color' id='qrcodeBtn' title='{$lang->user->mobileLogin}'");
|
|
echo "<div class='popover top' id='qrcodePopover'><div class='arrow'></div><h3 class='popover-title'>{$lang->user->mobileLogin}</h3><div class='popover-content'><img src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'></div></div>";
|
|
echo '<script>$(function(){$("#qrcodeBtn").click(function(){$("#qrcodePopover").toggleClass("show");}); $("#wrap").click(function(){$("#qrcodePopover").removeClass("show");});});</script>';
|
|
echo '<script>$(function(){$("#qrcodeBtn").hover(function(){$(".popover-content img").attr("src", "' . helper::createLink('misc', 'qrCode') . '");});});</script>';
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* @static
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public static function printOrderLink($fieldName, $orderBy, $vars, $label, $module = '', $method = '')
|
|
{
|
|
global $lang, $app;
|
|
if(empty($module)) $module = $app->getModuleName();
|
|
if(empty($method)) $method = $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' : 'headerSortDown';
|
|
}
|
|
else
|
|
{
|
|
$orderBy = "{$order[0]}_asc";
|
|
$className = $isMobile ? 'SortDown' : 'headerSortUp';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$orderBy = "" . trim($fieldName, '`') . "" . '_' . 'asc';
|
|
$className = 'header';
|
|
}
|
|
$link = helper::createLink($module, $method, sprintf($vars, $orderBy));
|
|
echo $isMobile ? html::a($link, $label, '', "class='$className'") : "<div class='$className'>" . html::a($link, $label) . '</div>';
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* @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 $module
|
|
* @static
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public static function printCommentIcon($module, $object = null)
|
|
{
|
|
if(isonlybody()) return false;
|
|
|
|
global $lang;
|
|
|
|
if(!commonModel::hasPriv($module, 'edit', $object)) return false;
|
|
echo html::a('#commentBox', '<i class="icon-comment-alt"></i>', '', "title='$lang->comment' onclick='setComment()' class='btn'");
|
|
}
|
|
|
|
/**
|
|
* Build icon button.
|
|
*
|
|
* @param string $module
|
|
* @param string $method
|
|
* @param string $vars
|
|
* @param object $object
|
|
* @param string $type button|list
|
|
* @param string $icon
|
|
* @param string $target
|
|
* @param string $extraClass
|
|
* @param bool $onlyBody
|
|
* @param string $misc
|
|
* @static
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public static function buildIconButton($module, $method, $vars = '', $object = '', $type = 'button', $icon = '', $target = '', $extraClass = '', $onlyBody = false, $misc = '', $title = '')
|
|
{
|
|
if(isonlybody() and strpos($extraClass, 'showinonlybody') === false) return false;
|
|
|
|
global $app, $lang;
|
|
|
|
/* Judge the $method of $module clickable or not, default is clickable. */
|
|
$clickable = true;
|
|
if(is_object($object))
|
|
{
|
|
if($app->getModuleName() != $module) $app->control->loadModel($module);
|
|
$modelClass = class_exists("ext{$module}Model") ? "ext{$module}Model" : $module . "Model";
|
|
if(class_exists($modelClass) and is_callable(array($modelClass, 'isClickable')))
|
|
{
|
|
$clickable = call_user_func_array(array($modelClass, 'isClickable'), array('object' => $object, 'method' => $method));
|
|
}
|
|
}
|
|
|
|
/* Set module and method, then create link to it. */
|
|
if(strtolower($module) == 'story' and strtolower($method) == 'createcase') ($module = 'testcase') and ($method = 'create');
|
|
if(strtolower($module) == 'bug' and strtolower($method) == 'tostory') ($module = 'story') and ($method = 'create');
|
|
if(strtolower($module) == 'bug' and strtolower($method) == 'createcase') ($module = 'testcase') and ($method = 'create');
|
|
if(!commonModel::hasPriv($module, $method, $object)) return false;
|
|
$link = helper::createLink($module, $method, $vars, '', $onlyBody);
|
|
|
|
/* Set the icon title, try search the $method defination in $module's lang or $common's lang. */
|
|
if(empty($title))
|
|
{
|
|
$title = $method;
|
|
if($method == 'create' and $icon == 'copy') $method = 'copy';
|
|
if(isset($lang->$method) and is_string($lang->$method)) $title = $lang->$method;
|
|
if((isset($lang->$module->$method) or $app->loadLang($module)) and isset($lang->$module->$method))
|
|
{
|
|
$title = $method == 'report' ? $lang->$module->$method->common : $lang->$module->$method;
|
|
}
|
|
if($icon == 'toStory') $title = $lang->bug->toStory;
|
|
if($icon == 'createBug') $title = $lang->testtask->createBug;
|
|
}
|
|
|
|
/* set the class. */
|
|
if(!$icon)
|
|
{
|
|
$icon = isset($lang->icons[$method]) ? $lang->icons[$method] : $method;
|
|
}
|
|
if(strpos(',edit,copy,report,export,delete,', ",$method,") !== false) $module = 'common';
|
|
$class = "icon-$module-$method";
|
|
if(!$clickable) $class .= ' disabled';
|
|
if($icon) $class .= ' icon-' . $icon;
|
|
|
|
|
|
/* Create the icon link. */
|
|
if($clickable)
|
|
{
|
|
if($app->getViewType() == 'mhtml')
|
|
{
|
|
return "<a data-remote='$link' class='$extraClass' $misc>$title</a>";
|
|
}
|
|
if($type == 'button')
|
|
{
|
|
if($method != 'edit' and $method != 'copy' and $method != 'delete')
|
|
{
|
|
return html::a($link, "<i class='$class'></i> " . $title, $target, "class='btn $extraClass' $misc", true);
|
|
}
|
|
else
|
|
{
|
|
return html::a($link, "<i class='$class'></i>", $target, "class='btn $extraClass' title='$title' $misc", false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return html::a($link, "<i class='$class'></i>", $target, "class='btn-icon $extraClass' title='$title' $misc", false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if($type == 'list')
|
|
{
|
|
return "<button type='button' class='disabled btn-icon $extraClass'><i class='$class' title='$title' $misc></i></button>";
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print link icon.
|
|
*
|
|
* @param string $module
|
|
* @param string $method
|
|
* @param string $vars
|
|
* @param object $object
|
|
* @param string $type button|list
|
|
* @param string $icon
|
|
* @param string $target
|
|
* @param string $extraClass
|
|
* @param bool $onlyBody
|
|
* @param string $misc
|
|
* @static
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public static function printIcon($module, $method, $vars = '', $object = '', $type = 'button', $icon = '', $target = '', $extraClass = '', $onlyBody = false, $misc = '', $title = '')
|
|
{
|
|
echo common::buildIconButton($module, $method, $vars, $object, $type, $icon, $target, $extraClass, $onlyBody, $misc, $title);
|
|
}
|
|
|
|
/**
|
|
* Print backLink and preLink and nextLink.
|
|
*
|
|
* @param string $backLink
|
|
* @param object $preAndNext
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
static public function printRPN($backLink, $preAndNext = '', $linkTemplate = '')
|
|
{
|
|
global $lang, $app;
|
|
if(isonlybody()) return false;
|
|
|
|
$title = $lang->goback . $lang->backShortcutKey;
|
|
echo html::a($backLink, '<i class="icon-goback icon-level-up icon-large icon-rotate-270"></i>', '', "id='back' class='btn' title={$title}");
|
|
|
|
if(isset($preAndNext->pre) and $preAndNext->pre)
|
|
{
|
|
$id = (isset($_SESSION['testcaseOnlyCondition']) and !$_SESSION['testcaseOnlyCondition'] and $app->getModuleName() == 'testcase' and isset($preAndNext->pre->case)) ? 'case' : 'id';
|
|
$title = isset($preAndNext->pre->title) ? $preAndNext->pre->title : $preAndNext->pre->name;
|
|
$title = '#' . $preAndNext->pre->$id . ' ' . $title . ' ' . $lang->preShortcutKey;
|
|
$link = $linkTemplate ? sprintf($linkTemplate, $preAndNext->pre->$id) : inLink('view', "ID={$preAndNext->pre->$id}");
|
|
echo html::a($link, '<i class="icon-pre icon-chevron-left"></i>', '', "id='pre' class='btn' title='{$title}'");
|
|
}
|
|
if(isset($preAndNext->next) and $preAndNext->next)
|
|
{
|
|
$id = (isset($_SESSION['testcaseOnlyCondition']) and !$_SESSION['testcaseOnlyCondition'] and $app->getModuleName() == 'testcase' and isset($preAndNext->next->case)) ? 'case' : 'id';
|
|
$title = isset($preAndNext->next->title) ? $preAndNext->next->title : $preAndNext->next->name;
|
|
$title = '#' . $preAndNext->next->$id . ' ' . $title . ' ' . $lang->nextShortcutKey;
|
|
$link = $linkTemplate ? sprintf($linkTemplate, $preAndNext->next->$id) : inLink('view', "ID={$preAndNext->next->$id}");
|
|
echo html::a($link, '<i class="icon-pre icon-chevron-right"></i>', '', "id='next' class='btn' title='$title'");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create changes of one object.
|
|
*
|
|
* @param mixed $old the old object
|
|
* @param mixed $new the new object
|
|
* @static
|
|
* @access public
|
|
* @return array
|
|
*/
|
|
public static function createChanges($old, $new)
|
|
{
|
|
global $config;
|
|
$changes = array();
|
|
$magicQuote = get_magic_quotes_gpc();
|
|
foreach($new as $key => $value)
|
|
{
|
|
if(strtolower($key) == 'lastediteddate') continue;
|
|
if(strtolower($key) == 'lasteditedby') continue;
|
|
if(strtolower($key) == 'assigneddate') continue;
|
|
if(strtolower($key) == 'editedby') continue;
|
|
if(strtolower($key) == 'editeddate') continue;
|
|
if(strtolower($key) == 'uid') continue;
|
|
if(strtolower($key) == 'finisheddate' && $value == '') continue;
|
|
if(strtolower($key) == 'canceleddate' && $value == '') continue;
|
|
if(strtolower($key) == 'closeddate' && $value == '') continue;
|
|
|
|
if($magicQuote) $value = stripslashes($value);
|
|
if(isset($old->$key) and $value != stripslashes($old->$key))
|
|
{
|
|
$diff = '';
|
|
if(substr_count($value, "\n") > 1 or
|
|
substr_count($old->$key, "\n") > 1 or
|
|
strpos('name,title,desc,spec,steps,content,digest,verify,report', strtolower($key)) !== false)
|
|
{
|
|
$diff = commonModel::diff($old->$key, $value);
|
|
}
|
|
$changes[] = array('field' => $key, 'old' => $old->$key, 'new' => $value, 'diff' => $diff);
|
|
}
|
|
}
|
|
return $changes;
|
|
}
|
|
|
|
/**
|
|
* Diff two string. (see phpt)
|
|
*
|
|
* @param string $text1
|
|
* @param string $text2
|
|
* @static
|
|
* @access public
|
|
* @return string
|
|
*/
|
|
public static function diff($text1, $text2)
|
|
{
|
|
$text1 = str_replace(' ', '', trim($text1));
|
|
$text2 = str_replace(' ', '', trim($text2));
|
|
$w = explode("\n", $text1);
|
|
$o = explode("\n", $text2);
|
|
$w1 = array_diff_assoc($w,$o);
|
|
$o1 = array_diff_assoc($o,$w);
|
|
$w2 = array();
|
|
$o2 = array();
|
|
foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1) . "<del>" . trim($val) . "</del>";
|
|
foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1) . "<ins>" . trim($val) . "</ins>";
|
|
$diff = array_merge($w2, $o2);
|
|
ksort($diff);
|
|
return implode("\n", $diff);
|
|
}
|
|
|
|
/**
|
|
* Judge Suhosin Setting whether the actual size of post data is large than the setting size.
|
|
*
|
|
* @param int $countInputVars
|
|
* @static
|
|
* @access public
|
|
* @return bool
|
|
*/
|
|
public static function judgeSuhosinSetting($countInputVars)
|
|
{
|
|
if(extension_loaded('suhosin'))
|
|
{
|
|
$maxPostVars = ini_get('suhosin.post.max_vars');
|
|
$maxRequestVars = ini_get('suhosin.request.max_vars');
|
|
if($countInputVars > $maxPostVars or $countInputVars > $maxRequestVars) return true;
|
|
}
|
|
else
|
|
{
|
|
$maxInputVars = ini_get('max_input_vars');
|
|
if($maxInputVars and $countInputVars > (int)$maxInputVars) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the previous and next object.
|
|
*
|
|
* @param string $type story|task|bug|case
|
|
* @param string $objectID
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function getPreAndNextObject($type, $objectID)
|
|
{
|
|
$preAndNextObject = new stdClass();
|
|
|
|
if(strpos('story, task, bug, testcase, doc', $type) === false) return $preAndNextObject;
|
|
|
|
/* Use existObject when the preAndNextObject of this objectID has exist in session. */
|
|
$existObject = $type . 'PreAndNext';
|
|
if(isset($_SESSION[$existObject]) and $_SESSION[$existObject]['objectID'] == $objectID) return $_SESSION[$existObject]['preAndNextObject'];
|
|
|
|
/* Get objectIDList. */
|
|
$table = $this->config->objectTables[$type];
|
|
$queryCondition = $type . 'QueryCondition';
|
|
$typeOnlyCondition = $type . 'OnlyCondition';
|
|
$queryCondition = $this->session->$queryCondition;
|
|
$orderBy = $type . 'OrderBy';
|
|
$orderBy = $this->session->$orderBy;
|
|
$orderBy = str_replace('`left`', 'left', $orderBy); // process the `left` to left.
|
|
|
|
if(empty($queryCondition) or $this->session->$typeOnlyCondition)
|
|
{
|
|
$queryObjects = $this->dao->select('*')->from($table)->where('id')->eq($objectID)
|
|
->beginIF($queryCondition != false)->orWhere($queryCondition)->fi()
|
|
->beginIF($orderBy != false)->orderBy($orderBy)->fi()
|
|
->query();
|
|
}
|
|
else
|
|
{
|
|
$queryObjects = $this->dao->query($queryCondition . (empty($orderBy) ? '' : " ORDER BY $orderBy"));
|
|
}
|
|
|
|
$preObj = false;
|
|
$preAndNextObject->pre = '';
|
|
$preAndNextObject->next = '';
|
|
while($object = $queryObjects->fetch())
|
|
{
|
|
$key = (!$this->session->$typeOnlyCondition and $type == 'testcase' and isset($object->case)) ? 'case' : 'id';
|
|
$id = $object->$key;
|
|
|
|
/* Get next object. */
|
|
if($preObj === true)
|
|
{
|
|
$preAndNextObject->next = $object;
|
|
break;
|
|
}
|
|
|
|
/* Get pre object. */
|
|
if($id == $objectID)
|
|
{
|
|
if($preObj) $preAndNextObject->pre = $preObj;
|
|
$preObj = true;
|
|
}
|
|
if($preObj !== true) $preObj = $object;
|
|
}
|
|
|
|
$this->session->set($existObject, array('objectID' => $objectID, 'preAndNextObject' => $preAndNextObject));
|
|
return $preAndNextObject;
|
|
}
|
|
|
|
/**
|
|
* Save one executed query.
|
|
*
|
|
* @param string $sql
|
|
* @param string $objectType story|task|bug|testcase
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function saveQueryCondition($sql, $objectType, $onlyCondition = true)
|
|
{
|
|
/* Set the query condition session. */
|
|
if($onlyCondition)
|
|
{
|
|
$queryCondition = explode('WHERE', $sql);
|
|
$queryCondition = isset($queryCondition[1]) ? $queryCondition[1] : '';
|
|
if($queryCondition)
|
|
{
|
|
$queryCondition = explode('ORDER', $queryCondition);
|
|
$queryCondition = str_replace('t1.', '', $queryCondition[0]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$queryCondition = explode('ORDER', $sql);
|
|
$queryCondition = $queryCondition[0];
|
|
}
|
|
$queryCondition = trim($queryCondition);
|
|
if(empty($queryCondition)) $queryCondition = "1=1";
|
|
|
|
$this->session->set($objectType . 'QueryCondition', $queryCondition);
|
|
$this->session->set($objectType . 'OnlyCondition', $onlyCondition);
|
|
|
|
/* Set the query condition session. */
|
|
$orderBy = explode('ORDER BY', $sql);
|
|
$orderBy = isset($orderBy[1]) ? $orderBy[1] : '';
|
|
if($orderBy)
|
|
{
|
|
$orderBy = explode('LIMIT', $orderBy);
|
|
$orderBy = $orderBy[0];
|
|
if($onlyCondition) $orderBy = str_replace('t1.', '', $orderBy);
|
|
}
|
|
$this->session->set($objectType . 'OrderBy', $orderBy);
|
|
}
|
|
|
|
/**
|
|
* Remove duplicate for story, task, bug, case, doc.
|
|
*
|
|
* @param string $type e.g. story task bug case doc.
|
|
* @param array|object $data
|
|
* @param string $condition
|
|
* @access public
|
|
* @return array
|
|
*/
|
|
public function removeDuplicate($type, $data = '', $condition = '')
|
|
{
|
|
$table = $this->config->objectTables[$type];
|
|
$titleField = $type == 'task' ? 'name' : 'title';
|
|
$date = date(DT_DATETIME1, time() - $this->config->duplicateTime);
|
|
$dateField = $type == 'doc' ? 'addedDate' : 'openedDate';
|
|
$titles = $data->$titleField;
|
|
|
|
if(empty($titles)) return false;
|
|
$duplicate = $this->dao->select("id,$titleField")->from($table)
|
|
->where('deleted')->eq(0)
|
|
->andWhere($titleField)->in($titles)
|
|
->andWhere($dateField)->ge($date)->fi()
|
|
->beginIF($condition)->andWhere($condition)->fi()
|
|
->fetchPairs();
|
|
|
|
if($duplicate and is_string($titles)) return array('stop' => true, 'duplicate' => key($duplicate));
|
|
if($duplicate and is_array($titles))
|
|
{
|
|
foreach($titles as $i => $title)
|
|
{
|
|
if(in_array($title, $duplicate)) unset($titles[$i]);
|
|
}
|
|
$data->$titleField = $titles;
|
|
}
|
|
return array('stop' => false, 'data' => $data);
|
|
}
|
|
|
|
/**
|
|
* Append order by.
|
|
*
|
|
* @param string $orderBy
|
|
* @param string $append
|
|
* @access public
|
|
* @return string
|
|
*/
|
|
public function appendOrder($orderBy, $append = 'id')
|
|
{
|
|
list($firstOrder) = explode(',', $orderBy);
|
|
$sort = strpos($firstOrder, '_') === false ? '_asc' : strstr($firstOrder, '_');
|
|
return strpos($orderBy, $append) === false ? $orderBy . ',' . $append . $sort : $orderBy;
|
|
}
|
|
|
|
/**
|
|
* Check field exists
|
|
*
|
|
* @param string $table
|
|
* @param string $field
|
|
* @access public
|
|
* @return bool
|
|
*/
|
|
public function checkField($table, $field)
|
|
{
|
|
$fields = $this->dao->query("DESC $table")->fetchAll();
|
|
$hasField = false;
|
|
foreach($fields as $fieldObj)
|
|
{
|
|
if($field == $fieldObj->Field)
|
|
{
|
|
$hasField = true;
|
|
break;
|
|
}
|
|
}
|
|
return $hasField;
|
|
}
|
|
|
|
/**
|
|
* Check upgrade's status file is ok or not.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function checkUpgradeStatus()
|
|
{
|
|
$statusFile = $this->loadModel('upgrade')->checkSafeFile();
|
|
if($statusFile)
|
|
{
|
|
$cmd = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? $this->lang->upgrade->createFileWinCMD : $this->lang->upgrade->createFileLinuxCMD;
|
|
$cmd = sprintf($cmd, $statusFile);
|
|
|
|
echo "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' /></head><body>";
|
|
echo "<table align='center' style='margin-top:100px; border:1px solid gray; font-size:14px;padding:8px;'><tr><td>";
|
|
printf($this->lang->upgrade->setStatusFile, $cmd, $statusFile);
|
|
die('</td></tr></table></body></html>');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check the user has permission to access this method, if not, locate to the login page or deny page.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function checkPriv()
|
|
{
|
|
$module = $this->app->getModuleName();
|
|
$method = $this->app->getMethodName();
|
|
if(isset($this->app->user->modifyPassword) and $this->app->user->modifyPassword and ($module != 'my' or $method != 'changepassword')) die(js::locate(helper::createLink('my', 'changepassword')));
|
|
if($this->isOpenMethod($module, $method)) return true;
|
|
if(!$this->loadModel('user')->isLogon() and $this->server->php_auth_user) $this->user->identifyByPhpAuth();
|
|
if(!$this->loadModel('user')->isLogon() and $this->cookie->za) $this->user->identifyByCookie();
|
|
|
|
if(isset($this->app->user))
|
|
{
|
|
if(!commonModel::hasPriv($module, $method)) $this->deny($module, $method);
|
|
}
|
|
else
|
|
{
|
|
$referer = helper::safe64Encode($this->app->getURI(true));
|
|
die(js::locate(helper::createLink('user', 'login', "referer=$referer")));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check the user has permisson of one method of one module.
|
|
*
|
|
* @param string $module
|
|
* @param string $method
|
|
* @static
|
|
* @access public
|
|
* @return bool
|
|
*/
|
|
public static function hasPriv($module, $method, $object = null)
|
|
{
|
|
global $app, $lang;
|
|
|
|
/* Check is the super admin or not. */
|
|
if(!empty($app->user->admin)) return true;
|
|
/* If not super admin, check the rights. */
|
|
$rights = $app->user->rights['rights'];
|
|
$acls = $app->user->rights['acls'];
|
|
$module = strtolower($module);
|
|
$method = strtolower($method);
|
|
|
|
if(isset($rights[$module][$method]))
|
|
{
|
|
if(!commonModel::hasDBPriv($object, $module, $method)) return false;
|
|
|
|
if(empty($acls['views'])) return true;
|
|
$menu = isset($lang->menugroup->$module) ? $lang->menugroup->$module : $module;
|
|
$menu = strtolower($menu);
|
|
if($menu != 'qa' and !isset($lang->$menu->menu)) return true;
|
|
if($menu == 'my' or $menu == 'index' or $module == 'tree') return true;
|
|
if($module == 'company' and $method == 'dynamic') return true;
|
|
if($module == 'action' and $method == 'editcomment') return true;
|
|
if(!isset($acls['views'][$menu])) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static function hasDBPriv($object, $module = null, $method = null)
|
|
{
|
|
global $app;
|
|
|
|
if(!empty($app->user->admin)) return true;
|
|
if($module = 'todo' and ($method == 'create' or $method == 'batchcreate')) return true;
|
|
if($module = 'effort' and ($method == 'createforobject' or $method == 'batchcreate')) return true;
|
|
|
|
// limited project
|
|
$limitedProject = false;
|
|
if(!empty($module) && $module == 'task' && !empty($object->project) or
|
|
!empty($module) && $module == 'project' && !empty($object->id))
|
|
{
|
|
$objectID = '';
|
|
if(!empty($object->id)) $objectID = $object->id;
|
|
if(!empty($object->id) && !empty($object->project)) $objectID = $object->project;
|
|
|
|
$limitedProjects = !empty($_SESSION['limitedProjects']) ? $_SESSION['limitedProjects'] : '';
|
|
if(strpos(",{$limitedProjects},", ",$objectID,") !== false) $limitedProject = true;
|
|
}
|
|
|
|
if(empty($app->user->rights['rights']['my']['limited']) && !$limitedProject) return true;
|
|
|
|
if(!is_null($method) && strpos($method, 'batch') === 0) return false;
|
|
if(!is_null($method) && strpos($method, 'link') === 0) return false;
|
|
if(!is_null($method) && strpos($method, 'create') === 0) return false;
|
|
if(!is_null($method) && strpos($method, 'import') === 0) return false;
|
|
|
|
if(is_null($object)) return true;
|
|
|
|
if(!empty($object->openedBy) && $object->openedBy == $app->user->account or
|
|
!empty($object->addedBy) && $object->addedBy == $app->user->account or
|
|
!empty($object->assignedTo) && $object->assignedTo == $app->user->account or
|
|
!empty($object->finishedBy) && $object->finishedBy == $app->user->account or
|
|
!empty($object->canceledBy) && $object->canceledBy == $app->user->account or
|
|
!empty($object->closedBy) && $object->closedBy == $app->user->account or
|
|
!empty($object->lastEditedBy) && $object->lastEditedBy == $app->user->account)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check whether IP in white list.
|
|
*
|
|
* @access public
|
|
* @return bool
|
|
*/
|
|
public function checkIP()
|
|
{
|
|
$ip = $this->server->remote_addr;
|
|
|
|
$ipWhiteList = $this->config->ipWhiteList;
|
|
|
|
/* If the ip white list is '*'. */
|
|
if($ipWhiteList == '*') return true;
|
|
|
|
/* The ip is same as ip in white list. */
|
|
if($ip == $ipWhiteList) return true;
|
|
|
|
/* If the ip in white list is like 192.168.1.1-192.168.1.10. */
|
|
if(strpos($ipWhiteList, '-') !== false)
|
|
{
|
|
list($min, $max) = explode('-', $ipWhiteList);
|
|
$min = ip2long(trim($min));
|
|
$max = ip2long(trim($max));
|
|
$ip = ip2long(trim($ip));
|
|
|
|
return $ip >= $min and $ip <= $max;
|
|
}
|
|
|
|
/* If the ip in white list is in IP/CIDR format eg 127.0.0.1/24. Thanks to zcat. */
|
|
if(strpos($ipWhiteList, '/') == false) $ipWhiteList .= '/32';
|
|
list($ipWhiteList, $netmask) = explode('/', $ipWhiteList, 2);
|
|
|
|
$ip = ip2long($ip);
|
|
$ipWhiteList = ip2long($ipWhiteList);
|
|
$wildcard = pow(2, (32 - $netmask)) - 1;
|
|
$netmask = ~ $wildcard;
|
|
|
|
return (($ip & $netmask) == ($ipWhiteList & $netmask));
|
|
}
|
|
|
|
/**
|
|
* Replace the %s of one key of a menu by $params.
|
|
*
|
|
* All the menus are defined in the common's language file. But there're many dynamic params, so in the defination,
|
|
* we used %s as placeholder. These %s should be setted in one module.
|
|
*
|
|
* The items of one module's menu may be an string or array. For example, please see module/common/lang.
|
|
*
|
|
* @param string $object the menus of one module
|
|
* @param string $key the menu item to be replaced
|
|
* @param string $params the params passed to the menu item
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public static function setMenuVars($menu, $key, $params)
|
|
{
|
|
if(!isset($menu->$key)) return false;
|
|
|
|
if(is_array($params))
|
|
{
|
|
if(is_array($menu->$key))
|
|
{
|
|
$menu->$key = (object)$menu->$key;
|
|
$menu->$key->link = vsprintf($menu->$key->link, $params);
|
|
$menu->$key = (array)$menu->$key;
|
|
}
|
|
else
|
|
{
|
|
$menu->$key = vsprintf($menu->$key, $params);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(is_array($menu->$key))
|
|
{
|
|
$menu->$key = (object)$menu->$key;
|
|
$menu->$key->link = sprintf($menu->$key->link, $params);
|
|
$menu->$key = (array)$menu->$key;
|
|
}
|
|
else
|
|
{
|
|
$menu->$key = sprintf($menu->$key, $params);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the full url of the system.
|
|
*
|
|
* @access public
|
|
* @return string
|
|
*/
|
|
public static function getSysURL()
|
|
{
|
|
$httpType = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? 'https' : 'http';
|
|
$httpHost = $_SERVER['HTTP_HOST'];
|
|
return "$httpType://$httpHost";
|
|
}
|
|
|
|
/**
|
|
* Check whether view type is tutorial
|
|
* @access public
|
|
* @return boolean
|
|
*/
|
|
public static function isTutorialMode()
|
|
{
|
|
return (isset($_SESSION['tutorialMode']) and $_SESSION['tutorialMode']);
|
|
}
|
|
|
|
/**
|
|
* Convert items to Pinyin.
|
|
*
|
|
* @param array $items
|
|
* @static
|
|
* @access public
|
|
* @return array
|
|
*/
|
|
public static function convert2Pinyin($items)
|
|
{
|
|
global $app;
|
|
static $allConverted = array();
|
|
static $pinyin;
|
|
if(empty($pinyin)) $pinyin = $app->loadClass('pinyin');
|
|
|
|
$sign = ' aNdAnD ';
|
|
$notConvertedItems = array_diff($items, array_keys($allConverted));
|
|
|
|
if($notConvertedItems)
|
|
{
|
|
$convertedPinYin = $pinyin->romanize(join($sign, $notConvertedItems));
|
|
$itemsPinYin = explode(trim($sign), $convertedPinYin);
|
|
foreach($notConvertedItems as $item)
|
|
{
|
|
$itemPinYin = array_shift($itemsPinYin);
|
|
$wordsPinYin = explode("\t", trim($itemPinYin));
|
|
|
|
$abbr = '';
|
|
foreach($wordsPinYin as $i => $wordPinyin)
|
|
{
|
|
if($wordPinyin) $abbr .= $wordPinyin[0];
|
|
}
|
|
|
|
$allConverted[$item] = strtolower(join($wordsPinYin) . ' ' . $abbr);
|
|
}
|
|
}
|
|
|
|
$convertedItems = array();
|
|
foreach($items as $item) $convertedItems[$item] = zget($allConverted, $item, null);
|
|
|
|
return $convertedItems;
|
|
}
|
|
|
|
/**
|
|
* Check an entry.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function checkEntry()
|
|
{
|
|
if(!$this->session->valid_entry)
|
|
{
|
|
if(!$this->session->entry_code) $this->response(340001);
|
|
if($this->session->valid_entry != md5(md5($this->get->code) . $this->server->remote_addr)) $this->response(340002);
|
|
return true;
|
|
}
|
|
|
|
if(!$this->get->code) $this->response(300001);
|
|
if(!$this->get->token) $this->response(300002);
|
|
|
|
$entry = $this->loadModel('entry')->getByCode($this->get->code);
|
|
if(!$entry) $this->response(310001);
|
|
if(!$entry->key) $this->response(310002);
|
|
|
|
$this->checkEntryIP($entry->ip);
|
|
$this->checkEntryToken($entry->key);
|
|
|
|
$this->session->set('ENTRY_CODE', $this->get->code);
|
|
$this->session->set('VALID_ENTRY', md5(md5($this->get->code) . $this->server->remote_addr));
|
|
$this->loadModel('entry')->saveLog($entry->id, $this->server->request_uri);
|
|
}
|
|
|
|
/**
|
|
* Check ip of an entry.
|
|
*
|
|
* @param string $ip
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function checkEntryIP($ip)
|
|
{
|
|
$ipWhiteList = $this->config->ipWhiteList;
|
|
$this->config->ipWhiteList = $ip;
|
|
$result = $this->checkIP();
|
|
$this->config->ipWhiteList = $ipWhiteList;
|
|
if(!$result) $this->response(320001);
|
|
}
|
|
|
|
/**
|
|
* Check token of an entry.
|
|
*
|
|
* @param string $key
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function checkEntryToken($key)
|
|
{
|
|
parse_str($this->server->query_String, $queryString);
|
|
unset($queryString['token']);
|
|
$queryString = http_build_query($queryString);
|
|
if($_GET['token'] != md5(md5($queryString) . $key)) $this->response(330001);
|
|
}
|
|
|
|
/**
|
|
* Response.
|
|
*
|
|
* @param int $code
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function response($code)
|
|
{
|
|
$response = new stdclass();
|
|
$response->errcode = $code;
|
|
$response->errmsg = $this->lang->error->entry[$code];
|
|
|
|
die(helper::jsonEncode($response));
|
|
}
|
|
}
|
|
|
|
class common extends commonModel
|
|
{
|
|
}
|