diff --git a/module/custom/control.php b/module/custom/control.php index 790594288b..2f877e40ca 100644 --- a/module/custom/control.php +++ b/module/custom/control.php @@ -12,277 +12,52 @@ class custom extends control { /** - * Index + * Index. * * @access public * @return void */ public function index() { - if($this->config->vision == 'lite') return print(js::locate(inlink('execution'))); + if($this->config->vision == 'lite') return $this->locate(inlink('execution')); - if(common::hasPriv('custom', 'set')) return print(js::locate(inlink('set', "module=project&field=" . key($this->lang->custom->project->fields)))); - if(common::hasPriv('custom', 'product')) return print(js::locate(inlink('product'))); - if(common::hasPriv('custom', 'execution')) return print(js::locate(inlink('execution'))); + if(common::hasPriv('custom', 'set')) return $this->locate(inlink('set', "module=project&field=" . key($this->lang->custom->project->fields))); + if(common::hasPriv('custom', 'product')) return $this->locate(inlink('product')); + if(common::hasPriv('custom', 'execution')) return $this->locate(inlink('execution')); foreach($this->lang->custom->system as $sysObject) { - if(common::hasPriv('custom', $sysObject)) return print(js::locate(inlink($sysObject))); + if(common::hasPriv('custom', $sysObject)) return $this->locate(inlink($sysObject)); } } /** - * Custom + * 设置对象字段的语言项。 + * Set the language items of the object fields. * - * @param string $module - * @param string $field - * @param string $lang + * @param string $module todo|story|task|bug|testcase|testtask|user|project + * @param string $field priList|typeList|statusList|sourceList|reasonList|stageList|reviewRules|reviewResultList|review|severityList|osList|browserList|resolutionList|longlife|resultList|roleList|contactField|deleted|unitList + * @param string $lang all|zh-cn|zh-tw|en|de|fr * @access public * @return void */ public function set(string $module = 'story', string $field = 'priList', string $lang = '') { if(empty($lang)) $lang = $this->app->getClientLang(); - if($module == 'user' and $field == 'priList') $field = 'statusList'; - if($module == 'block' and $field == 'priList')$field = 'closed'; + if($module == 'user' && $field == 'priList') $field = 'statusList'; + if($module == 'block' && $field == 'priList')$field = 'closed'; $currentLang = $this->app->getClientLang(); - $this->app->loadLang($module); - if($lang == 'all') - { - $fieldList = array(); - $items = $this->custom->getItems("lang=all&module=$module§ion=$field&vision={$this->config->vision}"); - foreach($items as $key => $item) - { - $fieldList[$key] = $item->value; - } - } - else - { - $fieldList = zget($this->lang->$module, $field, ''); - } - - if($module == 'project' and $field == 'unitList') - { - $this->app->loadConfig($module); - $unitList = zget($this->config->$module, 'unitList', ''); - $this->view->unitList = explode(',', $unitList); - $this->view->defaultCurrency = zget($this->config->$module, 'defaultCurrency', 'CNY'); - } - if(($module == 'story' or $module == 'demand') and $field == 'reviewRules') - { - $this->app->loadConfig($module); - $this->view->reviewRule = zget($this->config->$module, 'reviewRules', 'allpass'); - $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); - $this->view->superReviewers = zget($this->config->$module, 'superReviewers', ''); - } - if(($module == 'story' or $module == 'testcase' or $module == 'demand') and $field == 'review') - { - $this->app->loadConfig($module); - $this->loadModel('user'); - - if($module == 'story' or $module == 'demand') - { - $this->view->depts = $this->loadModel('dept')->getDeptPairs(); - - $this->view->forceReviewRoles = zget($this->config->$module, 'forceReviewRoles', ''); - $this->view->forceReviewDepts = zget($this->config->$module, 'forceReviewDepts', ''); - - $this->view->forceNotReviewRoles = zget($this->config->$module, 'forceNotReviewRoles', ''); - $this->view->forceNotReviewDepts = zget($this->config->$module, 'forceNotReviewDepts', ''); - } - - $this->view->users = $module == 'story' ? $this->user->getCanCreateStoryUsers() : $this->user->getPairs('noclosed|nodeleted'); - $this->view->needReview = zget($this->config->$module, 'needReview', 1); - $this->view->forceReview = zget($this->config->$module, 'forceReview', ''); - $this->view->forceNotReview = zget($this->config->$module, 'forceNotReview', ''); - } - if($module == 'bug' and $field == 'longlife') - { - $this->app->loadConfig('bug'); - $this->view->longlife = $this->config->bug->longlife; - } - if($module == 'block' and $field == 'closed') - { - $this->loadModel('block'); - $closedBlock = isset($this->config->block->closed) ? $this->config->block->closed : ''; - - $this->view->blockPairs = $this->block->getClosedBlockPairs($closedBlock); - $this->view->closedBlock = $closedBlock; - } - if($module == 'user' and $field == 'deleted') - { - $this->app->loadConfig('user'); - $this->view->showDeleted = isset($this->config->user->showDeleted) ? $this->config->user->showDeleted : '0'; - } + $this->customZen->assignVarsForSet($module, $field, $lang, $currentLang); if(strtolower($this->server->request_method) == "post") { - $postArray = fixer::input('post'); - $keys = array(); - if(isset($postArray->data->keys)) - { - foreach($postArray->data->keys as $key) - { - if($module == 'testtask' and $field == 'typeList' and empty($key)) continue; - if($key && in_array($key, $keys)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->custom->notice->repeatKey, $key))); - $keys[] = $key; - } - } - - if($module == 'project' and $field == 'unitList') - { - $data = fixer::input('post')->join('unitList', ',')->get(); - if(empty($data->unitList)) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->currencyNotEmpty)); - if(empty($data->defaultCurrency)) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->defaultNotEmpty)); - $this->loadModel('setting')->setItems("system.$module", $data); - } - elseif(($module == 'story' or $module == 'demand') and $field == 'review') - { - $data = fixer::input('post') - ->setDefault('forceReview', '') - ->setDefault('forceNotReview', '') - ->setDefault('forceReviewRoles', '') - ->setDefault('forceNotReviewRoles', '') - ->setDefault('forceReviewDepts', '') - ->setDefault('forceNotReviewDepts', '') - ->join('forceReview', ',') - ->join('forceReviewRoles', ',') - ->join('forceReviewDepts', ',') - ->join('forceNotReview', ',') - ->join('forceNotReviewRoles', ',') - ->join('forceNotReviewDepts', ',') - ->get(); - - foreach($data as $key => $value) - { - if($key == 'needReview') continue; - if(strpos($key, 'Not') and $data->needReview == 0) $data->$key = ''; - if(!strpos($key, 'Not') and $data->needReview == 1) $data->$key = ''; - } - - $this->loadModel('setting')->setItems("system.$module@{$this->config->vision}", $data); - } - elseif(($module == 'story' or $module == 'demand') and $field == 'reviewRules') - { - $data = fixer::input('post')->setDefault('superReviewers', '')->join('superReviewers', ',')->get(); - $this->loadModel('setting')->setItems("system.$module@{$this->config->vision}", $data); - } - elseif($module == 'testcase' and $field == 'review') - { - $review = fixer::input('post')->get(); - if($review->needReview) $data = fixer::input('post')->setDefault('forceNotReview', '')->join('forceNotReview', ',')->remove('forceReview')->get(); - if(!$review->needReview) $data = fixer::input('post')->setDefault('forceReview', '')->join('forceReview', ',')->remove('forceNotReview')->get(); - $this->loadModel('setting')->setItems("system.$module", $data); - - $reviewCase = isset($review->reviewCase) ? $review->reviewCase : 0; - if($review->needReview == 0 and $reviewCase) - { - $waitCases = $this->loadModel('testcase')->getByStatus(0, 0, 'all', 'wait'); - $this->testcase->batchReview(array_keys($waitCases), 'pass'); - } - } - elseif($module == 'bug' and $field == 'longlife') - { - $this->loadModel('setting')->setItems('system.bug', fixer::input('post')->get()); - } - elseif($module == 'block' and $field == 'closed') - { - $data = fixer::input('post')->join('closed', ',')->get(); - $this->loadModel('setting')->setItem('system.block.closed', zget($data, 'closed', '')); - } - elseif($module == 'user' and $field == 'contactField') - { - $data = fixer::input('post')->join('contactField', ',')->get(); - if(!isset($data->contactField)) $data->contactField = ''; - $this->loadModel('setting')->setItem('system.user.contactField', $data->contactField); - } - elseif($module == 'user' and $field == 'deleted') - { - $data = fixer::input('post')->get(); - $this->loadModel('setting')->setItem('system.user.showDeleted', $data->showDeleted); - } - else - { - if(!$this->post->keys) return $this->sendError(sprintf($this->lang->error->notempty, $this->lang->custom->key)); - $lang = $_POST['lang']; - $oldCustoms = $this->custom->getItems("lang=$lang&module=$module§ion=$field"); - foreach($_POST['keys'] as $index => $key) - { - if(!empty($key)) $key = trim($key); - /* Invalid key. It should be numbers. (It includes severityList in bug module and priList in story, task, bug, testcasea, testtask and todo module.) */ - if($field == 'priList' or $field == 'severityList') - { - if(!is_numeric($key) or $key > 255) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->invalidNumberKey)); - } - if(!empty($key) and !isset($oldCustoms[$key]) and $key != 'n/a' and !validater::checkREG($key, '/^[a-z_A-Z_0-9]+$/')) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->invalidStringKey)); - - /* The length of roleList in user module is less than 10. check it when saved. */ - if($module == 'user' and $field == 'roleList' and strlen($key) > 10) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->invalidStrlen['ten'])); - - /* The length of typeList in todo module is less than 15. check it when saved. */ - if($module == 'todo' and $field == 'typeList' and strlen($key) > 15) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->invalidStrlen['fifteen'])); - - /* The length of sourceList in story module and typeList in task module is less than 20, check it when saved. */ - if(($module == 'story' and $field == 'sourceList') or ($module == 'task' and $field == 'typeList')) - { - if(strlen($key) > 20) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->invalidStrlen['twenty'])); - } - - /* The length of stageList in testcase module is less than 255, check it when saved. */ - if($module == 'testcase' and $field == 'stageList' and strlen($key) > 255) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->invalidStrlen['twoHundred'])); - - /* The length of field that in bug and testcase module and reasonList in story and task module is less than 30, check it when saved. */ - if(in_array($module, array('bug', 'testcase')) or (in_array($module, array('story', 'task')) and $field == 'reasonList')) - { - if(strlen($key) > 30) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->invalidStrlen['thirty'])); - } - } - - $this->custom->deleteItems("lang=$lang&module=$module§ion=$field&vision={$this->config->vision}"); - if($lang == 'all') $this->custom->deleteItems("lang=$currentLang&module=$module§ion=$field&vision={$this->config->vision}"); - - $data = fixer::input('post')->get(); - $emptyKey = false; - foreach($data->keys as $index => $key) - { - if(!$key && $emptyKey) continue; - - //if(!$system and (!$value or !$key)) continue; //Fix bug #951. - - $value = $data->values[$index]; - $system = $data->systems[$index]; - if($key and trim($value) === '') return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->valueEmpty)); // Fix bug #23538. - - $this->custom->setItem("{$lang}.{$module}.{$field}.{$key}.{$system}", $value); - - if(!$key) $emptyKey = true; - } - } + $this->customZen->setFieldListForSet($module, $field); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); return $this->sendSuccess(array('load' => $this->createLink('custom', 'set', "module=$module&field=$field&lang=" . ($lang == 'all' ? $lang : '')))); } - /* Check whether the current language has been customized. */ - $lang = str_replace('_', '-', $lang); - $dbFields = $this->custom->getItems("lang=$lang&module=$module§ion=$field&vision={$this->config->vision}"); - if(empty($dbFields)) $dbFields = $this->custom->getItems("lang=" . ($lang == $currentLang ? 'all' : $currentLang) . "&module=$module§ion=$field"); - if($dbFields) - { - $dbField = reset($dbFields); - if($lang != $dbField->lang) - { - $lang = str_replace('-', "_", $dbField->lang); - foreach($fieldList as $key => $value) - { - if(isset($dbFields[$key]) and $value != $dbFields[$key]->value) $fieldList[$key] = $dbFields[$key]->value; - } - } - } - $this->view->title = $this->lang->custom->common . $this->lang->colon . $this->lang->$module->common; - $this->view->fieldList = $fieldList; - $this->view->dbFields = $dbFields; $this->view->field = $field; $this->view->lang2Set = str_replace('_', '-', $lang); $this->view->module = $module; diff --git a/module/custom/ui/set.html.php b/module/custom/ui/set.html.php index f2a562d553..8ca5c05a47 100644 --- a/module/custom/ui/set.html.php +++ b/module/custom/ui/set.html.php @@ -407,7 +407,9 @@ else foreach($fieldList as $key => $value) { - $system = isset($dbFields[$key]) ? $dbFields[$key]->system : 1; + $system = isset($dbFields[$key]) ? $dbFields[$key]->system : 1; + $keyLabel = $key === '' ? 'NULL' : $key; + if($key == 0) $keyLabel = '0'; $formItems[] = formRow ( @@ -426,7 +428,7 @@ else formGroup ( set::width('1/2'), - set::label($key === '' ? 'NULL' : $key), + set::label($keyLabel), set::name('values[]'), set::value(isset($dbFields[$key]) ? $dbFields[$key]->value : $value), set::readonly(empty($key)) diff --git a/module/custom/zen.php b/module/custom/zen.php new file mode 100644 index 0000000000..2a82135681 --- /dev/null +++ b/module/custom/zen.php @@ -0,0 +1,364 @@ + + * @package custom + * @link https://www.zentao.net + */ +class customZen extends custom +{ + /** + * 设置自定义字段列表。 + * Set the list of custom fields. + * + * @param string $module todo|story|task|bug|testcase|testtask|user|project + * @param string $field priList|typeList|statusList|sourceList|reasonList|stageList|reviewRules|reviewResultList|review|severityList|osList|browserList|resolutionList|longlife|resultList|roleList|contactField|deleted|unitList + * @param string $lang all|zh-cn|zh-tw|en|de|fr + * @param string $currentLang all|zh-cn|zh-tw|en|de|fr + * @access protected + * @return void + */ + protected function assignFieldListForSet(string $module = 'story', string $field = 'priList', string $lang = '', string $currentLang = ''): void + { + $this->app->loadLang($module); + if($lang == 'all') + { + $fieldList = array(); + $items = $this->custom->getItems("lang=all&module={$module}§ion={$field}&vision={$this->config->vision}"); + foreach($items as $key => $item) + { + $fieldList[$key] = $item->value; + } + } + else + { + $fieldList = zget($this->lang->$module, $field, array()); + } + + /* Check whether the current language has been customized. */ + $lang = str_replace('_', '-', $lang); + $dbFields = $this->custom->getItems("lang={$lang}&module={$module}§ion={$field}&vision={$this->config->vision}"); + if(empty($dbFields)) $dbFields = $this->custom->getItems("lang=" . ($lang == $currentLang ? 'all' : $currentLang) . "&module={$module}§ion={$field}"); + if($dbFields) + { + $dbField = reset($dbFields); + if($lang != $dbField->lang) + { + $lang = str_replace('-', "_", $dbField->lang); + foreach($fieldList as $key => $value) + { + if(isset($dbFields[$key]) && $value != $dbFields[$key]->value) $fieldList[$key] = $dbFields[$key]->value; + } + } + } + $this->view->fieldList = $fieldList; + $this->view->dbFields = $dbFields; + } + + /** + * 设置自定义列表变量。 + * Set the list of custom variables. + * + * @param string $module todo|story|task|bug|testcase|testtask|user|project + * @param string $field priList|typeList|statusList|sourceList|reasonList|stageList|reviewRules|reviewResultList|review|severityList|osList|browserList|resolutionList|longlife|resultList|roleList|contactField|deleted|unitList + * @param string $lang all|zh-cn|zh-tw|en|de|fr + * @param string $currentLang all|zh-cn|zh-tw|en|de|fr + * @access protected + * @return void + */ + protected function assignVarsForSet(string $module = 'story', string $field = 'priList', string $lang = '', string $currentLang = ''): void + { + $this->assignFieldListForSet($module, $field, $lang, $currentLang); + if($module == 'project' && $field == 'unitList') + { + $this->app->loadConfig($module); + $unitList = zget($this->config->$module, 'unitList', ''); + $this->view->unitList = explode(',', $unitList); + $this->view->defaultCurrency = zget($this->config->$module, 'defaultCurrency', 'CNY'); + } + if(in_array($module, array('story', 'demand')) && $field == 'reviewRules') + { + $this->app->loadConfig($module); + $this->view->reviewRule = zget($this->config->$module, 'reviewRules', 'allpass'); + $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); + $this->view->superReviewers = zget($this->config->$module, 'superReviewers', ''); + } + if(in_array($module, array('story', 'testcase', 'demand')) && $field == 'review') + { + $this->app->loadConfig($module); + $this->loadModel('user'); + if(in_array($module, array('story', 'demand'))) + { + $this->view->depts = $this->loadModel('dept')->getDeptPairs(); + $this->view->forceReviewRoles = zget($this->config->$module, 'forceReviewRoles', ''); + $this->view->forceReviewDepts = zget($this->config->$module, 'forceReviewDepts', ''); + $this->view->forceNotReviewRoles = zget($this->config->$module, 'forceNotReviewRoles', ''); + $this->view->forceNotReviewDepts = zget($this->config->$module, 'forceNotReviewDepts', ''); + } + $this->view->users = $module == 'story' ? $this->user->getCanCreateStoryUsers() : $this->user->getPairs('noclosed|nodeleted'); + $this->view->needReview = zget($this->config->$module, 'needReview', 1); + $this->view->forceReview = zget($this->config->$module, 'forceReview', ''); + $this->view->forceNotReview = zget($this->config->$module, 'forceNotReview', ''); + } + if($module == 'bug' && $field == 'longlife') + { + $this->app->loadConfig('bug'); + $this->view->longlife = $this->config->bug->longlife; + } + if($module == 'block' && $field == 'closed') + { + $this->loadModel('block'); + $closedBlock = isset($this->config->block->closed) ? $this->config->block->closed : ''; + $this->view->blockPairs = $this->block->getClosedBlockPairs($closedBlock); + $this->view->closedBlock = $closedBlock; + } + if($module == 'user' && $field == 'deleted') + { + $this->app->loadConfig('user'); + $this->view->showDeleted = isset($this->config->user->showDeleted) ? $this->config->user->showDeleted : '0'; + } + } + + /** + * 设置自定义字段的值。 + * Set the value of the custom field. + * + * @param string $module todo|story|task|bug|testcase|testtask|user|project + * @param string $field priList|typeList|statusList|sourceList|reasonList|stageList|reviewRules|reviewResultList|review|severityList|osList|browserList|resolutionList|longlife|resultList|roleList|contactField|deleted|unitList + * @access protected + * @return string|bool + */ + protected function setFieldListForSet(string $module = 'story', string $field = 'priList'): string|bool + { + $data = $_POST; + if($module == 'project' && $field == 'unitList') + { + if(empty($data['unitList'])) return dao::$errors['message'] = $this->lang->custom->currencyNotEmpty; + if(empty($data['defaultCurrency'])) return dao::$errors['message'] = $this->lang->custom->defaultNotEmpty; + $this->loadModel('setting')->setItems("system.$module", $data); + } + elseif(($module == 'story' || $module == 'demand') && $field == 'review') + { + $this->setStoryReview($data); + } + elseif(($module == 'story' || $module == 'demand') && $field == 'reviewRules') + { + if(!isset($data['superReviewers'])) $data['superReviewers'] = array(); + $data['superReviewers'] = implode(',', $data['superReviewers']); + $this->loadModel('setting')->setItems("system.$module@{$this->config->vision}", $data); + } + elseif($module == 'testcase' && $field == 'review') + { + $this->setTestcaseReview($data); + } + elseif($module == 'bug' && $field == 'longlife') + { + $this->loadModel('setting')->setItems('system.bug', $data); + } + elseif($module == 'block' && $field == 'closed') + { + $data['closed'] = implode(',', $data['closed']); + $this->loadModel('setting')->setItem('system.block.closed', zget($data, 'closed', '')); + } + elseif($module == 'user' && $field == 'contactField') + { + if(!isset($data['contactField'])) $data['contactField']= array(); + $data['contactField'] = implode(',', $data['contactField']); + $this->loadModel('setting')->setItem('system.user.contactField', $data['contactField']); + } + elseif($module == 'user' && $field == 'deleted') + { + $this->loadModel('setting')->setItem('system.user.showDeleted', $data['showDeleted']); + } + else + { + if(!$this->post->keys) return dao::$errors['message'] = sprintf($this->lang->error->notempty, $this->lang->custom->key); + $this->checkKeysForSet($module, $field); + } + + return !dao::isError(); + } + + /** + * 检查自定义key值是否合法。 + * Check whether the key of custom is valid. + * + * @param string $module todo|story|task|bug|testcase|testtask|user|project + * @param string $field priList|typeList|statusList|sourceList|reasonList|stageList|reviewRules|reviewResultList|review|severityList|osList|browserList|resolutionList|longlife|resultList|roleList|contactField|deleted|unitList + * @access protected + * @return bool + */ + protected function checkKeysForSet(string $module = 'story', string $field = 'priList'): bool + { + $this->checkDuplicateKeys($module, $field); + if(dao::$errors) return false; + + $this->checkInvalidKeys($module, $field); + if(dao::$errors) return false; + + $lang = $_POST['lang']; + $this->custom->deleteItems("lang={$lang}&module={$module}§ion={$field}&vision={$this->config->vision}"); + if($lang == 'all') $this->custom->deleteItems("lang={$currentLang}&module={$module}§ion={$field}&vision={$this->config->vision}"); + + $this->checkEmptyKeys($module, $field); + return !dao::isError(); + } + + /** + * 检查自定义key值是否重复。 + * Check whether the key of custom is duplicate. + * + * @param string $module todo|story|task|bug|testcase|testtask|user|project + * @param string $field priList|typeList|statusList|sourceList|reasonList|stageList|reviewRules|reviewResultList|review|severityList|osList|browserList|resolutionList|longlife|resultList|roleList|contactField|deleted|unitList + * @access protected + * @return bool|string + */ + protected function checkDuplicateKeys(string $module = 'story', string $field = 'priList'): bool|string + { + $keys = array(); + if(isset($_POST['keys'])) + { + foreach($_POST['keys'] as $key) + { + if($module == 'testtask' && $field == 'typeList' && empty($key)) continue; + if($key && in_array($key, $keys)) return dao::$errors['message'] = sprintf($this->lang->custom->notice->repeatKey, $key); + $keys[] = $key; + } + } + return true; + } + + /** + * 检查自定义key值是否正确。 + * Check whether the key of custom is valid. + * + * @param string $module todo|story|task|bug|testcase|testtask|user|project + * @param string $field priList|typeList|statusList|sourceList|reasonList|stageList|reviewRules|reviewResultList|review|severityList|osList|browserList|resolutionList|longlife|resultList|roleList|contactField|deleted|unitList + * @access protected + * @return bool|string + */ + protected function checkInvalidKeys(string $module = 'story', string $field = 'priList'): bool|string + { + $lang = $_POST['lang']; + $oldCustoms = $this->custom->getItems("lang={$lang}&module={$module}§ion={$field}"); + foreach($_POST['keys'] as $index => $key) + { + if(!empty($key)) $key = trim($key); + + /* Invalid key. It should be numbers. (It includes severityList in bug module && priList in story, task, bug, testcasea, testtask && todo module.) */ + if(($field == 'priList' || $field == 'severityList') && (!is_numeric($key) || $key > 255)) return dao::$errors['message'] = $this->lang->custom->notice->invalidNumberKey; + + if(!empty($key) && !isset($oldCustoms[$key]) && $key != 'n/a' && !validater::checkREG($key, '/^[a-z_A-Z_0-9]+$/')) return dao::$errors['message'] = $this->lang->custom->notice->invalidStringKey; + + /* The length of roleList in user module is less than 10. check it when saved. */ + if($module == 'user' && $field == 'roleList' && strlen($key) > 10) return dao::$errors['message'] = $this->lang->custom->notice->invalidStrlen['ten']; + + /* The length of typeList in todo module is less than 15. check it when saved. */ + if($module == 'todo' && $field == 'typeList' && strlen($key) > 15) return dao::$errors['message'] = $this->lang->custom->notice->invalidStrlen['fifteen']; + + /* The length of sourceList in story module && typeList in task module is less than 20, check it when saved. */ + if((($module == 'story' && $field == 'sourceList') || ($module == 'task' && $field == 'typeList')) && strlen($key) > 20) return dao::$errors['message'] = $this->lang->custom->notice->invalidStrlen['twenty']; + + /* The length of field that in bug && testcase module && reasonList in story && task module is less than 30, check it when saved. */ + if((in_array($module, array('bug', 'testcase')) || (in_array($module, array('story', 'task')) && $field == 'reasonList')) && strlen($key) > 30) return dao::$errors['message'] = $this->lang->custom->notice->invalidStrlen['thirty']; + } + + return true; + } + + /** + * 检查自定义key值是否为空。 + * Check whether the key of custom is empty. + * + * @param string $module todo|story|task|bug|testcase|testtask|user|project + * @param string $field priList|typeList|statusList|sourceList|reasonList|stageList|reviewRules|reviewResultList|review|severityList|osList|browserList|resolutionList|longlife|resultList|roleList|contactField|deleted|unitList + * @access protected + * @return bool|string + */ + protected function checkEmptyKeys(string $module = 'story', string $field = 'priList'): bool|string + { + $lang = $_POST['lang']; + $emptyKey = false; + $keys = array(); + foreach($_POST['keys'] as $index => $key) + { + if(!$key && $emptyKey) continue; + + $value = $_POST['values'][$index]; + $system = $_POST['systems'][$index]; + if($key && trim($value) === '') return dao::$errors['message'] = $this->lang->custom->notice->valueEmpty; // Fix bug #23538. + + $this->custom->setItem("{$lang}.{$module}.{$field}.{$key}.{$system}", $value); + + if(!$key) $emptyKey = true; + } + return true; + } + + /** + * 设置需求评审规则。 + * Set the review rules of story. + * + * @param array $data + * @access protected + * @return bool + */ + protected function setStoryReview(array $data): bool + { + $forceFields = array('forceReview', 'forceNotReview', 'forceReviewRoles', 'forceNotReviewRoles', 'forceReviewDepts', 'forceNotReviewDepts'); + foreach($forceFields as $forceField) + { + if(!isset($data[$forceField])) $data[$forceField] = array(); + $data[$forceField] = implode(',', $data[$forceField]); + } + + foreach($data as $key => $value) + { + if($key == 'needReview') continue; + if(strpos($key, 'Not') && $data['needReview'] == 0) $data[$key] = ''; + if(!strpos($key, 'Not') && $data['needReview'] == 1) $data[$key] = ''; + } + + $this->loadModel('setting')->setItems("system.$module@{$this->config->vision}", $data); + + return !dao::isError(); + } + + /** + * 设置用例评审规则。 + * Set testcase review rules. + * + * @param array $data + * @access protected + * @return bool + */ + protected function setTestcaseReview(array $data): bool + { + if($data['needReview']) + { + unset($data['forceReview']); + if(!isset($data['forceNotReview'])) $data['forceNotReview'] = array(); + $data['forceNotReview'] = implode(',', $data['forceNotReview']); + } + else + { + unset($data['forceNotReview']); + if(!isset($data['forceReview'])) $data['forceReview'] = array(); + $data['forceReview'] = implode(',', $data['forceReview']); + } + $this->loadModel('setting')->setItems("system.testcase", $data); + + $reviewCase = isset($data['reviewCase']) ? $data['reviewCase'] : 0; + if($data['needReview'] == 0 && $reviewCase) + { + $waitCases = $this->loadModel('testcase')->getByStatus(0, 0, 'all', 'wait'); + $this->testcase->batchReview(array_keys($waitCases), 'pass'); + } + + return !dao::isError(); + } +}