| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351 |
- <?php /**
- * The model file of custom module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
- * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Congzhi Chen <congzhi@cnezsoft.com>
- * @package custom
- * @version $Id$
- * @link https://www.zentao.net
- */
- class customModel extends model
- {
- /**
- * 获取自定义语言项。
- * Get all custom lang.
- *
- * @access public
- * @return array|false
- */
- public function getAllLang()
- {
- $currentLang = $this->app->getClientLang();
- $allCustomLang = $this->customTao->getCustomLang();
- if(!$allCustomLang) return false;
- $sectionLang = array();
- foreach($allCustomLang as $customLang)
- {
- $sectionLang[$customLang->module][$customLang->section][$customLang->lang] = $customLang->lang;
- }
- $processedLang = array();
- foreach($allCustomLang as $customLang)
- {
- if(isset($sectionLang[$customLang->module][$customLang->section]['all']) && isset($sectionLang[$customLang->module][$customLang->section][$currentLang]) && $customLang->lang == 'all') continue;
- /* Process list featureBar and more language. */
- if(strpos($customLang->section, 'featureBar-') !== false || strpos($customLang->section, 'moreSelects-') !== false)
- {
- $sections = explode('-', $customLang->section);
- $sections = array_reverse($sections);
- if(!isset($processedLang[$customLang->module])) $processedLang[$customLang->module] = array();
- $sectionArr = array($customLang->key => $customLang->value);
- foreach($sections as $section)
- {
- $sectionKey = key($sectionArr);
- $sectionArr[$section] = $sectionArr;
- if($sectionKey != $section) unset($sectionArr[$sectionKey]);
- }
- if(!empty($sectionArr)) $processedLang[$customLang->module] = array_merge_recursive($processedLang[$customLang->module], $sectionArr);
- }
- else
- {
- if($customLang->module == 'productMenu' && $customLang->key == 'system') $this->lang->product->system = $customLang->value;
- $processedLang[$customLang->module][$customLang->section][$customLang->key] = $customLang->value;
- }
- }
- return $processedLang;
- }
- /**
- * 设置自定义语言项。
- * Set value of an item.
- *
- * @param string $path zh-cn.story.soucreList.customer.1
- * @param string $value
- * @access public
- * @return bool
- */
- public function setItem($path, $value = '')
- {
- $level = substr_count($path, '.');
- $section = '';
- $system = 1;
- if($level <= 1) return false;
- if($level == 2) list($lang, $module, $key) = explode('.', $path);
- if($level == 3) list($lang, $module, $section, $key) = explode('.', $path);
- if($level == 4) list($lang, $module, $section, $key, $system) = explode('.', $path);
- $item = new stdclass();
- $item->lang = $lang;
- $item->module = $module;
- $item->section = $section;
- $item->key = $key;
- $item->value = $value;
- $item->system = $system;
- if(!$this->app->upgrading)
- {
- $item->vision = $this->config->vision;
- if(in_array("{$item->module}-{$item->section}", $this->config->custom->nonInterface->lang)) $item->vision = 'all';
- if($item->module == 'feedback') $item->vision = 'all';
- }
- $this->dao->replace(TABLE_LANG)->data($item)->exec();
- return !dao::isError();
- }
- /**
- * 获取自定义语言项。
- * Get value of custom items.
- *
- * @param string $paramString see parseItemParam();
- * @access public
- * @return array
- */
- public function getItems($paramString)
- {
- return $this->prepareSQL($this->parseItemParam($paramString), 'select')->orderBy('lang,id')->fetchAll('key', false);
- }
- /**
- * 删除自定义项。
- * Delete items.
- *
- * @param string $paramString see parseItemParam();
- * @access public
- * @return bool
- */
- public function deleteItems($paramString)
- {
- $this->prepareSQL($this->parseItemParam($paramString), 'delete')->exec();
- return !dao::isError();
- }
- /**
- * 解析选择或删除项的参数字符串。
- * Parse the param string for select or delete items.
- *
- * @param string $paramString lang=xxx&module=story§ion=sourceList&key=customer and so on.
- * @access public
- * @return array
- */
- public function parseItemParam($paramString)
- {
- /* Parse the param string into array. */
- parse_str($paramString, $params);
- /* Init fields not set in the param string. */
- $fields = 'lang,module,section,key,vision';
- $fields = explode(',', $fields);
- foreach($fields as $field)
- {
- if(isset($params[$field])) continue;
- $params[$field] = '';
- }
- return $params;
- }
- /**
- * 创建一个DAO对象来选择或删除一条或多条记录。
- * Create a DAO object to select or delete one or more records.
- *
- * @param array $params the params parsed by parseItemParam() method.
- * @param string $method select|delete.
- * @access public
- * @return object
- */
- public function prepareSQL($params, $method = 'select')
- {
- return $this->dao->$method('*')->from(TABLE_LANG)->where('1 = 1')
- ->beginIF($params['lang'])->andWhere('lang')->in($params['lang'])->fi()
- ->beginIF($params['module'])->andWhere('module')->in($params['module'])->fi()
- ->beginIF($params['section'])->andWhere('section')->in($params['section'])->fi()
- ->beginIF($params['key'])->andWhere('`key`')->in($params['key'])->fi()
- ->beginIF($params['vision'])->andWhere('`vision`')->in('all,' . $params['vision'])->fi();
- }
- /**
- * 通过配置文件设置菜单。
- * Build menu data from config
- *
- * @param object|array $allMenu
- * @param string|array $customMenu
- * @param string $module
- * @access public
- * @return array
- */
- public static function setMenuByConfig($allMenu, $customMenu, $module = '')
- {
- global $app, $lang;
- $tab = $app->tab;
- list($customMenuMap, $order) = static::buildCustomMenuMap($allMenu, $customMenu, $module);
- /* Merge fileMenu && customMenu. */
- foreach($customMenuMap as $name => &$item)
- {
- if(is_object($allMenu) && !isset($allMenu->{$name})) $allMenu->{$name} = $item;
- if(is_array($allMenu) && !isset($allMenu[$name])) $allMenu[$name] = $item;
- if(is_object($allMenu) && isset($allMenu->{$name}))
- {
- $menuItem = (array)$allMenu->{$name};
- if(isset($menuItem['icon'])) $item->icon = $menuItem['icon'];
- }
- }
- $menu = static::buildMenuItems($allMenu, $customMenuMap, $module, $order);
- ksort($menu, SORT_NUMERIC);
- if(!isset($lang->{$tab})) return array();
- /* Set divider in main && module menu. */
- if(!isset($lang->{$tab}->menuOrder))
- {
- if(!isset($lang->{$tab})) $tab == 'my';
- $lang->{$tab}->menuOrder = array();
- }
- ksort($lang->{$tab}->menuOrder, SORT_NUMERIC);
- $group = 0;
- $dividerOrders = array();
- foreach($lang->{$tab}->menuOrder as $name)
- {
- if(isset($lang->{$tab}->dividerMenu) && strpos($lang->{$tab}->dividerMenu, ",{$name},") !== false) $group++;
- $dividerOrders[$name] = $group;
- }
- $isFirst = true; // No divider before First item.
- $group = 0;
- foreach($menu as $item)
- {
- $isNormalItem = $module == 'main' && isset($item->name) && $item->name != 'other';
- if($isNormalItem && isset($dividerOrders[$item->name]) && $dividerOrders[$item->name] > $group)
- {
- $menu[$item->order]->divider = $isFirst ? false : true;
- $group = $dividerOrders[$item->name];
- }
- else
- {
- $isFirst = false;
- if(!isset($menu[$item->order]->divider)) $menu[$item->order]->divider = false;
- }
- }
- return array_values($menu);
- }
- /**
- * 构造自定义导航数据。
- * Build custom menu data.
- *
- * @param array|string $customMenu
- * @param string $module
- * @static
- * @access public
- * @return array
- * @param object|mixed[] $allMenu
- */
- public static function buildCustomMenuMap($allMenu, $customMenu = '', $module = '')
- {
- global $lang;
- $customMenuMap = array();
- $order = 1;
- if($customMenu && is_array($customMenu))
- {
- $prev = '';
- foreach($customMenu as $customMenuItem)
- {
- if(empty($customMenuItem->name)) continue;
- $name = $customMenuItem->name;
- if(!isset($customMenuItem->order)) $customMenuItem->order = $order;
- if($prev == 'divider') $customMenuItem->divider = true;
- if($name != 'divider') $customMenuMap[$name] = $customMenuItem;
- $prev = $name;
- $order ++;
- }
- }
- elseif($module)
- {
- $menuOrder = array();
- if($module == 'main' && isset($lang->menuOrder))
- {
- $menuOrder = $lang->menuOrder;
- }
- elseif(isset($lang->menu->{$module}))
- {
- $moduleMenu = is_object($lang->menu->$module) ? (array)$lang->menu->$module : $lang->menu->$module;
- if(is_array($moduleMenu) && isset($moduleMenu['menuOrder'])) $menuOrder = $moduleMenu['menuOrder'];
- }
- if($menuOrder)
- {
- ksort($menuOrder);
- foreach($menuOrder as $name)
- {
- /* If menu is removed, delete the menuOrder. */
- if(!isset($allMenu->$name)) continue;
- $item = new stdclass();
- $item->name = $name;
- $item->hidden = false;
- $item->order = $order ++;
- $customMenuMap[$name] = $item;
- }
- }
- }
- return array($customMenuMap, $order);
- }
- /**
- * 构造菜单数据。
- * Build menu data.
- *
- * @param object|array $allMenu
- * @param array $customMenuMap
- * @param string $menuModuleName
- * @param int $order
- * @static
- * @access public
- * @return array
- */
- public static function buildMenuItems($allMenu, $customMenuMap, $menuModuleName, $order = 1)
- {
- global $config, $app;
- $menu = array();
- $isTutorialMode = commonModel::isTutorialMode();
- $module = $menuModuleName;
- foreach($allMenu as $name => $item)
- {
- $name = (string)$name;
- if(is_object($item)) $item = (array)$item;
- /* The variable of item has not link && is not link then ignore it. */
- $link = (is_array($item) && isset($item['link'])) ? $item['link'] : $item;
- if(!is_string($link)) continue;
- $subMenu = array();
- $label = $link;
- $hasPriv = true;
- $method = '';
- if(strpos($link, '|') !== false)
- {
- $link = explode('|', $link);
- list($label, $module, $method) = $link;
- $methodName = $method;
- /* 需求列表按照对应的需求模块鉴权。 */
- if($module == 'product' && $method == 'browse')
- {
- $params = zget($link, 3, '');
- preg_match('/storyType=([^&]*)/', $params, $matches);
- $methodName = !empty($matches[1]) ? $matches[1] : $methodName;
- }
- $hasPriv = commonModel::hasPriv($module, $methodName, null, zget($link, 3, ''));
- /* Fix bug #20464 */
- if(isset($vars)) unset($vars);
- if(!$hasPriv && is_array($item) && isset($item['subMenu']))
- {
- foreach($item['subMenu'] as $subMenu)
- {
- if(!isset($subMenu['link']) || strpos($subMenu['link'], '|') === false) continue;
- if(strpos("|program|product|project|execution|qa|", "|{$app->tab}|") === false && strpos($subMenu['link'], '%s') !== false) continue;
- list($subLabel, $module, $method) = explode('|', $subMenu['link']);
- if(count(explode('|', $subMenu['link'])) > 3) list($subLabel, $module, $method, $vars) = explode('|', $subMenu['link']);
- $hasPriv = commonModel::hasPriv($module, $method);
- if($hasPriv) break;
- }
- }
- if($module == 'execution' && $method == 'more') $hasPriv = true;
- if($module == 'project' && $method == 'other') $hasPriv = true;
- if(!$hasPriv && isset($vars)) unset($vars);
- }
- if($isTutorialMode || $hasPriv)
- {
- $itemLink = '';
- if($module && $method)
- {
- $itemLink = array('module' => $module, 'method' => $method);
- if(isset($link[3])) $itemLink['vars'] = $link[3];
- if(isset($vars)) $itemLink['vars'] = $vars;
- if(is_array($item) && isset($item['target'])) $itemLink['target'] = $item['target'];
- }
- /* Process menu item's order and hidden attirbute. */
- $menuItem = static::buildMenuItem($item, $customMenuMap, $name, $label, $itemLink, $isTutorialMode, $subMenu);
- $menuItem->order = (isset($customMenuMap[$name]) && isset($customMenuMap[$name]->order) ? $customMenuMap[$name]->order : $order ++);
- if(!empty($customMenuMap) && !empty($customMenuMap[$name]->hidden)) $menuItem->hidden = true; // 自定义过滤掉的菜单不显示。
- if(isset($customMenuMap[$name]) && isset($customMenuMap[$name]->divider)) $menuItem->divider = true;
- if($app->viewType == 'mhtml' && isset($config->custom->moblieHidden[$menuModuleName]) && in_array($name, $config->custom->moblieHidden[$menuModuleName])) $menuItem->hidden = 1; // Hidden menu by config in mobile.
- while(isset($menu[$menuItem->order])) $menuItem->order ++;
- $menu[$menuItem->order] = $menuItem;
- }
- }
- return $menu;
- }
- /**
- * 构造菜单数据项。
- * Build menu item.
- *
- * @param array|string $item
- * @param int $customMenuMap
- * @param string $name
- * @param string $label
- * @param string|array $itemLink
- * @param bool $isTutorialMode
- * @param array $subMenu
- * @static
- * @access public
- * @return object
- */
- public static function buildMenuItem($item, $customMenuMap, $name = '', $label = '', $itemLink = '', $isTutorialMode = false, $subMenu = array())
- {
- /* 用例列表featureBar的分割线。 */
- if($item === '-')
- {
- $menuItem = new stdclass();
- $menuItem->type = 'divider';
- return $menuItem;
- }
- if(is_array($item) && (isset($item['subMenu']) || isset($item['dropMenu'])))
- {
- foreach(array('subMenu', 'dropMenu') as $key)
- {
- if(!isset($item[$key])) continue;
- foreach($item[$key] as $subItem)
- {
- if(isset($subItem->link['module']) && isset($subItem->link['method'])) $subItem->hidden = !common::hasPriv($subItem->link['module'], $subItem->link['method']);
- }
- }
- }
- $menuItem = new stdclass();
- $menuItem->name = $name;
- $menuItem->link = $itemLink;
- $menuItem->text = $label;
- if(is_array($item) && isset($item['showInMainMenu'])) $menuItem->showInMainMenu = $item['showInMainMenu'];
- if($isTutorialMode) $menuItem->tutorial = true;
- if(isset($customMenuMap[$name]) && isset($customMenuMap[$name]->icon)) $menuItem->icon = $customMenuMap[$name]->icon;
- $attrList = array('class', 'subModule', 'dropMenu', 'alias', 'exclude', 'divider');
- $hidden = strpos($name, 'QUERY') === 0 && !isset($customMenuMap[$name]) ? false : isset($customMenuMap[$name]) && isset($customMenuMap[$name]->hidden) && $customMenuMap[$name]->hidden;
- foreach($attrList as $attr)
- {
- if(!empty($item[$attr])) $menuItem->$attr = $item[$attr];
- }
- if($hidden) $menuItem->hidden = $hidden;
- if($subMenu) $menuItem->subMenu = $subMenu;
- return $menuItem;
- }
- /**
- * 获取模块菜单数据,如果模块是'main'则返回主菜单。
- * Get module menu data, if module is 'main' then return main menu.
- *
- * @param string $module
- * @param bool $isHomeMenu
- * @access public
- * @return array
- */
- public static function getModuleMenu($module = 'main', $isHomeMenu = false)
- {
- global $app, $lang, $config;
- if(empty($module)) $module = 'main';
- $allMenu = new stdclass();
- if($module == 'main' and !empty($lang->menu)) $allMenu = $lang->menu;
- if($module != 'main' and isset($lang->menu->$module))
- {
- $moduleMenu = is_object($lang->menu->$module) ? (array)$lang->menu->$module : $lang->menu->$module;
- if(is_array($moduleMenu) && isset($moduleMenu['subMenu'])) $allMenu = $moduleMenu['subMenu'];
- }
- if($module == 'product' and isset($allMenu->branch)) $allMenu->branch = str_replace('@branch@', $lang->custom->branch, $allMenu->branch);
- /* 获取自定义过的导航。 */
- $customKey = $isHomeMenu ? $app->tab . '-home' : ($module == 'main' ? $app->tab : $app->tab . '-' . $module);
- /* 项目自定义导航的key特殊获取。*/
- if($app->tab == 'project' && !$isHomeMenu && $module == 'main')
- {
- $projectID = isset($_SESSION['project']) ? $_SESSION['project'] : 0;
- $projectModel = $app->dbh->query("SELECT `model` FROM " . TABLE_PROJECT . " WHERE `id` = '$projectID'")->fetch();
- if($projectModel) $customKey = 'project-' . $projectModel->model;
- }
- $customMenu = (isset($config->customMenu->{$customKey}) && !commonModel::isTutorialMode()) ? $config->customMenu->{$customKey}: array();
- if(!empty($customMenu) && is_string($customMenu) && substr($customMenu, 0, 1) === '[') $customMenu = json_decode($customMenu);
- if($module == 'my' && empty($config->global->scoreStatus)) unset($allMenu->score);
- return static::setMenuByConfig($allMenu, $customMenu, $module);
- }
- /**
- * 获取主菜单数据。
- * Get main menu data.
- *
- * @param bool $isHomeMenu
- * @access public
- * @return array
- */
- public static function getMainMenu($isHomeMenu = false)
- {
- return static::getModuleMenu('main', $isHomeMenu);
- }
- /**
- * 获取模块的筛选标签。
- * Get feature menu.
- *
- * @param string $module
- * @param string $method
- * @access public
- * @return array|null
- */
- public static function getFeatureMenu($module, $method)
- {
- global $app, $lang, $config;
- $app->loadLang($module);
- customModel::mergeFeatureBar($module, $method);
- $configKey = $config->global->flow . '_feature_' . $module . '_' . $method;
- $allMenu = isset($lang->$module->featureBar[$method]) ? $lang->$module->featureBar[$method] : null;
- $customMenu = '';
- if(!commonModel::isTutorialMode() && isset($config->customMenu->$configKey)) $customMenu = $config->customMenu->$configKey;
- if(!empty($customMenu) && is_string($customMenu)) $customMenu = json_decode($customMenu);
- return $allMenu ? static::setMenuByConfig($allMenu, $customMenu) : null;
- }
- /**
- * 将查询条件合并到筛选标签中。
- * Merge shortcut query in featureBar.
- *
- * @param string $module
- * @param string $method
- * @access public
- * @return void
- */
- public static function mergeFeatureBar($module, $method)
- {
- global $lang, $app, $config;
- if(!isset($lang->$module->featureBar[$method])) return;
- $queryModule = $module == 'execution' && $method == 'task' ? 'task' : $module;
- if($module == 'product') $queryModule = !empty($_SESSION['storyType']) ? $_SESSION['storyType'] : 'story';
- if(isset($config->$module->queryModule[$method])) $queryModule = $config->$module->queryModule[$method];
- if($module == 'execution' && $method == 'story') $queryModule = 'executionStory';
- $shortcuts = $app->dbQuery('select id, title from ' . TABLE_USERQUERY . " where (`account` = '{$app->user->account}' or `common` = '1') AND `module` = '{$queryModule}' AND `shortcut` = '1' order by id")->fetchAll();
- if($shortcuts)
- {
- $lang->$module->featureBar[$method]['QUERY'] = $lang->custom->common;
- foreach($shortcuts as $shortcut) $lang->custom->queryList[$shortcut->id] = $shortcut->title;
- }
- }
- /**
- * 获取必填字段。
- * Get required fields by config.
- *
- * @param object $moduleConfig
- * @access public
- * @return array
- */
- public function getRequiredFields($moduleConfig)
- {
- $requiredFields = array();
- foreach($moduleConfig as $method => $subConfig)
- {
- if(is_object($subConfig) && isset($subConfig->requiredFields)) $requiredFields[$method] = trim(str_replace(' ', '', $subConfig->requiredFields));
- }
- return $requiredFields;
- }
- /**
- * 获取表单必填字段。
- * Get form required fields.
- *
- * @param string $moduleName
- * @param string $method
- * @access public
- * @return array
- */
- public function getFormFields($moduleName, $method = '')
- {
- $fields = array();
- $moduleLang = $this->lang->{$moduleName};
- $customFields = $this->config->custom->fieldList;
- if(isset($customFields[$moduleName]))
- {
- $fieldList = isset($customFields[$moduleName][$method]) ? $customFields[$moduleName][$method] : $customFields[$moduleName];
- if(!is_string($fieldList)) return $fields;
- if($moduleName == 'user' && $method == 'edit') $this->app->loadConfig('user');
- foreach(explode(',', $fieldList) as $fieldName)
- {
- if($moduleName == 'user' && $method == 'edit' && strpos($this->config->user->contactField, $fieldName) === false && !in_array($fieldName, array('dept', 'role', 'group', 'email', 'commiter'))) continue;
- if($moduleName == 'project' && $fieldName == 'budget' && $this->config->vision == 'lite') continue;
- if($fieldName == 'comment') $fields[$fieldName] = $this->lang->comment;
- if(isset($moduleLang->{$fieldName}) && is_string($moduleLang->{$fieldName})) $fields[$fieldName] = $moduleLang->$fieldName;
- if($moduleName == 'program')
- {
- $fieldKey = substr($method, 0, 3) . ucfirst($fieldName);
- if(isset($moduleLang->{$fieldKey}) && is_string($moduleLang->{$fieldKey})) $fields[$fieldName] = $moduleLang->$fieldKey;
- }
- if($moduleName == 'execution' && in_array($fieldName, array('desc', 'PM', 'code')))
- {
- $fieldKey = 'exec' . ucfirst($fieldName);
- $fields[$fieldName] = $this->lang->execution->{$fieldKey};
- }
- }
- }
- return $fields;
- }
- /**
- * 获取需求概念。
- * Get UR and SR concept.
- *
- * @param int $key
- * @param string $lang
- * @access public
- * @return string|false
- */
- public function getURSRConcept($key, $lang = '')
- {
- if(empty($lang)) $lang = $this->app->getClientLang();
- return $this->dao->select('`value`')->from(TABLE_LANG)
- ->where('lang')->eq($lang)
- ->andWhere('module')->eq('custom')
- ->andWhere('section')->eq('URSRList')
- ->andWhere('`key`')->eq($key)
- ->fetch('value');
- }
- /**
- * 获取需求概念集合。
- * Get UR and SR pairs.
- *
- * @access public
- * @return array
- */
- public function getURSRPairs()
- {
- $lang = $this->app->getClientLang();
- $langData = $this->dao->select('`key`, `value`, `system`')->from(TABLE_LANG)
- ->where('lang')->eq($lang)
- ->andWhere('module')->eq('custom')
- ->andWhere('section')->eq('URSRList')
- ->fetchAll();
- if(empty($langData))
- {
- $URSR = $this->loadModel('setting')->getURSR();
- $langData = $this->dao->select('`key`, `value`, `system`')->from(TABLE_LANG)->where('`key`')->eq($URSR)->andWhere('module')->eq('custom')->andWhere('section')->eq('URSRList')->fetchAll();
- }
- $URSRPairs = array();
- foreach($langData as $content)
- {
- $value = json_decode($content->value);
- if(!$this->config->URAndSR && !$this->config->enableER) $URSRPairs[$content->key] = $value->SRName;
- if($this->config->URAndSR && !$this->config->enableER) $URSRPairs[$content->key] = $value->URName . '/' . $value->SRName;
- if($this->config->URAndSR && $this->config->enableER) $URSRPairs[$content->key] = $value->ERName . '/' . $value->URName . '/' . $value->SRName;
- }
- return $URSRPairs;
- }
- /**
- * 获取用需概念集合。
- * Get UR pairs.
- *
- * @access public
- * @return array
- */
- public function getURPairs()
- {
- $URSRList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('custom')->andWhere('section')->eq('URSRList')->andWhere('lang')->eq($this->app->clientLang)->fetchPairs();
- if(empty($URSRList))
- {
- $URSR = $this->loadModel('setting')->getURSR();
- $URSRList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('custom')->andWhere('section')->eq('URSRList')->andWhere('`key`')->eq($URSR)->fetchPairs();
- }
- $URPairs = array();
- foreach($URSRList as $key => $value)
- {
- $URSR = json_decode($value);
- $URPairs[$key] = $URSR->URName;
- }
- return $URPairs;
- }
- /**
- * 获取软需概念集合。
- * Get SR pairs.
- *
- * @access public
- * @return array
- */
- public function getSRPairs()
- {
- $URSRList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('custom')->andWhere('section')->eq('URSRList')->andWhere('lang')->eq($this->app->clientLang)->fetchPairs();
- if(empty($URSRList))
- {
- $URSR = $this->loadModel('setting')->getURSR();
- $URSRList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('custom')->andWhere('section')->eq('URSRList')->andWhere('`key`')->eq($URSR)->fetchPairs();
- }
- $SRPairs = array();
- foreach($URSRList as $key => $value)
- {
- $URSR = json_decode($value);
- $SRPairs[$key] = $URSR->SRName;
- }
- return $SRPairs;
- }
- /**
- * 获取需求概念列表。
- * Get UR and SR list.
- *
- * @access public
- * @return array
- */
- public function getURSRList()
- {
- $this->app->loadLang('custom');
- $lang = $this->app->getClientLang();
- $URSRDataList = $this->dao->select('`key`, `value`, `system`')->from(TABLE_LANG)
- ->where('lang')->eq($lang)
- ->andWhere('module')->eq('custom')
- ->andWhere('section')->eq('URSRList')
- ->fetchAll();
- if(empty($URSRDataList))
- {
- $URSR = $this->loadModel('setting')->getURSR();
- $URSRDataList = $this->dao->select('`key`, `value`, `system`')->from(TABLE_LANG)->where('`key`')->eq($URSR)->andWhere('module')->eq('custom')->andWhere('section')->eq('URSRList')->fetchAll();
- }
- $URSRList = array();
- foreach($URSRDataList as $URSRData)
- {
- $value = json_decode($URSRData->value);
- $URSRList[$URSRData->key] = new stdclass();
- $URSRList[$URSRData->key]->key = $URSRData->key;
- $URSRList[$URSRData->key]->ERName = $value->ERName;
- $URSRList[$URSRData->key]->SRName = $value->SRName;
- $URSRList[$URSRData->key]->URName = $value->URName;
- $URSRList[$URSRData->key]->system = $URSRData->system;
- }
- return $URSRList;
- }
- /**
- * 保存表单必填字段设置。
- * Save required fields.
- *
- * @param string $moduleName product|story|productplan|release|execution|task|bug|testcase|testsuite|testtask|testreport|caselib|doc|user|project|build
- * @param array $data
- * @access public
- * @return void
- */
- public function saveRequiredFields($moduleName, $data)
- {
- if(isset($this->config->systemDB->$moduleName)) unset($this->config->systemDB->$moduleName);
- if(isset($this->config->personalDB->$moduleName)) unset($this->config->personalDB->$moduleName);
- $this->loadModel($moduleName);
- $systemFields = $this->getRequiredFields($this->config->$moduleName);
- $requiredFields = array();
- if(!empty($systemFields))
- {
- foreach($systemFields as $method => $fields)
- {
- $optionFields = isset($this->config->custom->fieldList[$moduleName][$method]) ? explode(',', $this->config->custom->fieldList[$moduleName][$method]) : array();
- $systemFieldList = explode(',', $this->config->$moduleName->$method->requiredFields);
- foreach($optionFields as $field)
- {
- if(in_array($field, $systemFieldList))
- {
- $key = array_search($field, $systemFieldList);
- unset($systemFieldList[$key]);
- }
- }
- $systemField = implode(',', $systemFieldList);
- /* Keep the original required fields when the fields is empty. */
- if(!isset($data['requiredFields'][$method]))
- {
- $requiredFields[$method]['requiredFields'] = $systemField;
- continue;
- }
- $fields = implode(',', $data['requiredFields'][$method]);
- $systemFields = array_reverse(explode(',', $systemField));
- foreach($systemFields as $field)
- {
- $field = trim($field);
- if(strpos(",$fields,", ",$field,") === false) $fields = "{$field},{$fields}";
- }
- $requiredFields[$method]['requiredFields'] = trim($fields, ',');
- }
- }
- $this->loadModel('setting')->setItems("system.{$moduleName}@{$this->config->vision}", $requiredFields);
- }
- /**
- * 设置产品、项目和迭代概念。
- * Set product and project and sprint concept.
- *
- * @param string $sprintConcept
- * @access public
- * @return bool
- */
- public function setConcept($sprintConcept)
- {
- $this->loadModel('setting');
- $this->setting->setItem('system.custom.sprintConcept', $sprintConcept);
- $this->setting->setItem('system.custom.productProject', '0_' . $sprintConcept);
- /* Change block title. */
- $oldConfig = isset($this->config->custom->sprintConcept) ? $this->config->custom->sprintConcept : '0';
- $newConfig = $sprintConcept;
- foreach($this->config->executionCommonList as $executionCommonList)
- {
- if(!isset($executionCommonList[$oldConfig]) || !isset($executionCommonList[$newConfig]))
- {
- $this->setting->setItem('system.custom.sprintConcept', '0');
- $this->setting->setItem('system.custom.productProject', '0_0');
- continue;
- }
- $this->dao->update(TABLE_BLOCK)->set("`title` = REPLACE(`title`, '{$executionCommonList[$oldConfig]}', '{$executionCommonList[$newConfig]}')")->where('dashboard')->eq('execution')->exec();
- }
- return !dao::isError();
- }
- /**
- * 设置需求概念。
- * Set UR and SR concept.
- *
- * @param array $data
- * @access public
- * @return bool
- */
- public function setURAndSR($data)
- {
- $lang = $this->app->getClientLang();
- $maxKey = $this->dao->select('max(cast(`key` as DECIMAL)) as maxKey')->from(TABLE_LANG)
- ->where('section')->eq('URSRList')
- ->andWhere('module')->eq('custom')
- ->andWhere('lang')->eq($lang)
- ->fetch('maxKey');
- $maxKey = $maxKey ? (int)$maxKey : 1;
- /* If has custom UR and SR name. */
- foreach($data['SRName'] as $key => $SRName)
- {
- $URName = zget($data['URName'], $key, $this->lang->URCommon);
- $ERName = zget($data['ERName'], $key, $this->lang->ERCommon);
- if(!$URName || !$SRName || !$ERName) continue;
- $URSRList = new stdclass();
- $URSRList->ERName = $ERName;
- $URSRList->SRName = $SRName;
- $URSRList->URName = $URName;
- $value = json_encode($URSRList);
- $maxKey += 1;
- $this->setItem("$lang.custom.URSRList.{$maxKey}.0", $value);
- }
- return true;
- }
- /**
- * 编辑需求概念。
- * Edit UR and SR concept.
- *
- * @param int $key
- * @param string $lang zh-cn|zh-tw|en|fr|de
- * @param array $data
- * @access public
- * @return bool
- */
- public function updateURAndSR($key = 0, $lang = '', $data = array())
- {
- if(empty($lang)) $lang = $this->app->getClientLang();
- if(empty($data['SRName']) || empty($data['URName']) || empty($data['ERName'])) return false;
- $oldValue = $this->getURSRConcept($key, $lang);
- $oldValue = json_decode($oldValue);
- if(!$oldValue) return false;
- $URSRList = new stdclass();
- $URSRList->defaultERName = zget($oldValue, 'defaultERName', $oldValue->ERName);
- $URSRList->defaultSRName = zget($oldValue, 'defaultSRName', $oldValue->SRName);
- $URSRList->defaultURName = zget($oldValue, 'defaultURName', $oldValue->URName);
- $URSRList->ERName = empty($data['ERName']) ? $URSRList->defaultERName : $data['ERName'];
- $URSRList->SRName = empty($data['SRName']) ? $URSRList->defaultSRName : $data['SRName'];
- $URSRList->URName = empty($data['URName']) ? $URSRList->defaultURName : $data['URName'];
- $value = json_encode($URSRList);
- $this->dao->update(TABLE_LANG)->set('value')->eq($value)
- ->where('`key`')->eq($key)
- ->andWhere('section')->eq('URSRList')
- ->andWhere('lang')->eq($lang)
- ->andWhere('module')->eq('custom')
- ->exec();
- return true;
- }
- /**
- * 计算启用和不启用的功能。
- * Compute the enabled and disabled features.
- *
- * @access public
- * @return array
- */
- public function computeFeatures()
- {
- /* Check that the project features are enabled. */
- $disabledFeatures = array('program', 'productLine');
- foreach($this->config->custom->dataFeatures as $feature)
- {
- $function = 'has' . ucfirst($feature) . 'Data';
- if(!$this->$function())
- {
- if(in_array($feature, $this->config->custom->projectFeatures))
- {
- if(!isset($disabledFeatures['project'])) $disabledFeatures['project'] = array();
- $disabledFeatures['project'][] = $feature;
- }
- elseif(in_array($feature, array('waterfall', 'waterfallplus')))
- {
- $disabledFeatures[] = 'project' . ucfirst($feature);
- }
- else
- {
- $disabledFeatures[] = $feature;
- }
- }
- }
- if(!isset($disabledFeatures['project'])) $disabledFeatures['project'] = array();
- /* Check that the project features are enabled. */
- $enabledProjectFeatures = array();
- $disabledProjectFeatures = array();
- if(in_array($this->config->edition, array('max', 'ipd')))
- {
- foreach($this->config->custom->projectFeatures as $projectFeature)
- {
- $label = $this->lang->custom->projectFeatures[$projectFeature];
- if(in_array($projectFeature, $disabledFeatures['project']))
- {
- $disabledProjectFeatures[] = $label;
- }
- else
- {
- $enabledProjectFeatures[] = $label;
- }
- }
- }
- return array($disabledFeatures, $enabledProjectFeatures, $disabledProjectFeatures);
- }
- /**
- * 处理项目权限为继承项目集的项目权限。
- * process project priv within a program set.
- *
- * @access public
- * @return bool
- */
- public function processProjectAcl()
- {
- list($projectGroup, $programPM, $stakeholders) = $this->customTao->getDataForUpdateProjectAcl();
- $projectIDList = array();
- foreach($projectGroup as $projects) $projectIDList = array_merge($projectIDList, array_keys($projects));
- $executionGroup = $this->dao->select('project,id')->from(TABLE_EXECUTION)->where('project')->in($projectIDList)->fetchGroup('project', 'id');
- $this->loadModel('user');
- $this->loadModel('action');
- $this->loadModel('personnel');
- foreach($projectGroup as $projects)
- {
- foreach($projects as $project)
- {
- $PM = zget($programPM, $project->parent, '');
- $stakeholder = zget($stakeholders, $project->parent, '');
- if($stakeholder) $stakeholder = implode(',', array_keys($stakeholder));
- $whitelist = rtrim($project->whitelist . ',' . $PM . ',' . $stakeholder);
- $whitelist = explode(',', $whitelist);
- $whitelist = array_filter(array_unique($whitelist));
- $whitelist = implode(',', $whitelist);
- $data = new stdclass();
- $data->acl = 'private';
- $data->whitelist = $whitelist;
- $this->dao->update(TABLE_PROJECT)->data($data)->where('id')->eq($project->id)->exec();
- $whitelist = explode(',', $whitelist);
- $this->personnel->updateWhitelist($whitelist, 'project', $project->id);
- $this->user->updateUserView(array($project->id), 'project');
- if(zget($executionGroup, $project->id, ''))
- {
- $executions = zget($executionGroup, $project->id);
- $executionPairs = array();
- foreach($executions as $executionID => $execution) $executionPairs[$executionID] = $executionID;
- $this->user->updateUserView($executionPairs, 'sprint');
- }
- $changes = common::createChanges($project, $data);
- $actionID = $this->action->create('project', $project->id, 'SwitchToLight');
- $this->action->logHistory($actionID, $changes);
- }
- }
- return !dao::isError();
- }
- /**
- * 根据管理模式禁用相关功能。
- * Disable related features based on the management mode.
- *
- * @param string $mode
- * @access public
- * @return void
- */
- public function disableFeaturesByMode($mode)
- {
- $disabledFeatures = '';
- if($mode == 'light')
- {
- /* Check whether the product or project data in the system is empty. */
- foreach($this->config->custom->dataFeatures as $feature)
- {
- $function = 'has' . ucfirst($feature) . 'Data';
- if(!$this->$function())
- {
- if(in_array($feature, $this->config->custom->projectFeatures)) $feature = 'project' . ucfirst($feature);
- /* If the data is empty, this feature is disabled. */
- $disabledFeatures .= "$feature,";
- }
- }
- $disabledFeatures .= 'productTrack,productRoadmap';
- }
- /* Save the features that are disable to the config. */
- $disabledFeatures = rtrim($disabledFeatures, ',');
- $this->loadModel('setting')->setItem('system.common.disabledFeatures', $disabledFeatures);
- $URAndSR = strpos(",$disabledFeatures,", ',productUR,') === false ? '1' : '0';
- $this->setting->setItem('system.custom.URAndSR', $URAndSR);
- $disableER = strpos(",$disabledFeatures,", ',productER,') !== false;
- $enableER = (!$URAndSR || $disableER) ? '0' : '1';
- $this->setting->setItem('system.custom.enableER', $enableER);
- $this->processMeasrecordCron();
- }
- /**
- * 检查系统中是否有业务需求数据。
- * Check whether there is epic data in the system.
- *
- * @access public
- * @return int
- */
- public function hasProductERData()
- {
- return (int)$this->dao->select('*')->from(TABLE_STORY)->where('type')->eq('epic')->andWhere('deleted')->eq('0')->count();
- }
- /**
- * 检查系统中是否有用户需求数据。
- * Check whether there is requirement data in the system.
- *
- * @access public
- * @return int
- */
- public function hasProductURData()
- {
- return (int)$this->dao->select('*')->from(TABLE_STORY)->where('type')->eq('requirement')->andWhere('deleted')->eq('0')->count();
- }
- /**
- * 检查系统中是否有瀑布项目数据。
- * Check whether there is waterfall project data in the system.
- *
- * @access public
- * @return int
- */
- public function hasWaterfallData()
- {
- return (int)$this->dao->select('*')->from(TABLE_PROJECT)->where('model')->eq('waterfall')->andWhere('deleted')->eq('0')->count();
- }
- /**
- * 检查系统中是否有融合项目数据。
- * Check whether there is waterfallplus project data in the system.
- *
- * @access public
- * @return int
- */
- public function hasWaterfallplusData()
- {
- return (int)$this->dao->select('*')->from(TABLE_PROJECT)->where('model')->eq('waterfallplus')->andWhere('deleted')->eq('0')->count();
- }
- /**
- * 检查系统中是否有资产库数据。
- * Check whether there is assetlib data in the system.
- *
- * @access public
- * @return int
- */
- public function hasAssetlibData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_ASSETLIB)->where('deleted')->eq(0)->count();
- return 0;
- }
- /**
- * 检查系统中是否有问题数据。
- * Check whether there is issue data in the system.
- *
- * @access public
- * @return int
- */
- public function hasIssueData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_ISSUE)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有风险数据。
- * Check whether there is risk data in the system.
- *
- * @access public
- * @return int
- */
- public function hasRiskData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_RISK)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有培训计划数据。
- * Check whether there is gapanalysis data in the system.
- *
- * @access public
- * @return int
- */
- public function hasGapanalysisData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_GAPANALYSIS)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有调研计划数据。
- * Check whether there is researchplan data in the system.
- *
- * @access public
- * @return int
- */
- public function hasResearchplanData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_RESEARCHPLAN)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有机会数据。
- * Check whether there is opportunity data in the system.
- *
- * @access public
- * @return int
- */
- public function hasOpportunityData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_OPPORTUNITY)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有敏捷项目的会议数据。
- * Check whether there is meeting data in the system.
- *
- * @access public
- * @return int
- */
- public function hasMeetingData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_MEETING)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有度量数据。
- * Check whether there is measrecord data in the system.
- *
- * @access public
- * @return int
- */
- public function hasMeasrecordData()
- {
- return 0;
- }
- /**
- * 检查系统中是否有审计数据。
- * Check whether there is auditplan data in the system.
- *
- * @access public
- * @return int
- */
- public function hasAuditplanData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_AUDITPLAN)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有项目活动数据。
- * Check whether there is process data in the system.
- *
- * @access public
- * @return int
- */
- public function hasProcessData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_PROGRAMACTIVITY)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有交付物数据。
- * Check whether there is deliverable data in the system.
- *
- * @access public
- * @return int
- */
- public function hasDeliverableData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_PROJECTDELIVERABLE)->count();
- return 0;
- }
- /**
- * 检查系统中是否有评审数据,有交付物就算有评审。
- * Check whether there is review data in the system.
- *
- * @access public
- * @return int
- */
- public function hasReviewData()
- {
- if(in_array($this->config->edition, array('max', 'ipd')))
- {
- $reviewCount = (int)$this->dao->select('*')->from(TABLE_REVIEW)->where('deleted')->eq('0')->count();
- $deliverableCount = (int)$this->dao->select('*')->from(TABLE_DELIVERABLE)->where('deleted')->eq('0')->count();
- return $reviewCount + $deliverableCount;
- }
- return 0;
- }
- /**
- * 检查系统中是否有变更管理数据。
- * Check whether there is projectchange data in the system.
- *
- * @access public
- * @return int
- */
- public function hasChangeData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_PROJECTCHANGE)->where('deleted')->eq('0')->count();
- return 0;
- }
- /**
- * 检查系统中是否有基线数据。
- * Check whether there is cm data in the system.
- *
- * @access public
- * @return int
- */
- public function hasCmData()
- {
- if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_OBJECT)->where('deleted')->eq('0')->andWhere('type')->eq('taged')->count();
- return 0;
- }
- /**
- * 处理定时任务。
- * Process measrecord cron.
- *
- * @access public
- * @return void
- */
- public function processMeasrecordCron()
- {
- $this->loadModel('setting');
- $closedFeatures = $this->setting->getItem('owner=system&module=common§ion=&key=closedFeatures');
- $disabledFeatures = $this->setting->getItem('owner=system&module=common§ion=&key=disabledFeatures');
- $disabledFeatures = $disabledFeatures . ',' . $closedFeatures;
- $hasProjectMeasrecord = strpos(",{$disabledFeatures},", ',projectMeasrecord,') === false;
- /* Determine whether the cron is enabled based on whether the feature is disabled. */
- $cronStatus = 'normal';
- if(!$hasProjectMeasrecord) $cronStatus = 'stop';
- /* Update the status of the cron. */
- $this->loadModel('cron');
- $cron = $this->dao->select('id,status')->from(TABLE_CRON)->where('command')->like('%methodName=initCrontabQueue')->fetch();
- if($cron && $cron->status != $cronStatus) $this->cron->changeStatus($cron->id, $cronStatus);
- $cron = $this->dao->select('id,status')->from(TABLE_CRON)->where('command')->like('%methodName=execCrontabQueue')->fetch();
- if($cron && $cron->status != $cronStatus) $this->cron->changeStatus($cron->id, $cronStatus);
- }
- }
|