diff --git a/db/zentao.sql b/db/zentao.sql
index 9c47c48449..6690d04830 100644
--- a/db/zentao.sql
+++ b/db/zentao.sql
@@ -8816,7 +8816,7 @@ ALTER TABLE `zt_story` ADD `fromStory` mediumint(8) unsigned NOT NULL default 0
ALTER TABLE `zt_story` ADD `fromVersion` smallint(6) NOT NULL default 1 after `fromStory`;
ALTER TABLE `zt_story` ADD `approvedDate` date NOT NULL after `assignedDate`;
-ALTER TABLE `zt_todo` CHANGE `type` `type` char(15) NOT NULL AFTER `feedback`;
+ALTER TABLE `zt_todo` CHANGE `type` char(15) NOT NULL AFTER `feedback`;
-- DROP TABLE IF EXISTS `zt_durationestimation`;
CREATE TABLE IF NOT EXISTS `zt_durationestimation` (
diff --git a/lib/base/front/front.class.php b/lib/base/front/front.class.php
index bb6db7f452..fce5e33cc0 100644
--- a/lib/base/front/front.class.php
+++ b/lib/base/front/front.class.php
@@ -1019,9 +1019,9 @@ EOT;
{
$js .= "history.back(-1);\n";
}
- elseif(strpos($target, '$.apps.open') !== false)
+ elseif($target === 'app' or strpos($target, '$.apps.open') !== false)
{
- $js .= "$target('$url')";
+ $js .= "parent.$target('$url')";
}
else
{
diff --git a/lib/scm/scm.class.php b/lib/scm/scm.class.php
index c16cc4e942..30cb1f9965 100644
--- a/lib/scm/scm.class.php
+++ b/lib/scm/scm.class.php
@@ -230,7 +230,7 @@ class scm
*/
public static function checkRevision($revision)
{
- if(preg_match('/[^a-z0-9\-_\.\^]/i', $revision)) return false;
+ if(preg_match('/[^a-z0-9\-_\.\^\w][\x{4e00}-\x{9fa5}]/ui', $revision)) return false;
return true;
}
}
diff --git a/module/action/control.php b/module/action/control.php
index 488ea7763a..7a143d26ba 100755
--- a/module/action/control.php
+++ b/module/action/control.php
@@ -131,6 +131,19 @@ class action extends control
*/
public function comment($objectType, $objectID)
{
+ if(strtolower($objectType) == 'task')
+ {
+ $task = $this->loadModel('task')->getById($objectID);
+ $executions = explode(',', $this->app->user->view->sprints);
+ if(!in_array($task->execution, $executions)) return print(js::error($this->lang->error->accessDenied));
+ }
+ elseif(strtolower($objectType) == 'story')
+ {
+ $story = $this->loadModel('story')->getById($objectID);
+ $executions = explode(',', $this->app->user->view->sprints);
+ if(!array_intersect(array_keys($story->executions), $executions)) return print(js::error($this->lang->error->accessDenied));
+ }
+
$actionID = $this->action->create($objectType, $objectID, 'Commented', $this->post->comment);
if(defined('RUN_MODE') && RUN_MODE == 'api')
{
diff --git a/module/bug/control.php b/module/bug/control.php
index 92f7ba569d..f9a9c9f320 100644
--- a/module/bug/control.php
+++ b/module/bug/control.php
@@ -2153,7 +2153,7 @@ class bug extends control
if(isset($bugLang->resolutionList[$bug->resolution])) $bug->resolution = $bugLang->resolutionList[$bug->resolution];
if(isset($users[$bug->openedBy])) $bug->openedBy = $users[$bug->openedBy];
- if(isset($users[$bug->assignedTo])) $bug->assignedTo = $users[$bug->assignedTo];
+ if(isset($users[$bug->assignedTo])) $bug->assignedTo = $users[$bug->assignedTo] . "(#$bug->assignedTo)";
if(isset($users[$bug->resolvedBy])) $bug->resolvedBy = $users[$bug->resolvedBy];
if(isset($users[$bug->lastEditedBy])) $bug->lastEditedBy = $users[$bug->lastEditedBy];
if(isset($users[$bug->closedBy])) $bug->closedBy = $users[$bug->closedBy];
diff --git a/module/bug/view/batchcreate.html.php b/module/bug/view/batchcreate.html.php
index 7c3e8c87f7..f83e38018b 100644
--- a/module/bug/view/batchcreate.html.php
+++ b/module/bug/view/batchcreate.html.php
@@ -125,7 +125,13 @@
' style='overflow:visible'> bug->osList, $os, "class='form-control chosen'");?> |
' style='overflow:visible'> bug->browserList, $browser, "class='form-control chosen'");?> |
'> |
- control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, '', $extendField->field . "[$i]") . "";?>
+ {$extendField->field} = $extendField->default;
+ echo "control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, $object, $extendField->field . "[$i]") . " | ";
+ }
+ ?>
@@ -172,7 +178,14 @@
' style='overflow:visible'> bug->osList, $os, "class='form-control chosen'");?> |
' style='overflow:visible'> bug->browserList, $browser, "class='form-control chosen'");?> |
'> |
- control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, '', $extendField->field . "[$i]") . "";?>
+ {$extendField->field} = $extendField->default;
+ echo "control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, '', $extendField->field . "[$i]") . " | ";
+ }
+ ?>
@@ -218,7 +231,14 @@
' style='overflow:visible'> bug->osList, $os, "class='form-control chosen'");?> |
' style='overflow:visible'> bug->browserList, $browser, "class='form-control chosen'");?> |
'> |
- control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, '', $extendField->field . "[%s]") . "";?>
+ {$extendField->field} = $extendField->default;
+ echo "control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, '', $extendField->field . "[%s]") . " | ";
+ }
+ ?>
diff --git a/module/common/lang/en.php b/module/common/lang/en.php
index 78c7628741..408f1289a7 100644
--- a/module/common/lang/en.php
+++ b/module/common/lang/en.php
@@ -388,6 +388,7 @@ $lang->error->noData = 'No data.';
$lang->error->editedByOther = 'This record might have been changed. Please refresh and try to edit again!';
$lang->error->tutorialData = 'No data can be imported in tutorial mode. Please quit tutorial first!';
$lang->error->noCurlExt = 'No Curl module installed';
+$lang->error->loginTimeout = 'Login has timed out, please login again!'
/* Page info. */
$lang->pager = new stdclass();
diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php
index 9df9fbcc1e..91c85e100e 100644
--- a/module/common/lang/zh-cn.php
+++ b/module/common/lang/zh-cn.php
@@ -389,6 +389,7 @@ $lang->error->noData = '没有数据';
$lang->error->editedByOther = '该记录可能已经被改动。请刷新页面重新编辑!';
$lang->error->tutorialData = '新手模式下不会插入数据,请退出新手模式操作';
$lang->error->noCurlExt = '服务器未安装Curl模块。';
+$lang->error->loginTimeout = '登录已超时,请重新登入!';
/* 分页信息。*/
$lang->pager = new stdclass();
diff --git a/module/common/model.php b/module/common/model.php
index 326a822199..7ca52cefe4 100644
--- a/module/common/model.php
+++ b/module/common/model.php
@@ -2245,6 +2245,8 @@ EOD;
}
else
{
+ if(helper::isAjaxRequest()) die(json_encode(array('result' => false, 'message' => $this->lang->error->loginTimeout))); // Fix bug #14478.
+
$referer = helper::safe64Encode($this->app->getURI(true));
print(js::locate(helper::createLink('user', 'login', "referer=$referer")));
helper::end();
diff --git a/module/custom/control.php b/module/custom/control.php
index 8001a8cdc9..62ad339866 100644
--- a/module/custom/control.php
+++ b/module/custom/control.php
@@ -172,14 +172,14 @@ class custom extends control
}
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 and typeList in todo module is less than 10. check it when saved. */
- if($field == 'roleList' or $module == 'todo' and $field == 'typeList')
- {
- if(strlen($key) > 10) return $this->send(array('result' => 'fail', 'message' => $this->lang->custom->notice->invalidStrlen['ten']));
- }
+ /* 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($field == 'sourceList' or $module == 'task' and $field == 'typeList')
+ 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']));
}
@@ -188,7 +188,7 @@ class custom extends control
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($module == 'bug' or $field == 'reasonList' or $module == 'testcase')
+ 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']));
}
diff --git a/module/custom/lang/en.php b/module/custom/lang/en.php
index efcc7f963f..a9396a720d 100644
--- a/module/custom/lang/en.php
+++ b/module/custom/lang/en.php
@@ -183,6 +183,7 @@ $lang->custom->notice->indexPage['project'] = "ZenTao 8.2+ has Project Home. Do
$lang->custom->notice->indexPage['qa'] = "ZenTao 8.2+ has Test Homepage. Do you want to go to Test Homepage?";
$lang->custom->notice->invalidStrlen['ten'] = 'The key should be <= 10 characters.';
+$lang->custom->notice->invalidStrlen['fifteen'] = 'The key should be <= 15 characters.';
$lang->custom->notice->invalidStrlen['twenty'] = 'The key should be <= 20 characters.';
$lang->custom->notice->invalidStrlen['thirty'] = 'The key should be <= 30 characters.';
$lang->custom->notice->invalidStrlen['twoHundred'] = 'The key should be <= 225 characters.';
diff --git a/module/custom/lang/zh-cn.php b/module/custom/lang/zh-cn.php
index 5e77ee1f0e..991319a060 100644
--- a/module/custom/lang/zh-cn.php
+++ b/module/custom/lang/zh-cn.php
@@ -183,6 +183,7 @@ $lang->custom->notice->indexPage['project'] = "从8.2版本起增加了项目主
$lang->custom->notice->indexPage['qa'] = "从8.2版本起增加了测试主页视图,是否默认进入测试主页?";
$lang->custom->notice->invalidStrlen['ten'] = '键的长度必须小于10个字符!';
+$lang->custom->notice->invalidStrlen['fifteen'] = '键的长度必须小于15个字符!';
$lang->custom->notice->invalidStrlen['twenty'] = '键的长度必须小于20个字符!';
$lang->custom->notice->invalidStrlen['thirty'] = '键的长度必须小于30个字符!';
$lang->custom->notice->invalidStrlen['twoHundred'] = '键的长度必须小于225个字符!';
diff --git a/module/execution/model.php b/module/execution/model.php
index bfe6908a0b..428699a89a 100644
--- a/module/execution/model.php
+++ b/module/execution/model.php
@@ -44,10 +44,10 @@ class executionModel extends model
echo(js::alert($this->lang->execution->accessDenied));
- if(!$this->server->http_referer) return print(js::locate(helper::createLink('execution', 'index')));
+ if(!$this->server->http_referer) return print(js::locate(helper::createLink('execution', 'all')));
$loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login";
- if(strpos($this->server->http_referer, $loginLink) !== false) return print(js::locate(helper::createLink('execution', 'index')));
+ if(strpos($this->server->http_referer, $loginLink) !== false) return print(js::locate(helper::createLink('execution', 'all')));
return print(js::locate(helper::createLink('execution', 'all')));
}
diff --git a/module/my/control.php b/module/my/control.php
index 171cef2db3..ea6d26055d 100644
--- a/module/my/control.php
+++ b/module/my/control.php
@@ -418,8 +418,9 @@ EOF;
if($this->config->systemMode == 'new')
{
$projects = $this->dao->select('t1.id,t1.name,t2.id as execution')->from(TABLE_PROJECT)->alias('t1')
- ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.id=t2.parent')
+ ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.id=t2.project')
->where('t2.id')->in($executionIDList)
+ ->andWhere('t1.type')->eq('project')
->fetchAll('execution');
}
diff --git a/module/programplan/model.php b/module/programplan/model.php
index 564734ced8..61d5044520 100644
--- a/module/programplan/model.php
+++ b/module/programplan/model.php
@@ -540,6 +540,27 @@ class programplanModel extends model
->where('id')->eq($stageID)
->exec();
+ /* Add PM to stage teams and project teams. */
+ if(!empty($data->PM))
+ {
+ $team = $this->user->getTeamMemberPairs($stageID, 'execution');
+ if(isset($team[$data->PM])) continue;
+
+ $roles = $this->user->getUserRoles($data->PM);
+ $member = new stdclass();
+ $member->root = $stageID;
+ $member->account = $data->PM;
+ $member->role = zget($roles, $data->PM, '');
+ $member->join = $now;
+ $member->type = 'execution';
+ $member->days = $data->days;
+ $member->hours = $this->config->execution->defaultWorkhours;
+ $this->dao->insert(TABLE_TEAM)->data($member)->exec();
+ $this->execution->addProjectMembers($data->project, array($data->PM => $member));
+ }
+
+ if($data->acl != 'open') $this->user->updateUserView($stageID, 'sprint');
+
/* Record version change information. */
if($planChanged)
{
@@ -592,7 +613,7 @@ class programplanModel extends model
/* Add creators and PM to stage teams and project teams. */
$teamMembers = array();
- $members = array($account, $data->PM);
+ $members = array($this->app->user->account, $data->PM);
$roles = $this->user->getUserRoles(array_values($members));
$team = $this->user->getTeamMemberPairs($stageID, 'execution');
foreach($members as $account)
diff --git a/module/repo/control.php b/module/repo/control.php
index c7c3ea7633..5a4779c469 100644
--- a/module/repo/control.php
+++ b/module/repo/control.php
@@ -272,9 +272,10 @@ class repo extends control
$this->commonAction($repoID, $objectID);
- $file = $entry;
- $repo = $this->repo->getRepoByID($repoID);
- $entry = $this->repo->decodePath($entry);
+ $file = $entry;
+ $repo = $this->repo->getRepoByID($repoID);
+ $entry = $this->repo->decodePath($entry);
+ $revision = str_replace('*', '-', $revision);
$this->scm->setEngine($repo);
$info = $this->scm->info($entry, $revision);
diff --git a/module/story/control.php b/module/story/control.php
index e14c548a59..dc976c96ee 100644
--- a/module/story/control.php
+++ b/module/story/control.php
@@ -2402,7 +2402,7 @@ class story extends control
if(isset($storyLang->sourceList[$story->sourceNote])) $story->sourceNote = $storyLang->sourceList[$story->sourceNote];
if(isset($users[$story->openedBy])) $story->openedBy = $users[$story->openedBy];
- if(isset($users[$story->assignedTo])) $story->assignedTo = $users[$story->assignedTo];
+ if(isset($users[$story->assignedTo])) $story->assignedTo = $users[$story->assignedTo] . "(#$story->assignedTo)";
if(isset($users[$story->lastEditedBy])) $story->lastEditedBy = $users[$story->lastEditedBy];
if(isset($users[$story->closedBy])) $story->closedBy = $users[$story->closedBy];
diff --git a/module/story/view/batchcreate.html.php b/module/story/view/batchcreate.html.php
index 8a89e14a39..67321db43c 100644
--- a/module/story/view/batchcreate.html.php
+++ b/module/story/view/batchcreate.html.php
@@ -114,7 +114,14 @@
'> |
- control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, '', $extendField->field . '[$id]') . "";?>
+ {$extendField->field} = $extendField->default;
+ echo "control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->loadModel('flow')->getFieldControl($extendField, $object, $extendField->field . '[$id]') . " | ";
+ }
+ ?>
diff --git a/test/class/admin.class.php b/test/class/admin.class.php
new file mode 100644
index 0000000000..2fb907a7f6
--- /dev/null
+++ b/test/class/admin.class.php
@@ -0,0 +1,198 @@
+objectModel = $tester->loadModel('admin');
+ $this->user = $tester->loadModel('user');
+ $this->communityConfig = $app->loadConfig('community');
+ $this->adminConfig = $config->admin;
+ }
+
+ /**
+ * Post data form API.
+ *
+ * @param string $url
+ * @param string $formvars
+ * @access public
+ * @return void
+ */
+ public function postAPITest()
+ {
+ $apiConfig = $this->objectModel->getApiConfig();
+ $apiURL = $this->adminConfig->apiRoot . "/user-apiRegister.json?HTTP_X_REQUESTED_WITH=XMLHttpRequest&{$apiConfig->sessionVar}={$apiConfig->sessionID}";
+
+ $objects = $this->objectModel->postAPI($apiURL);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+
+ /**
+ * Get status of zentaopms.
+ * @access public
+ * @return void
+ */
+
+ public function getStatOfPMSTest()
+ {
+ $objects = $this->objectModel->getStatOfPMS();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getStatOfCompanyTest($companyID)
+ {
+ $objects = $this->objectModel->getStatOfCompany($companyID);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getStatOfSysTest()
+ {
+ $objects = $this->objectModel->getStatOfSys();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function registerByAPITest()
+ {
+ $objects = $this->objectModel->registerByAPI();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+ /**
+ * Login zentao by API.
+ *
+ * @access public
+ * @return void
+ */
+ public function bindByAPITest($param)
+ {
+ $_POST = $param;
+ $objects = $this->objectModel->bindByAPI();
+ $objects = json_decode($objects);
+ unset($_POST);
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getSecretKeyTest()
+ {
+ $objects = $this->objectModel->getSecretKey();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function sendCodeByAPITest($type)
+ {
+ $objects = $this->objectModel->sendCodeByAPI($type);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function certifyByAPITest($type)
+ {
+ $objects = $this->objectModel->certifyByAPI($type);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function setCompanyByAPITest()
+ {
+ $objects = $this->objectModel->setCompanyByAPI();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ /**
+ * Get signature.
+ *
+ * @param array $params
+ * @access public
+ * @return string
+ */
+
+ public function getSignatureTest()
+ {
+ $params['u'] = $this->communityConfig;
+ $params['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequet';
+
+ $apiConfig = $this->objectModel->getApiConfig();
+ $params[$apiConfig->sessionVar] = $apiConfig->sessionID;
+
+ $objects = $this->objectModel->getSignature($params);
+
+ if(dao::isError()) return dao::getError();
+
+ if($objects){
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+
+ public function getApiConfigTest()
+ {
+ $objects = $this->objectModel->getApiConfig();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ /**
+ * Get register information.
+ *
+ * @access public
+ * @return object
+ */
+ public function getRegisterInfoTest()
+ {
+ $objects = $this->objectModel->getRegisterInfo();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+ /**
+ * Check weak.
+ *
+ * @param object $user
+ * @access public
+ * @return bool
+ */
+
+ public function checkWeakTest($account)
+ {
+ $user = $this->user->getById($account);
+ $objects = $this->objectModel->checkWeak($user);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+}
diff --git a/test/class/report.class.php b/test/class/report.class.php
new file mode 100644
index 0000000000..7f197be0eb
--- /dev/null
+++ b/test/class/report.class.php
@@ -0,0 +1,365 @@
+objectModel = $tester->loadModel('report');
+ }
+
+ /**
+ * Test compute percent of every item.
+ *
+ * @param array $datas
+ * @access public
+ * @return string
+ */
+ public function computePercentTest($datas)
+ {
+ $objects = $this->objectModel->computePercent($datas);
+
+ if(dao::isError()) return dao::getError();
+
+ $percents = '';
+ foreach($objects as $moduleID => $object) $percents .= "$moduleID:$object->percent;";
+ return $percents;
+ }
+
+ /**
+ * Test create json data of single charts.
+ *
+ * @param int $executionID
+ * @access public
+ * @return string
+ */
+ public function createSingleJSONTest($executionID)
+ {
+ global $tester;
+ $this->execution = $tester->loadModel('execution');
+
+ $execution = $this->execution->getByID($executionID);
+ $sets = $this->execution->getBurnDataFlot($executionID, 'left');
+ $dateList = $this->execution->getDateList($execution->begin, $execution->end, 'noweekend', 0, 'Y-m-d');
+
+ $objects = $this->objectModel->createSingleJSON($sets, $dateList[0]);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ /**
+ * Test convert date format.
+ *
+ * @param array $dateList
+ * @param string $format
+ * @access public
+ * @return string
+ */
+ public function convertFormatTest($dateList, $format = 'Y-m-d')
+ {
+ $objects = $this->objectModel->convertFormat($dateList, $format = 'Y-m-d');
+
+ if(dao::isError()) return dao::getError();
+
+ return implode(',', $objects);
+ }
+
+ /**
+ * Test get executions.
+ *
+ * @param int $begin
+ * @param int $end
+ * @access public
+ * @return void
+ */
+ public function getExecutionsTest($begin = 0, $end = 0)
+ {
+ $begin = $begin != 0 ? date('Y-m-d', strtotime(date('Y-m-d') . $begin)) : 0;
+ $end = $end != 0 ? date('Y-m-d', strtotime(date('Y-m-d') . $end)) : 0;
+ $objects = $this->objectModel->getExecutions($begin, $end);
+
+ if(dao::isError()) return dao::getError();
+
+ $executions = '';
+ foreach($objects as $executionID => $execution) $executions .= "$executionID:$execution->estimate,$execution->consumed,$execution->projectName;";
+ return $executions;
+ }
+
+ /**
+ * Test get products.
+ *
+ * @param string $conditions
+ * @param string $storyType
+ * @access public
+ * @return string
+ */
+ public function getProductsTest($conditions, $storyType = 'story')
+ {
+ $objects = $this->objectModel->getProducts($conditions, $storyType);
+
+ if(dao::isError()) return dao::getError();
+
+ $planCount = 0;
+ foreach($objects as $object)
+ {
+ if(isset($object->plans)) $planCount += count($object->plans);
+ }
+ return 'product:' . count($objects) . ';plan:' . $planCount;
+ }
+
+ /**
+ * Test get bugs.
+ *
+ * @param string $begin
+ * @param string $end
+ * @param int $product
+ * @param int $execution
+ * @access public
+ * @return array
+ */
+ public function getBugsTest($begin, $end, $product, $execution)
+ {
+ $begin = date('Y-m-d', strtotime(date('Y-m-d') . $begin));
+ $end = date('Y-m-d', strtotime(date('Y-m-d') . $end));
+ $objects = $this->objectModel->getBugs($begin, $end, $product, $execution);
+
+ if(dao::isError()) return dao::getError();
+
+ $count = array();
+ foreach($objects as $user => $types)
+ {
+ $count[$user] = '';
+ foreach($types as $type => $typeCount) $count[$user] .= "$type:$typeCount;";
+ }
+ return $count;
+ }
+
+ public function getWorkloadTest($dept = 0, $assign = 'assign')
+ {
+ $objects = $this->objectModel->getWorkload($dept = 0, $assign = 'assign');
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ /**
+ * Test get bug assign.
+ *
+ * @access public
+ * @return void
+ */
+ public function getBugAssignTest()
+ {
+ $objects = $this->objectModel->getBugAssign();
+
+ if(dao::isError()) return dao::getError();
+
+ $count = array();
+ foreach($objects as $user => $object) $count[$user] = $object['total']['count'];
+ return $count;
+ }
+
+ public function getSysURLTest()
+ {
+ $objects = $this->objectModel->getSysURL();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserBugsTest()
+ {
+ $objects = $this->objectModel->getUserBugs();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserTasksTest()
+ {
+ $objects = $this->objectModel->getUserTasks();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserTodosTest()
+ {
+ $objects = $this->objectModel->getUserTodos();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserTestTasksTest()
+ {
+ $objects = $this->objectModel->getUserTestTasks();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserYearLoginsTest($accounts, $year)
+ {
+ $objects = $this->objectModel->getUserYearLogins($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserYearActionsTest($accounts, $year)
+ {
+ $objects = $this->objectModel->getUserYearActions($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserYearContributionsTest($accounts, $year)
+ {
+ $objects = $this->objectModel->getUserYearContributions($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserYearTodosTest($accounts, $year)
+ {
+ $objects = $this->objectModel->getUserYearTodos($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserYearEffortsTest($accounts, $year)
+ {
+ $objects = $this->objectModel->getUserYearEfforts($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserYearProductsTest($accounts, $year)
+ {
+ $objects = $this->objectModel->getUserYearProducts($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getUserYearExecutionsTest($accounts, $year)
+ {
+ $objects = $this->objectModel->getUserYearExecutions($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ /**
+ * Test get status stat that is all time, include story, task and bug.
+ *
+ * @access public
+ * @return array
+ */
+ public function getAllTimeStatusStatTest()
+ {
+ $objects = $this->objectModel->getAllTimeStatusStat();
+
+ if(dao::isError()) return dao::getError();
+
+ $types = array();
+ foreach($objects as $type => $status)
+ {
+ $types[$type] = '';
+ foreach($status as $statusType => $statusCount) $types[$type] .= "$statusType:$statusCount;";
+ }
+ return $types;
+ }
+
+ public function getYearObjectStatTest($accounts, $year, $objectType)
+ {
+ $objects = $this->objectModel->getYearObjectStat($accounts, $year, $objectType);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getYearCaseStatTest($accounts, $year)
+ {
+ $objects = $this->objectModel->getYearCaseStat($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getYearMonthsTest($year)
+ {
+ $objects = $this->objectModel->getYearMonths($year);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getStatusOverviewTest($objectType, $statusStat)
+ {
+ $objects = $this->objectModel->getStatusOverview($objectType, $statusStat);
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ public function getProjectStatusOverviewTest($accounts = array())
+ {
+ $objects = $this->objectModel->getProjectStatusOverview($accounts = array());
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+
+ /**
+ * Test get output data for API.
+ *
+ * @param string $accounts
+ * @param string $year
+ * @access public
+ * @return string
+ */
+ public function getOutput4APITest($accounts, $year)
+ {
+ $objects = $this->objectModel->getOutput4API($accounts, $year);
+
+ if(dao::isError()) return dao::getError();
+
+ $output = '';
+ foreach($objects as $objectType => $object) $output .= "$objectType:" . $object['total'] . ";";
+ return $output;
+ }
+
+ public function getProjectExecutionsTest()
+ {
+ $objects = $this->objectModel->getProjectExecutions();
+
+ if(dao::isError()) return dao::getError();
+
+ return $objects;
+ }
+}
diff --git a/test/data/bug.yaml b/test/data/bug.yaml
index 2628756984..bb6ba8333e 100644
--- a/test/data/bug.yaml
+++ b/test/data/bug.yaml
@@ -65,7 +65,7 @@ fields:
- field: openedBy
range: admin
- field: openedDate
- range: "(-1M)-(+1w):60"
+ range: "(-1M)-(+1w):-1D"
type: timestamp
format: "YYYY-MM-DD hh:mm:ss"
- field: openedBuild
@@ -73,7 +73,7 @@ fields:
- field: assignedTo
range: [admin,dev1,test1]{30},[]{20},[admin,dev1,test1]{20},[]{10},closed{20}
- field: assignedDate
- range: "(-1M)-(+1w):60"
+ range: "(-1M)-(+1w):-1D"
type: timestamp
format: "YYYY-MM-DD"
- field: deadline
diff --git a/test/data/moretask.yaml b/test/data/moretask.yaml
index 19a589fe73..264461b304 100644
--- a/test/data/moretask.yaml
+++ b/test/data/moretask.yaml
@@ -185,8 +185,7 @@ fields:
format: ""
- field: assignedTo
note: "指派给"
- from: common.user.v1.yaml
- use: user
+ range: ""
prefix: ""
postfix: ""
loop: 0
diff --git a/test/data/task.yaml b/test/data/task.yaml
index d74d81ee78..8adca0b47c 100644
--- a/test/data/task.yaml
+++ b/test/data/task.yaml
@@ -185,8 +185,7 @@ fields:
format: ""
- field: assignedTo
note: "指派给"
- from: common.user.v1.yaml
- use: user
+ range: ""
prefix: ""
postfix: ""
loop: 0
diff --git a/test/data/taskestimate.yaml b/test/data/taskestimate.yaml
index a77ef4aebd..e947141c7c 100644
--- a/test/data/taskestimate.yaml
+++ b/test/data/taskestimate.yaml
@@ -12,12 +12,12 @@ fields:
format: ""
- field: date
note: "更新日期"
- from: common.date.v1.yaml
- use: dateB
+ range: "(-1M)-(+1w):60s"
+ type: timestamp
+ format: "YYYY-MM-DD hh:mm:ss"
prefix: ""
postfix: ""
loop: 0
- format: ""
- field: left
note: "总计消耗"
range: 0
diff --git a/test/data/taskson.yaml b/test/data/taskson.yaml
index eab4b3786c..3b7c794305 100644
--- a/test/data/taskson.yaml
+++ b/test/data/taskson.yaml
@@ -185,8 +185,7 @@ fields:
format: ""
- field: assignedTo
note: "指派给"
- from: common.user.v1.yaml
- use: user
+ range: po82,user92
prefix: ""
postfix: ""
loop: 0
diff --git a/test/model/admin/bindbyapi.php.bak b/test/model/admin/bindbyapi.php.bak
new file mode 100755
index 0000000000..e16727e4f7
--- /dev/null
+++ b/test/model/admin/bindbyapi.php.bak
@@ -0,0 +1,27 @@
+#!/usr/bin/env php
+bindByAPI();
+cid=1
+pid=1
+
+正常测试 >> success;wxm11,j8a5qCRTleJh9Gv4
+错误密码测试 >> fail;登录失败,请检查您的用户名或密码是否填写正确。
+post数据为空测试 >> fail;登录失败,请检查您的用户名或密码是否填写正确。
+
+*/
+
+$admin = new adminTest();
+
+$paramInfo = array('account' => 'wxm11', 'password' => '123qweasd', 'sn' => 'c8aa3269e181f2b9258ce96625de1497', 'site' => 'http://zentaopmsdemo.com');
+$errorPwd = array('account' => 'wxm11', 'password' => '123', 'sn' => 'c8aa3269e181f2b9258ce96625de1497', 'site' => 'http://zentaopmsdemo.com');
+$emptyPost = array();
+
+r($admin->bindByAPITest($errorPwd)) && p('result;message') && e('fail;登录失败,请检查您的用户名或密码是否填写正确。'); //错误密码测试
+r($admin->bindByAPITest($emptyPost)) && p('result;message') && e('fail;登录失败,请检查您的用户名或密码是否填写正确。'); //post数据为空测试
+r($admin->bindByAPITest($paramInfo)) && p('result;data:account,private') && e('success;wxm11,j8a5qCRTleJh9Gv4'); //正常测试
diff --git a/test/model/admin/certifybyapi.php.bak b/test/model/admin/certifybyapi.php.bak
new file mode 100755
index 0000000000..ff9b52002c
--- /dev/null
+++ b/test/model/admin/certifybyapi.php.bak
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+certifyByAPI();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+r($admin->certifyByAPITest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/admin/checkweak.php b/test/model/admin/checkweak.php
new file mode 100755
index 0000000000..57345dcaa4
--- /dev/null
+++ b/test/model/admin/checkweak.php
@@ -0,0 +1,20 @@
+#!/usr/bin/env php
+checkWeak();
+cid=1
+pid=1
+
+正常测试 >> 0
+
+*/
+$account = 'admin';
+
+$admin = new adminTest();
+
+r($admin->checkWeakTest($account)) && p() && e('0'); //正常测试
\ No newline at end of file
diff --git a/test/model/admin/getapiconfig.php.bak b/test/model/admin/getapiconfig.php.bak
new file mode 100755
index 0000000000..3293350d96
--- /dev/null
+++ b/test/model/admin/getapiconfig.php.bak
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+getApiConfig();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+r($admin->getApiConfigTest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/admin/getregisterinfo.php b/test/model/admin/getregisterinfo.php
new file mode 100755
index 0000000000..8ffcbd13f9
--- /dev/null
+++ b/test/model/admin/getregisterinfo.php
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+getRegisterInfo();
+cid=1
+pid=1
+
+正常测试 >> 易软天创网络科技有限公司
+
+*/
+
+$admin = new adminTest();
+
+r($admin->getRegisterInfoTest()) && p('company') && e('易软天创网络科技有限公司'); //正常测试
\ No newline at end of file
diff --git a/test/model/admin/getsecretkey.php.bak b/test/model/admin/getsecretkey.php.bak
new file mode 100755
index 0000000000..60e1f74a66
--- /dev/null
+++ b/test/model/admin/getsecretkey.php.bak
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+getSecretKey();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+r($admin->getSecretKeyTest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/admin/getsignature.php b/test/model/admin/getsignature.php
new file mode 100755
index 0000000000..b49acdb2ab
--- /dev/null
+++ b/test/model/admin/getsignature.php
@@ -0,0 +1,18 @@
+#!/usr/bin/env php
+getSignature();
+cid=1
+pid=1
+
+正常测试 >> 1
+
+*/
+$admin = new adminTest();
+
+r($admin->getSignatureTest()) && p() && e('1'); //正常测试
\ No newline at end of file
diff --git a/test/model/admin/getstatofcompany.php.bak b/test/model/admin/getstatofcompany.php.bak
new file mode 100755
index 0000000000..b988fce125
--- /dev/null
+++ b/test/model/admin/getstatofcompany.php.bak
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+getStatOfCompany();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+r($admin->getStatOfCompanyTest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/admin/getstatofpms.php b/test/model/admin/getstatofpms.php
new file mode 100755
index 0000000000..f039b99b87
--- /dev/null
+++ b/test/model/admin/getstatofpms.php
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+getStatOfPMS();
+cid=1
+pid=1
+
+正常测试 >> 0
+
+*/
+
+$admin = new adminTest();
+
+r($admin->getStatOfPMSTest()) && p() && e('0'); //正常测试
\ No newline at end of file
diff --git a/test/model/admin/getstatofsys.php.bak b/test/model/admin/getstatofsys.php.bak
new file mode 100755
index 0000000000..4316e5cc1f
--- /dev/null
+++ b/test/model/admin/getstatofsys.php.bak
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+getStatOfSys();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+r($admin->getStatOfSysTest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/admin/postapi.php.bak b/test/model/admin/postapi.php.bak
new file mode 100755
index 0000000000..0bef9f9f5f
--- /dev/null
+++ b/test/model/admin/postapi.php.bak
@@ -0,0 +1,20 @@
+#!/usr/bin/env php
+postAPI();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+a($admin->postAPITest());die;
+r($admin->postAPITest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/admin/registerbyapi.php.bak b/test/model/admin/registerbyapi.php.bak
new file mode 100755
index 0000000000..8b1a182acb
--- /dev/null
+++ b/test/model/admin/registerbyapi.php.bak
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+registerByAPI();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+r($admin->registerByAPITest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/admin/sendcodebyapi.php.bak b/test/model/admin/sendcodebyapi.php.bak
new file mode 100755
index 0000000000..a810fff39b
--- /dev/null
+++ b/test/model/admin/sendcodebyapi.php.bak
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+sendCodeByAPI();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+r($admin->sendCodeByAPITest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/admin/setcompanybyapi.php.bak b/test/model/admin/setcompanybyapi.php.bak
new file mode 100755
index 0000000000..8e8572f782
--- /dev/null
+++ b/test/model/admin/setcompanybyapi.php.bak
@@ -0,0 +1,19 @@
+#!/usr/bin/env php
+setCompanyByAPI();
+cid=1
+pid=1
+
+
+
+*/
+
+$admin = new adminTest();
+
+r($admin->setCompanyByAPITest()) && p() && e();
\ No newline at end of file
diff --git a/test/model/report/computepercent.php b/test/model/report/computepercent.php
new file mode 100755
index 0000000000..6733871b21
--- /dev/null
+++ b/test/model/report/computepercent.php
@@ -0,0 +1,38 @@
+#!/usr/bin/env php
+computePercent();
+cid=1
+pid=1
+
+测试 bug按照 模块 分组 的百分比 >> 0:0.9714;1821:0.0032;1822:0.0032;1823:0.0032;1825:0.0032;1826:0.0032;1827:0.0032;1831:0.0032;1832:0.0032;1833:0.003;
+测试 bug按照 版本 分组 的百分比 >> 0:0.0095;trunk:0.9238;1:0.019;11:0.019;12:0.0032;13:0.0032;14:0.0032;15:0.0032;16:0.0032;17:0.0032;18:0.0032;19:0.0032;20:0.0031;
+测试 bug按照 严重程度 分组 的百分比 >> 1:0.2508;2:0.2508;3:0.2508;4:0.2476;
+测试 bug按照 解决方案 分组 的百分比 >> fixed:0.3;duplicate:0.2;bydesign:0.12;external:0.12;willnotfix:0.12;postponed:0.08;notrepro:0.06;
+测试 bug按照 优先级 分组 的百分比 >> 1:0.2508;2:0.2508;3:0.2508;4:0.2476;
+测试 bug按照 类型 分组 的百分比 >> codeerror:0.1556;config:0.1079;install:0.1079;security:0.1048;performance:0.1048;standard:0.1048;automation:0.1048;designdefect:0.1048;others:0.10
+
+*/
+$report = new reportTest();
+
+global $tester;
+$bug = $tester->loadModel('bug');
+
+$bugsPerModule = $bug->getDataOfBugsPerModule();
+$bugsPerBuild = $bug->getDataOfBugsPerBuild();
+$bugsPerSeverity = $bug->getDataOfBugsPerSeverity();
+$bugsPerResolution = $bug->getDataOfBugsPerResolution();
+$bugsPerPri = $bug->getDataOfBugsPerPri();
+$bugsPerType = $bug->getDataOfBugsPerType();
+
+r($report->computePercentTest($bugsPerModule)) && p() && e('0:0.9714;1821:0.0032;1822:0.0032;1823:0.0032;1825:0.0032;1826:0.0032;1827:0.0032;1831:0.0032;1832:0.0032;1833:0.003;'); // 测试 bug按照 模块 分组 的百分比
+r($report->computePercentTest($bugsPerBuild)) && p() && e('0:0.0095;trunk:0.9238;1:0.019;11:0.019;12:0.0032;13:0.0032;14:0.0032;15:0.0032;16:0.0032;17:0.0032;18:0.0032;19:0.0032;20:0.0031;'); // 测试 bug按照 版本 分组 的百分比
+r($report->computePercentTest($bugsPerSeverity)) && p() && e('1:0.2508;2:0.2508;3:0.2508;4:0.2476;'); // 测试 bug按照 严重程度 分组 的百分比
+r($report->computePercentTest($bugsPerResolution)) && p() && e('fixed:0.3;duplicate:0.2;bydesign:0.12;external:0.12;willnotfix:0.12;postponed:0.08;notrepro:0.06;'); // 测试 bug按照 解决方案 分组 的百分比
+r($report->computePercentTest($bugsPerPri)) && p() && e('1:0.2508;2:0.2508;3:0.2508;4:0.2476;'); // 测试 bug按照 优先级 分组 的百分比
+r($report->computePercentTest($bugsPerType)) && p() && e('codeerror:0.1556;config:0.1079;install:0.1079;security:0.1048;performance:0.1048;standard:0.1048;automation:0.1048;designdefect:0.1048;others:0.10'); // 测试 bug按照 类型 分组 的百分比
\ No newline at end of file
diff --git a/test/model/report/convertformat.php b/test/model/report/convertformat.php
new file mode 100755
index 0000000000..ec4ac39050
--- /dev/null
+++ b/test/model/report/convertformat.php
@@ -0,0 +1,44 @@
+#!/usr/bin/env php
+convertFormat();
+cid=1
+pid=1
+
+测试获取 2022-01-01 到 2022-01-05 的日期列表 >> 2022-01-03,2022-01-04,2022-01-05
+测试获取 2022-01-06 到 2022-01-10 的日期列表 >> 2022-01-06,2022-01-07,2022-01-10
+测试获取 2022-01-11 到 2022-01-15 的日期列表 >> 2022-01-11,2022-01-12,2022-01-13,2022-01-14
+测试获取 2022-01-16 到 2022-01-20 的日期列表 >> 2022-01-17,2022-01-18,2022-01-19,2022-01-20
+测试获取 2022-01-01 到 2022-01-05 的日期列表 >> 2022-01-01,2022-01-02,2022-01-03,2022-01-04,2022-01-05
+测试获取 2022-01-06 到 2022-01-10 的日期列表 >> 2022-01-06,2022-01-07,2022-01-08,2022-01-09,2022-01-10
+测试获取 2022-01-11 到 2022-01-15 的日期列表 >> 2022-01-11,2022-01-12,2022-01-13,2022-01-14,2022-01-15
+测试获取 2022-01-16 到 2022-01-20 的日期列表 >> 2022-01-16,2022-01-17,2022-01-18,2022-01-19,2022-01-20
+
+*/
+$report = new reportTest();
+
+global $tester;
+$execution = $tester->loadModel('execution');
+
+$date1 = $execution->getDateList('2022-01-01', '2022-01-05', 'noweekend');
+$date2 = $execution->getDateList('2022-01-06', '2022-01-10', 'noweekend');
+$date3 = $execution->getDateList('2022-01-11', '2022-01-15', 'noweekend');
+$date4 = $execution->getDateList('2022-01-16', '2022-01-20', 'noweekend');
+$date5 = $execution->getDateList('2022-01-01', '2022-01-05', 'withweekend');
+$date6 = $execution->getDateList('2022-01-06', '2022-01-10', 'withweekend');
+$date7 = $execution->getDateList('2022-01-11', '2022-01-15', 'withweekend');
+$date8 = $execution->getDateList('2022-01-16', '2022-01-20', 'withweekend');
+
+r($report->convertFormatTest($date1[0])) && p() && e('2022-01-03,2022-01-04,2022-01-05'); // 测试获取 2022-01-01 到 2022-01-05 的日期列表
+r($report->convertFormatTest($date2[0])) && p() && e('2022-01-06,2022-01-07,2022-01-10'); // 测试获取 2022-01-06 到 2022-01-10 的日期列表
+r($report->convertFormatTest($date3[0])) && p() && e('2022-01-11,2022-01-12,2022-01-13,2022-01-14'); // 测试获取 2022-01-11 到 2022-01-15 的日期列表
+r($report->convertFormatTest($date4[0])) && p() && e('2022-01-17,2022-01-18,2022-01-19,2022-01-20'); // 测试获取 2022-01-16 到 2022-01-20 的日期列表
+r($report->convertFormatTest($date5[0])) && p() && e('2022-01-01,2022-01-02,2022-01-03,2022-01-04,2022-01-05'); // 测试获取 2022-01-01 到 2022-01-05 的日期列表
+r($report->convertFormatTest($date6[0])) && p() && e('2022-01-06,2022-01-07,2022-01-08,2022-01-09,2022-01-10'); // 测试获取 2022-01-06 到 2022-01-10 的日期列表
+r($report->convertFormatTest($date7[0])) && p() && e('2022-01-11,2022-01-12,2022-01-13,2022-01-14,2022-01-15'); // 测试获取 2022-01-11 到 2022-01-15 的日期列表
+r($report->convertFormatTest($date8[0])) && p() && e('2022-01-16,2022-01-17,2022-01-18,2022-01-19,2022-01-20'); // 测试获取 2022-01-16 到 2022-01-20 的日期列表
\ No newline at end of file
diff --git a/test/model/report/createsinglejson.php b/test/model/report/createsinglejson.php
new file mode 100755
index 0000000000..4091dae87a
--- /dev/null
+++ b/test/model/report/createsinglejson.php
@@ -0,0 +1,29 @@
+#!/usr/bin/env php
+createSingleJSON();
+cid=1
+pid=1
+
+测试获取执行 101 的json数据 >> [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+测试获取执行 102 的json数据 >> [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+测试获取执行 103 的json数据 >> [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+测试获取执行 104 的json数据 >> [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12]
+测试获取执行 105 的json数据 >> [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+
+*/
+
+$report = new reportTest();
+
+$executionID = array(101, 102, 103, 104, 105);
+
+r($report->createSingleJSONTest($executionID[0])) && p() && e('[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]'); // 测试获取执行 101 的json数据
+r($report->createSingleJSONTest($executionID[1])) && p() && e('[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]'); // 测试获取执行 102 的json数据
+r($report->createSingleJSONTest($executionID[2])) && p() && e('[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]'); // 测试获取执行 103 的json数据
+r($report->createSingleJSONTest($executionID[3])) && p() && e('[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12]'); // 测试获取执行 104 的json数据
+r($report->createSingleJSONTest($executionID[4])) && p() && e('[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]'); // 测试获取执行 105 的json数据
\ No newline at end of file
diff --git a/test/model/report/getalltimestatusstat.php b/test/model/report/getalltimestatusstat.php
new file mode 100755
index 0000000000..7bcdf0c5b3
--- /dev/null
+++ b/test/model/report/getalltimestatusstat.php
@@ -0,0 +1,23 @@
+#!/usr/bin/env php
+getAllTimeStatusStat();
+cid=1
+pid=1
+
+测试获取 需求 的状态分组个数 >> changed:81;active:93;draft:51;
+测试获取 任务 的状态分组个数 >> wait:152;doing:152;done:152;pause:152;cancel:151;closed:151;
+测试获取 bug 的状态分组个数 >> active:135;resolved:90;closed:60;
+
+*/
+
+$report = new reportTest();
+
+r($report->getAllTimeStatusStatTest()) && p('story') && e('changed:81;active:93;draft:51;'); // 测试获取 需求 的状态分组个数
+r($report->getAllTimeStatusStatTest()) && p('task') && e('wait:152;doing:152;done:152;pause:152;cancel:151;closed:151;'); // 测试获取 任务 的状态分组个数
+r($report->getAllTimeStatusStatTest()) && p('bug') && e('active:135;resolved:90;closed:60;'); // 测试获取 bug 的状态分组个数
\ No newline at end of file
diff --git a/test/model/report/getbugassign.php b/test/model/report/getbugassign.php
new file mode 100755
index 0000000000..d86fddf7ce
--- /dev/null
+++ b/test/model/report/getbugassign.php
@@ -0,0 +1,23 @@
+#!/usr/bin/env php
+getBugAssign();
+cid=1
+pid=1
+
+获取指派给 admin 的bug数量 >> 85
+获取指派给 dev1 的bug数量 >> 35
+获取指派给 test1 的bug数量 >> 5
+
+*/
+
+$report = new reportTest();
+
+r($report->getBugAssignTest()) && p('admin') && e('85'); // 获取指派给 admin 的bug数量
+r($report->getBugAssignTest()) && p('dev1') && e('35'); // 获取指派给 dev1 的bug数量
+r($report->getBugAssignTest()) && p('test1') && e('5'); // 获取指派给 test1 的bug数量
\ No newline at end of file
diff --git a/test/model/report/getbugs.php b/test/model/report/getbugs.php
new file mode 100755
index 0000000000..12b62ea584
--- /dev/null
+++ b/test/model/report/getbugs.php
@@ -0,0 +1,32 @@
+#!/usr/bin/env php
+getBugs();
+cid=1
+pid=1
+
+测试获取 -40 day 到 -29 day 产品 1 执行 101 的bug >> :4;all:4;validRate:0;
+测试获取 -28 day 到 -25 day 产品 2 执行 102 的bug >> :3;all:3;validRate:0;
+测试获取 -24 day 到 -21 day 产品 3 执行 103 的bug >> :2;all:2;validRate:0;
+测试获取 -20 day 到 -19 day 产品 4 执行 104 的bug >> :1;all:1;validRate:0;
+测试获取 -20 day 到 -16 day 产品 5 执行 105 的bug >> :3;all:3;validRate:0;
+
+*/
+
+$begin = array(' -40 day', ' -28 day', ' -24 day', ' -20 day', ' -20 day');
+$end = array(' -29 day', ' -25 day', ' -21 day', ' -19 day', ' -16 day');
+$productID = array(1, 2, 3, 4, 5);
+$executionID = array(101, 102, 103, 104, 105);
+
+$report = new reportTest();
+
+r($report->getBugsTest($begin[0], $end[0], $productID[0], $executionID[0])) && p('admin') && e(':4;all:4;validRate:0;'); // 测试获取 -40 day 到 -29 day 产品 1 执行 101 的bug
+r($report->getBugsTest($begin[1], $end[1], $productID[1], $executionID[1])) && p('admin') && e(':3;all:3;validRate:0;'); // 测试获取 -28 day 到 -25 day 产品 2 执行 102 的bug
+r($report->getBugsTest($begin[2], $end[2], $productID[2], $executionID[2])) && p('admin') && e(':2;all:2;validRate:0;'); // 测试获取 -24 day 到 -21 day 产品 3 执行 103 的bug
+r($report->getBugsTest($begin[3], $end[3], $productID[3], $executionID[3])) && p('admin') && e(':1;all:1;validRate:0;'); // 测试获取 -20 day 到 -19 day 产品 4 执行 104 的bug
+r($report->getBugsTest($begin[4], $end[4], $productID[4], $executionID[4])) && p('admin') && e(':3;all:3;validRate:0;'); // 测试获取 -20 day 到 -16 day 产品 5 执行 105 的bug
\ No newline at end of file
diff --git a/test/model/report/getexecutions.php b/test/model/report/getexecutions.php
new file mode 100755
index 0000000000..2d60bad624
--- /dev/null
+++ b/test/model/report/getexecutions.php
@@ -0,0 +1,37 @@
+#!/usr/bin/env php
+getExecutions();
+cid=1
+pid=1
+
+测试查询 开始时间 0 结束时间 0 的执行 >> 151:30,15,项目51;183:15,30,项目83;121:27,15,项目21;111:27,12,项目11;107:30,35,项目7;103:23,35,项目3;102:9,18,项目2;101:3,15,项目1;
+测试查询 开始时间大于 -40 day 结束时间小于 -10 day 的执行 >> 103:23,35,项目3;102:9,18,项目2;101:3,15,项目1;
+测试查询 开始时间大于 -28 day 结束时间小于 +5 day 的执行 >> 107:30,35,项目7;103:23,35,项目3;102:9,18,项目2;101:3,15,项目1;
+测试查询 开始时间大于 -24 day 结束时间小于 +10 day 的执行 >> 111:27,12,项目11;107:30,35,项目7;
+测试查询 开始时间大于 -20 day 结束时间小于 +15 day 的执行 >> 111:27,12,项目11;
+测试查询 开始时间大于 -20 day 结束时间小于 +20 day 的执行 >> 121:27,15,项目21;
+
+*/
+
+$begin = array('0', ' -70 day', ' -60 day', ' -55 day', ' -50 day', ' -40 day');
+$end = array('0', ' +10 day', ' +15 day', ' +20 day', ' +25 day', ' +30 day');
+
+$report = new reportTest();
+
+global $tester;
+$tester->dao->update(TABLE_EXECUTION)->set('`status`')->eq('closed')->where('id')->in('101,102,103,107,111,121,151,183')->exec();
+
+r($report->getExecutionsTest($begin[0], $end[0])) && p() && e('151:30,15,项目51;183:15,30,项目83;121:27,15,项目21;111:27,12,项目11;107:30,35,项目7;103:23,35,项目3;102:9,18,项目2;101:3,15,项目1;'); // 测试查询 开始时间 0 结束时间 0 的执行
+r($report->getExecutionsTest($begin[1], $end[1])) && p() && e('103:23,35,项目3;102:9,18,项目2;101:3,15,项目1;'); // 测试查询 开始时间大于 -40 day 结束时间小于 -10 day 的执行
+r($report->getExecutionsTest($begin[2], $end[2])) && p() && e('107:30,35,项目7;103:23,35,项目3;102:9,18,项目2;101:3,15,项目1;'); // 测试查询 开始时间大于 -28 day 结束时间小于 +5 day 的执行
+r($report->getExecutionsTest($begin[3], $end[3])) && p() && e('111:27,12,项目11;107:30,35,项目7;'); // 测试查询 开始时间大于 -24 day 结束时间小于 +10 day 的执行
+r($report->getExecutionsTest($begin[4], $end[4])) && p() && e('111:27,12,项目11;'); // 测试查询 开始时间大于 -20 day 结束时间小于 +15 day 的执行
+r($report->getExecutionsTest($begin[5], $end[5])) && p() && e('121:27,15,项目21;'); // 测试查询 开始时间大于 -20 day 结束时间小于 +20 day 的执行
+$tester->dao->update(TABLE_EXECUTION)->set('`status`')->eq('wait')->where('id')->in('101,103,107,111,121,151,183')->exec();
+$tester->dao->update(TABLE_EXECUTION)->set('`status`')->eq('doing')->where('id')->in('102')->exec();
diff --git a/test/model/report/getoutput4api.php b/test/model/report/getoutput4api.php
new file mode 100755
index 0000000000..e0077e287a
--- /dev/null
+++ b/test/model/report/getoutput4api.php
@@ -0,0 +1,25 @@
+#!/usr/bin/env php
+getOutput4API();
+cid=1
+pid=1
+
+测试获取 admin 2022 的输出 >> case:70;
+测试获取 dev17 2022 的输出 >> bug:1;case:0;
+测试获取 test18 2022 的输出 >> productplan:1;case:0;
+
+*/
+$account = array('admin', 'dev17', 'test18');
+$year = 2022;
+
+$report = new reportTest();
+
+r($report->getOutput4APITest($account[0], $year)) && p() && e('case:70;'); // 测试获取 admin 2022 的输出
+r($report->getOutput4APITest($account[1], $year)) && p() && e('bug:1;case:0;'); // 测试获取 dev17 2022 的输出
+r($report->getOutput4APITest($account[2], $year)) && p() && e('productplan:1;case:0;'); // 测试获取 test18 2022 的输出
\ No newline at end of file
diff --git a/test/model/report/getproducts.php b/test/model/report/getproducts.php
new file mode 100755
index 0000000000..5d92b90846
--- /dev/null
+++ b/test/model/report/getproducts.php
@@ -0,0 +1,26 @@
+#!/usr/bin/env php
+getProducts();
+cid=1
+pid=1
+
+
+
+*/
+$conditions = array('', 'closedProduct', 'overduePlan');
+$storyType = 'requirement';
+
+$report = new reportTest();
+
+r($report->getProductsTest($conditions[0])) && p() && e(''); // 测试获取 story 产品
+r($report->getProductsTest($conditions[1])) && p() && e(''); // 测试获取 story closedProduct 产品
+r($report->getProductsTest($conditions[2])) && p() && e(''); // 测试获取 story overduePlan 产品
+r($report->getProductsTest($conditions[0], $storyType)) && p() && e(''); // 测试获取 requirement 产品
+r($report->getProductsTest($conditions[1], $storyType)) && p() && e(''); // 测试获取 requirement closedProduct 产品
+r($report->getProductsTest($conditions[2], $storyType)) && p() && e(''); // 测试获取 requirement overduePlan 产品
\ No newline at end of file
diff --git a/test/ztest b/test/ztest
index 32052a1b45..ee415cc8a5 100755
--- a/test/ztest
+++ b/test/ztest
@@ -82,6 +82,9 @@ switch($argv[1])
case 'branch':
ztfRun('model/branch');
break;
+ case 'report':
+ ztfRun('model/report');
+ break;
case 'tree':
ztfRun('model/tree');
break;
@@ -93,6 +96,9 @@ switch($argv[1])
break;
case 'productsonplan':
ztfRun('model/productsonplan');
+ break;;
+ case 'admin':
+ ztfRun('model/admin');
break;
case 'model':
ztfRun('model');
diff --git a/www/js/kindeditor/kindeditor.js b/www/js/kindeditor/kindeditor.js
index 4c1f06da50..ddad7215a3 100644
--- a/www/js/kindeditor/kindeditor.js
+++ b/www/js/kindeditor/kindeditor.js
@@ -1,3 +1,10 @@
+/*!
+ * ZUI: Zentao Kindeditor - v1.10.0 - 2022-04-19
+ * http://openzui.com
+ * GitHub: https://github.com/easysoft/zui.git
+ * Copyright (c) 2022 cnezsoft.com; Licensed MIT
+ */
+
/******************************************************************************
* KindEditor - WYSIWYG HTML Editor for Internet
* Copyright (C) 2006-2013 kindsoft.net
@@ -7997,10 +8004,13 @@ KindEditor.plugin('lineheight', function(K) {
*******************************************************************************/
KindEditor.plugin('link', function(K) {
+ console.trace('plugin link');
var self = this,
name = 'link';
+ if (self.plugin.link) return;
self.plugin.link = {
edit: function() {
+ console.trace('edit');
var lang = self.lang(name + '.'),
html = '' +
//url
diff --git a/www/js/kindeditor/kindeditor.min.js b/www/js/kindeditor/kindeditor.min.js
index 0160e2b053..73155bce2b 100644
--- a/www/js/kindeditor/kindeditor.min.js
+++ b/www/js/kindeditor/kindeditor.min.js
@@ -1,8 +1,14 @@
+/*!
+ * ZUI: Zentao Kindeditor - v1.10.0 - 2022-04-19
+ * http://openzui.com
+ * GitHub: https://github.com/easysoft/zui.git
+ * Copyright (c) 2022 cnezsoft.com; Licensed MIT
+ */
/*! KindEditor Copyright (C) kindsoft.net, Licence: http://kindeditor.net/license.php */
if(function(window,undefined){function _isArray(e){return!!e&&"[object Array]"===Object.prototype.toString.call(e)}function _isFunction(e){return!!e&&"[object Function]"===Object.prototype.toString.call(e)}function _inArray(e,t){for(var n=0,i=t.length;n
=0}function _addUnit(e,t){return t=t||"px",e&&/^[\d\.]+$/.test(e)?e+t:e}function _removeUnit(e){var t;return e&&(t=/([\d\.]+)/.exec(e))?parseInt(t[1],10):0}function _escape(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function _unescape(e){return e.replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/&/g,"&")}function _toCamel(e){var t=e.split("-");return e="",_each(t,function(t,n){e+=t>0?n.charAt(0).toUpperCase()+n.substr(1):n}),e}function _toHex(e){function t(e){var t=parseInt(e,10).toString(16).toUpperCase();return t.length>1?t:"0"+t}return e.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/gi,function(e,n,i,a){return"#"+t(n)+t(i)+t(a)})}function _toMap(e,t){t=t===undefined?",":t;var n,i={},a=_isArray(e)?e:e.split(t);return _each(a,function(e,t){if(n=/^(\d+)\.\.(\d+)$/.exec(t))for(var a=parseInt(n[1],10);a<=parseInt(n[2],10);a++)i[a.toString()]=!0;else i[t]=!0}),i}function _toArray(e,t){return Array.prototype.slice.call(e,t||0)}function _undef(e,t){return e===undefined?t:e}function _invalidUrl(e){return!e||/[<>"]/.test(e)}function _addParam(e,t){return e.indexOf("?")>=0?e+"&"+t:e+"?"+t}function _extend(e,t,n){n||(n=t,t=null);var i;if(t){var a=function(){};a.prototype=t.prototype,i=new a,_each(n,function(e,t){i[e]=t})}else i=n;i.constructor=e,e.prototype=i,e.parent=t?t.prototype:null}function _json(text){var match;(match=/\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))&&(text=match[0]);var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;if(cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(e){return"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return eval("("+text+")");throw"JSON parse error"}function _getBasePath(){for(var e,t=document.getElementsByTagName("script"),n=0,i=t.length;n=0)return void _each(t.split(","),function(){_bind(e,this,n)});var i=_getId(e);i||(i=_setId(e)),_eventData[i]===undefined&&(_eventData[i]={});var a=_eventData[i][t];a&&a.length>0?_unbindEvent(e,t,a[0]):(_eventData[i][t]=[],_eventData[i].el=e),a=_eventData[i][t],0===a.length&&(a[0]=function(t){var n=t?new KEvent(e,t):undefined;_each(a,function(t,i){t>0&&i&&i.call(e,n)})}),_inArray(n,a)<0&&a.push(n),_bindEvent(e,t,a[0])}function _unbind(e,t,n){if(t&&t.indexOf(",")>=0)return void _each(t.split(","),function(){_unbind(e,this,n)});var i=_getId(e);if(i){if(t===undefined)return void(i in _eventData&&(_each(_eventData[i],function(t,n){"el"!=t&&n.length>0&&_unbindEvent(e,t,n[0])}),delete _eventData[i],_removeId(e)));if(_eventData[i]){var a=_eventData[i][t];if(a&&a.length>0){n===undefined?(_unbindEvent(e,t,a[0]),delete _eventData[i][t]):(_each(a,function(e,t){e>0&&t===n&&a.splice(e,1)}),1==a.length&&(_unbindEvent(e,t,a[0]),delete _eventData[i][t]));var o=0;_each(_eventData[i],function(){o++}),o<2&&(delete _eventData[i],_removeId(e))}}}}function _fire(e,t){if(t.indexOf(",")>=0)return void _each(t.split(","),function(){_fire(e,this)});var n=_getId(e);if(n){var i=_eventData[n][t];_eventData[n]&&i&&i.length>0&&i[0]()}}function _ctrl(e,t,n){t=/^\d{2,}$/.test(t)?t:t.toUpperCase().charCodeAt(0),_bind(e,"keydown",function(i){!i.ctrlKey||i.which!=t||i.shiftKey||i.altKey||(n.call(e),i.stop())})}function _ready(e){function t(){a||(a=!0,e(KindEditor),_readyFinished=!0)}function n(){if(!a){try{document.documentElement.doScroll("left")}catch(e){return void setTimeout(n,100)}t()}}function i(){"complete"===document.readyState&&t()}if(_readyFinished)return void e(KindEditor);var a=!1;if(document.addEventListener)_bind(document,"DOMContentLoaded",t);else if(document.attachEvent){_bind(document,"readystatechange",i);var o=!1;try{o=null==window.frameElement}catch(r){}document.documentElement.doScroll&&o&&n()}_bind(window,"load",t)}function _getCssList(e){for(var t,n={},i=/\s*([\w\-]+)\s*:([^;]*)(;|$)/g;t=i.exec(e);){var a=_trim(t[1].toLowerCase()),o=_trim(_toHex(t[2]));n[a]=o}return n}function _getAttrList(e,t){var n,i={},a=/\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g;for(t===undefined&&(t="");n=a.exec(e);){var o=(n[1]||n[2]||n[4]||n[6]).toLowerCase(),r=(n[2]?n[3]:n[4]?n[5]:n[7])||t;i[o]=r}return i}function _addClassToTag(e,t){return e=/\s+class\s*=/.test(e)?e.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/,function(e,n,i,a){return(" "+i+" ").indexOf(" "+t+" ")<0?""===i?n+t+a:n+i+" "+t+a:e}):e.substr(0,e.length-1)+' class="'+t+'">'}function _formatCss(e){var t="";return _each(_getCssList(e),function(e,n){t+=e+":"+n+";"}),t}function _formatUrl(e,t,n,i){function a(e){for(var t=e.split("/"),n=[],i=0,a=t.length;i0&&n.pop():""!==o&&"."!=o&&n.push(o)}return"/"+n.join("/")}function o(t,n){if(e.substr(0,t.length)===t){for(var a=[],r=0;r0&&(s+="/"+a.join("/")),"/"==i&&(s+="/"),s+e.substr(t.length)}if(l=/^(.*)\//.exec(t))return o(l[1],++n)}if("#"===e[0])return e;if(t=_undef(t,"").toLowerCase(),"data:"!=e.substr(0,5)&&(e=e.replace(/([^:])\/\//g,"$1/")),_inArray(t,["absolute","relative","domain"])<0)return e;if(n=n||location.protocol+"//"+location.host,i===undefined){var r=location.pathname.match(/^(\/.*)\//);i=r?r[1]:""}var l;if(l=/^(\w+:\/\/[^\/]*)/.exec(e)){if(l[1]!==n)return e}else if(/^\w+:/.test(e))return e;return/^\//.test(e)?e=n+a(e.substr(1)):/^\w+:\/\//.test(e)||(e=n+a(i+"/"+e)),"relative"===t?e=o(n+i,0).substr(2):"absolute"===t&&e.substr(0,n.length)===n&&(e=e.substr(n.length)),e}function _formatHtml(e,t,n,i,a,o){null==e&&(e=""),n=n||"",i=_undef(i,!1),a=_undef(a,"\t");var r="xx-small,x-small,small,medium,large,x-large,xx-large".split(",");e=e.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/gi,function(e,t,n,i){return t+n.replace(/<(?:br|br\s[^>]*)>/gi,"\n")+i}),e=e.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/gi,""),e=e.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/gi,"$1
$2"),e=e.replace(/\u200B/g,""),e=e.replace(/\u00A9/g,"©"),e=e.replace(/<[^>]+>/g,function(e){return e.replace(/\s+/g," ")});var l={};t&&(_each(t,function(e,t){for(var n=e.split(","),i=0,a=n.length;i]*)>)([\s\S]*?)(<\/script>)/gi,"")),l.style||(e=e.replace(/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/gi,"")));var s=/(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g,d=[],c=null;return e=e.replace(s,function(e,s,u,p,h,f,m){var g=e,v=s||"",_=u||"",b=p.toLowerCase(),y=h||"",k=f?" "+f:"",w=m||"";if(t&&!l[b])return"";if(""===k&&_SINGLE_TAG_MAP[b]&&(k=" /"),_INLINE_TAG_MAP[b]&&(v&&(v=" "),w&&(w=" ")),_PRE_TAG_MAP[b]&&(_?w="\n":v="\n"),!i||"br"!=b&&"hr"!==b||o&&c!==!0||(w="\n"),_BLOCK_TAG_MAP[b]&&!_PRE_TAG_MAP[b])if(i){var C=!!(_&&d.length>0&&d[d.length-1]===b);if(C?(d.pop(),o&&(v="",w="\n")):(d.push(b),o&&(v="\n",w="")),o||(v="\n",w="\n"),!o||c===!1&&!C||c===!0)for(var S=0,x=_?d.length:d.length-1;S=0&&(E[e]=_formatUrl(i,n)),(t&&"style"!==e&&!l[b]["*"]&&!l[b][e]||"body"===b&&"contenteditable"===e||/^kindeditor_\d+$/.test(e))&&delete E[e],"style"===e&&""!==i)){var a=_getCssList(i);_each(a,function(e,n){!t||l[b].style||l[b]["."+e]||delete a[e]});var o="";_each(a,function(e,t){o+=e+":"+t+";"}),E.style=o}}),y="",_each(E,function(e,t){if(t!==!1&&("style"!==e||""!==t)){if(t===!0)return void(y+=" "+e);t=t.replace(/"/g,"""),y+=" "+e+'="'+t+'"'}})}return"font"===b&&(b="span"),v+"<"+_+b+y+k+">"+w}),e=e.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/gi,function(e,t,n,i){return t+n.replace(/\n/g,'\n')+i}),e=e.replace(/\n\s*\n/g,"\n"),e=e.replace(/\n/g,"\n"),_trim(e)}function _clearMsWord(e,t){return e=e.replace(//gi,"").replace(//gi,"").replace(/"];return _isArray(n)||(n=[n]),_each(n,function(e,t){t&&a.push('')}),i&&a.push(""),a.push("