diff --git a/api/v1/entries/productissue.php b/api/v1/entries/productissue.php index eecc5704c4..f6a92de5bb 100644 --- a/api/v1/entries/productissue.php +++ b/api/v1/entries/productissue.php @@ -53,6 +53,7 @@ class productIssueEntry extends entry } break; + case 'bug': $this->app->loadLang('bug'); $bugStatus = array('' => '', 'active' => 'opened', 'resolved' => 'opened', 'closed' => 'closed'); @@ -132,7 +133,9 @@ class productIssueEntry extends entry $this->send404(); } - $actions = $this->loadModel('action')->getList($type, $issueID); + $actions = $this->loadModel('action')->getList($type, $id); + + $issue->comments = array_values($this->processActions($type, $actions)); /** * Get all users in issues so that we can bulk get user detail later. @@ -159,4 +162,52 @@ class productIssueEntry extends entry $this->send(200, array('issue' => $this->format($issue, 'openedDate:time,lastEditedDate:time'))); } + + /** + * Process actions of one issue. + * + * @param string $type + * @param array $actions + * @access public + * @return array + */ + public function processActions($type, $actions) + { + $accountsList = array(); + foreach($actions as $action) + { + $accountsList[] = $action->actor; + ob_start(); + $this->action->printAction($action); + $action->title = ob_get_contents(); + ob_clean(); + + $action->body_html = ''; + + if(!empty($action->history)) + { + ob_start(); + $this->action->printChanges($action->objectType, $action->history); + $action->body_html = ob_get_contents(); + ob_clean(); + } + + if(!empty($action->comment)) + { + $comment = strip_tags($action->comment) == $action->comment ? nl2br($action->comment) : $action->comment; + $action->body_html = "
{$comment}
"; + } + } + + /* Format user detail and date. */ + $accountsList = array_unique($accountsList); + $userDetails = $this->loadModel('user')->getUserDetailsForAPI($accountsList); + foreach($actions as $action) + { + $action->actor = $userDetails[$action->actor]; + $action->date = gmdate("Y-m-d\TH:i:s\Z", strtotime($action->date)); + } + + return $actions; + } } diff --git a/api/v1/entries/productissues.php b/api/v1/entries/productissues.php index d26b72a76a..6cda85a31d 100644 --- a/api/v1/entries/productissues.php +++ b/api/v1/entries/productissues.php @@ -107,32 +107,35 @@ class productIssuesEntry extends entry $bugFilter = array_unique($bugFilter); $executions = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('product')->eq($productID)->fetchPairs(); - if(!empty($taskFilter)) + + /* Get tasks. */ + if(empty($labelTypes) or in_array('task', $labelTypes)) { $query = $this->dao->select($taskFields)->from(TABLE_TASK)->where('execution')->in(array_values($executions)) ->beginIF($search)->andWhere('name')->like("%$search%")->fi() ->beginIF($status)->andWhere('status')->in($taskStatus[$status])->fi() ->andWhere('deleted')->eq(0); - foreach($taskFilter as $filter) if($filter != 'all') $query->andWhere('type')->eq($filter); $tasks = $query->fetchAll(); foreach($tasks as $task) $issues[] = array('id' => $task->id, 'type' => 'task', 'order' => $task->$order, 'status' => $this->getKey($task->status, $taskStatus)); } - if(!empty($storyFilter)) + /* Get stories. */ + if(empty($labelTypes) or in_array('story', $labelTypes)) { $query = $this->dao->select($storyFields)->from(TABLE_STORY) ->where('product')->eq($productID) ->beginIF($search)->andWhere('title')->like("%$search%")->fi() ->beginIF($status)->andWhere('status')->in($storyStatus[$status])->fi() ->andWhere('deleted')->eq(0); - foreach($storyFilter as $filter) if($filter != 'all') $query->andWhere('category')->eq($filter); $stories = $query->fetchAll(); foreach($stories as $story) $issues[] = array('id' => $story->id, 'type' => 'story', 'order' => $story->$order, 'status' => $this->getKey($story->status, $storyStatus)); } - if(!empty($bugFilter)) + /* Get bugs. */ + /* Get stories. */ + if(empty($labelTypes) or in_array('bug', $labelTypes)) { $query = $this->dao->select($bugFields)->from(TABLE_BUG) ->where('product')->eq($productID) @@ -305,7 +308,7 @@ class productIssuesEntry extends entry { foreach($issue->assignedTo as $index => $user) { - $issue->assignedTo[$index] = $userDetails[$user]; + $issue->assignedTo[$index] = $userDetails[$user]; } $issue->openedBy = $userDetails[$issue->openedBy]; } diff --git a/config/zentaopms.php b/config/zentaopms.php index fe193d98ca..bc2ecfea74 100644 --- a/config/zentaopms.php +++ b/config/zentaopms.php @@ -139,6 +139,7 @@ $config->openMethods[] = 'index.changelog'; $config->openMethods[] = 'my.preference'; $config->openMethods[] = 'my.changepassword'; $config->openMethods[] = 'my.profile'; +$config->openMethods[] = 'my.settutorialconfig'; /* Define the tables. */ define('TABLE_COMPANY', '`' . $config->db->prefix . 'company`'); diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php index 225d71cf78..eb498ec90f 100644 --- a/framework/api/entry.class.php +++ b/framework/api/entry.class.php @@ -188,7 +188,7 @@ class baseEntry header("Content-type: application/json"); header("HTTP/1.1 {$this->statusCode[$code]}"); - if($data) echo json_encode($data); + if($data) echo json_encode($data, JSON_HEX_TAG); exit; } diff --git a/lib/base/front/front.class.php b/lib/base/front/front.class.php index c1e9d597f3..a81a355823 100644 --- a/lib/base/front/front.class.php +++ b/lib/base/front/front.class.php @@ -490,11 +490,7 @@ class baseHTML if(helper::inOnlyBodyMode()) return false; global $lang, $app, $config; - if(empty($label)) - { - global $lang, $config; - $label = $lang->goback; - } + if(empty($label)) $label = $lang->goback; $tab = $_COOKIE['tab']; $referer = strtolower($_SERVER['HTTP_REFERER']); diff --git a/module/bug/view/create.html.php b/module/bug/view/create.html.php index 2eae7ec696..373db1cbbc 100644 --- a/module/bug/view/create.html.php +++ b/module/bug/view/create.html.php @@ -327,7 +327,7 @@ js::set('moduleID', $moduleID); session->bugList ? $this->session->bugList : $this->inlink('browse', "productID=$productID");?> - goback, $browseLink, 'self', '', 'btn btn-wide');?> + goback, '', 'class="btn btn-wide"');?> id);?> diff --git a/module/common/lang/en.php b/module/common/lang/en.php index d1238f0a8b..df6fe59f6e 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -296,7 +296,7 @@ $lang->createObjects['story'] = 'Story'; $lang->createObjects['task'] = 'Task'; $lang->createObjects['testcase'] = 'Case'; $lang->createObjects['execution'] = $lang->execution->common; -$lang->createObjects['project'] = $lang->projectCommon; +$lang->createObjects['project'] = 'Project'; $lang->createObjects['product'] = 'Product'; $lang->createObjects['program'] = 'Program'; $lang->createObjects['doc'] = 'Doc'; diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php index 979a276a96..414d918862 100644 --- a/module/common/lang/menu.php +++ b/module/common/lang/menu.php @@ -94,7 +94,7 @@ $lang->my->menu->work['subMenu']->task = array('link' => "{$lang->task->comm if($config->URAndSR) $lang->my->menu->work['subMenu']->requirement = "$lang->URCommon|my|work|mode=requirement"; $lang->my->menu->work['subMenu']->story = "$lang->SRCommon|my|work|mode=story"; $lang->my->menu->work['subMenu']->bug = "{$lang->bug->common}|my|work|mode=bug"; -$lang->my->menu->work['subMenu']->testcase = "{$lang->testcase->common}|my|work|mode=testcase&type=assigntome"; +$lang->my->menu->work['subMenu']->testcase = array('link' => "{$lang->testcase->common}|my|work|mode=testcase&type=assigntome", 'subModule' => 'testtask'); $lang->my->menu->work['subMenu']->testtask = "{$lang->testtask->common}|my|work|mode=testtask&type=wait"; $lang->my->menu->work['menuOrder'][5] = 'task'; diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index a97923eee7..634f5a18d5 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -296,7 +296,7 @@ $lang->createObjects['story'] = '需求'; $lang->createObjects['task'] = '任务'; $lang->createObjects['testcase'] = '用例'; $lang->createObjects['execution'] = $lang->execution->common; -$lang->createObjects['project'] = $lang->projectCommon; +$lang->createObjects['project'] = '项目'; $lang->createObjects['product'] = '产品'; $lang->createObjects['program'] = '项目集'; $lang->createObjects['doc'] = '文档'; diff --git a/module/common/model.php b/module/common/model.php index e32d9b92a7..1c1d81a7eb 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -367,7 +367,8 @@ class commonModel extends model foreach($lang->createIcons as $objectType => $objectIcon) { if(!isset($config->proVersion) and $objectType == 'effort') continue; - if($config->systemMode == 'classic' and ($objectType == 'project' or $objectType == 'porgram')) continue; + if($config->systemMode == 'classic' and strpos('project|program', $objectType) !== false) continue; + if(!empty($_COOKIE['feedbackView']) and strpos('todo|effort', $objectType) === false) continue; /* Change icon when object type is execution and mode is classic. */ if($config->systemMode == 'classic' and $objectType == 'execution') $objectIcon = 'project'; @@ -392,12 +393,13 @@ class commonModel extends model $showCreateList = true; $isOnlyBody = strpos('effort|doc', $objectType) !== false; $iconWord = $objectType == 'doc' ? 'W' : ''; // No ducument icon, print word instead of icon. + $attr = $objectType == 'effort' ? "data-width='95%' class='iframe' data-toggle='modal'" : "class='iframe'"; $params = ''; - if($objectType == 'bug' or $objectType == 'testcase') $params = "productID=$productID"; + if(strpos('bug|testcase|story', $objectType) !== false) $params = "productID=$productID"; if($objectType == 'doc') $params = "objectType=&objectID=0&libID=0"; - $html .= '
  • ' . html::a(helper::createLink($objectType, $createMethod, $params, '', $isOnlyBody), "$iconWord " . $lang->createObjects[$objectType], '', $isOnlyBody ? "class='iframe'" : '') . '
  • '; + $html .= '
  • ' . html::a(helper::createLink($objectType, $createMethod, $params, '', $isOnlyBody), "$iconWord " . $lang->createObjects[$objectType], '', $isOnlyBody ? $attr : '') . '
  • '; } } @@ -1350,7 +1352,7 @@ EOD; $executionPairs = array(); $object = $app->dbh->query('SELECT project,type FROM ' . TABLE_EXECUTION . " WHERE `id` = '$executionID'")->fetch(); $orderBy = $object->type == 'stage' ? 'ORDER BY `id` ASC' : 'ORDER BY `id` DESC'; - $executionList = $app->dbh->query("SELECT id,name FROM " . TABLE_EXECUTION . " WHERE `project` = '{$object->project}' $orderBy")->fetchAll(); + $executionList = $app->dbh->query("SELECT id,name FROM " . TABLE_EXECUTION . " WHERE `project` = '{$object->project}' AND `deleted` = '0' $orderBy")->fetchAll(); foreach($executionList as $execution) { if($execution->id == $executionID) continue; diff --git a/module/common/view/header.html.php b/module/common/view/header.html.php index 56521cfb98..8d38bca3ff 100755 --- a/module/common/view/header.html.php +++ b/module/common/view/header.html.php @@ -19,7 +19,7 @@ include 'chosen.html.php';
    diff --git a/module/custom/js/mode.js b/module/custom/js/mode.js index b24c0ac56f..e69de29bb2 100644 --- a/module/custom/js/mode.js +++ b/module/custom/js/mode.js @@ -1,9 +0,0 @@ -$(function() -{ - $('[name=mode]').change(function() - { - var mode = $(this).val(); - if(mode == 'new') $('#modeTips').html(newTips); - if(mode == 'classic') $('#modeTips').html(classicTips); - }) -}) diff --git a/module/custom/view/mode.html.php b/module/custom/view/mode.html.php index bb1077a87d..1f7fbebd90 100644 --- a/module/custom/view/mode.html.php +++ b/module/custom/view/mode.html.php @@ -11,8 +11,6 @@ */ ?> -upgrade->selectedModeTips['new'])?> -custom->changeClassicTip)?>
    @@ -29,7 +27,7 @@

    -

    custom->changeClassicTip : $lang->upgrade->selectedModeTips['new'];?>

    +

    upgrade->selectedModeTips['new'];?>

    diff --git a/module/doc/config.php b/module/doc/config.php index c00a0fcf33..a8c78892f1 100644 --- a/module/doc/config.php +++ b/module/doc/config.php @@ -9,7 +9,7 @@ $config->doc->edit = new stdclass(); $config->doc->createlib->requiredFields = 'name'; $config->doc->editlib->requiredFields = 'name'; -$config->doc->create->requiredFields = 'title'; +$config->doc->create->requiredFields = 'lib,title'; $config->doc->edit->requiredFields = 'title'; $config->doc->customObjectLibs = 'files,customFiles'; diff --git a/module/doc/control.php b/module/doc/control.php index 267e3b35f0..db0d4cbfe4 100644 --- a/module/doc/control.php +++ b/module/doc/control.php @@ -320,14 +320,18 @@ class doc extends control if($this->config->systemMode == 'classic') unset($this->lang->doc->menu->execution['subMenu']); } - $lib = $this->doc->getLibByID($libID); - $type = !empty($lib) ? $lib->type : 'product'; + /* Get libs and the default lib id. */ $unclosed = strpos($this->config->doc->custom->showLibs, 'unclosed') !== false ? 'unclosedProject' : ''; + $libs = $this->doc->getLibs($objectType, $extra = "withObject,$unclosed", $libID, $objectID); + if(!$libID and !empty($libs)) $libID = key($libs); + + $lib = $this->doc->getLibByID($libID); + $type = !empty($lib) ? $lib->type : 'product'; if(!isonlybody()) $this->view->title = $lib->name . $this->lang->colon . $this->lang->doc->create; $this->view->libID = $libID; - $this->view->libs = $this->doc->getLibs($objectType, $extra = "withObject,$unclosed", $libID, $objectID); + $this->view->libs = $libs; $this->view->libName = $this->dao->findByID($libID)->from(TABLE_DOCLIB)->fetch('name'); $this->view->moduleOptionMenu = $this->tree->getOptionMenu($libID, 'doc', $startModuleID = 0); $this->view->moduleID = $moduleID ? (int)$moduleID : (int)$this->cookie->lastDocModule; diff --git a/module/doc/js/edit.js b/module/doc/js/edit.js index 433e028559..bae3663c3e 100644 --- a/module/doc/js/edit.js +++ b/module/doc/js/edit.js @@ -7,6 +7,7 @@ $(function() $('#content').html(draft); editor = KindEditor.instances[0]; editor.html(draft); + $('.kindeditor-ph').remove(); } }, 100) diff --git a/module/doc/model.php b/module/doc/model.php index 0d998ab794..34b2071b52 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -61,7 +61,7 @@ class docModel extends model { if($lib->product != 0 and !isset($products[$lib->product])) continue; if($lib->execution != 0 and !isset($executions[$lib->execution])) continue; - if($lib->project != 0 and !isset($project[$lib->project])) continue; + if($lib->project != 0 and !isset($projects[$lib->project]) and $lib->type == 'project') continue; if($this->checkPrivLib($lib, $extra)) { @@ -499,6 +499,12 @@ class docModel extends model ->remove('files,labels,uid,contactListMenu') ->get(); + if(empty($doc->lib)) + { + dao::$errors['lib'] = sprintf($this->lang->error->notempty, $this->lang->doc->lib); + return false; + } + /* Fix bug #2929. strip_tags($this->post->contentMarkdown, $this->config->allowedTags)*/ $doc = $this->loadModel('file')->processImgURL($doc, $this->config->doc->editor->create['id'], $this->post->uid); $doc->contentMarkdown = $this->post->contentMarkdown; @@ -2304,7 +2310,7 @@ EOT; { $libs = $this->getLibsByObject('book', 0, '', $appendLib); $this->app->rawMethod = 'book'; - if($libID == 0 and !empty($libs)) $libID = reset($libs)->id; + if(!empty($libs) and ($libID == 0 or !isset($libs[$libID]))) $libID = reset($libs)->id; $this->lang->modulePageNav = $this->select($type, $objects, $objectID, $libs, $libID); $object = new stdclass(); diff --git a/module/doc/view/tablecontents.html.php b/module/doc/view/tablecontents.html.php index e54b1de5a8..fa0adfb0db 100644 --- a/module/doc/view/tablecontents.html.php +++ b/module/doc/view/tablecontents.html.php @@ -52,7 +52,7 @@ if(empty($type)) $type = 'product'; echo '
    '; } - if($type == 'book' and ($canEditLib or $canManageBook)) + if($type == 'book' and ($canEditLib or $canManageBook) and !empty($libs)) { echo "