headers); $x++)
+ {
+ if(preg_match('/^set-cookie:[\s]+([^=]+)=([^;]+)/i', $this->headers[$x],$match))
+ $this->cookies[$match[1]] = urldecode($match[2]);
+ }
+ }
+
+
+/*======================================================================*\
+ Function: _check_timeout
+ Purpose: checks whether timeout has occurred
+ Input: $fp file pointer
+\*======================================================================*/
+
+ function _check_timeout($fp)
+ {
+ if ($this->read_timeout > 0) {
+ $fp_status = socket_get_status($fp);
+ if ($fp_status["timed_out"]) {
+ $this->timed_out = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+/*======================================================================*\
+ Function: _connect
+ Purpose: make a socket connection
+ Input: $fp file pointer
+\*======================================================================*/
+
+ function _connect(&$fp)
+ {
+ if(!empty($this->proxy_host) && !empty($this->proxy_port))
+ {
+ $this->_isproxy = true;
+
+ $host = $this->proxy_host;
+ $port = $this->proxy_port;
+ }
+ else
+ {
+ $host = $this->host;
+ $port = $this->port;
+ }
+
+ $this->status = 0;
+
+ if($fp = fsockopen(
+ $host,
+ $port,
+ $errno,
+ $errstr,
+ $this->_fp_timeout
+ ))
+ {
+ // socket connection succeeded
+
+ return true;
+ }
+ else
+ {
+ // socket connection failed
+ $this->status = $errno;
+ switch($errno)
+ {
+ case -3:
+ $this->error="socket creation failed (-3)";
+ case -4:
+ $this->error="dns lookup failure (-4)";
+ case -5:
+ $this->error="connection refused or timed out (-5)";
+ default:
+ $this->error="connection failed (".$errno.")";
+ }
+ return false;
+ }
+ }
+/*======================================================================*\
+ Function: _disconnect
+ Purpose: disconnect a socket connection
+ Input: $fp file pointer
+\*======================================================================*/
+
+ function _disconnect($fp)
+ {
+ return(fclose($fp));
+ }
+
+
+/*======================================================================*\
+ Function: _prepare_post_body
+ Purpose: Prepare post body according to encoding type
+ Input: $formvars - form variables
+ $formfiles - form upload files
+ Output: post body
+\*======================================================================*/
+
+ function _prepare_post_body($formvars, $formfiles)
+ {
+ settype($formvars, "array");
+ settype($formfiles, "array");
+ $postdata = '';
+
+ if (count($formvars) == 0 && count($formfiles) == 0)
+ return;
+
+ switch ($this->_submit_type) {
+ case "application/x-www-form-urlencoded":
+ reset($formvars);
+ while(list($key,$val) = each($formvars)) {
+ if (is_array($val) || is_object($val)) {
+ while (list($cur_key, $cur_val) = each($val)) {
+ $postdata .= urlencode($key)."[]=".urlencode($cur_val)."&";
+ }
+ } else
+ $postdata .= urlencode($key)."=".urlencode($val)."&";
+ }
+ break;
+
+ case "multipart/form-data":
+ $this->_mime_boundary = "Snoopy".md5(uniqid(microtime()));
+
+ reset($formvars);
+ while(list($key,$val) = each($formvars)) {
+ if (is_array($val) || is_object($val)) {
+ while (list($cur_key, $cur_val) = each($val)) {
+ $postdata .= "--".$this->_mime_boundary."\r\n";
+ $postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n";
+ $postdata .= "$cur_val\r\n";
+ }
+ } else {
+ $postdata .= "--".$this->_mime_boundary."\r\n";
+ $postdata .= "Content-Disposition: form-data; name=\"$key\"\r\n\r\n";
+ $postdata .= "$val\r\n";
+ }
+ }
+
+ reset($formfiles);
+ while (list($field_name, $file_names) = each($formfiles)) {
+ settype($file_names, "array");
+ while (list(, $file_name) = each($file_names)) {
+ if (!is_readable($file_name)) continue;
+
+ $fp = fopen($file_name, "r");
+ $file_content = fread($fp, filesize($file_name));
+ fclose($fp);
+ $base_name = basename($file_name);
+
+ $postdata .= "--".$this->_mime_boundary."\r\n";
+ $postdata .= "Content-Disposition: form-data; name=\"$field_name\"; filename=\"$base_name\"\r\n\r\n";
+ $postdata .= "$file_content\r\n";
+ }
+ }
+ $postdata .= "--".$this->_mime_boundary."--\r\n";
+ break;
+ }
+
+ return $postdata;
+ }
+}
+?>
diff --git a/module/action/control.php b/module/action/control.php
index 7182ec27b9..8c881a7c2c 100644
--- a/module/action/control.php
+++ b/module/action/control.php
@@ -1,66 +1,66 @@
-
- * @package action
- * @version $Id$
- * @link http://www.zentao.net
- */
-class action extends control
-{
- /**
- * Trash
- *
- * @param string $orderBy
- * @param int $recTotal
- * @param int $recPerPage
- * @param int $pageID
- * @access public
- * @return void
- */
- public function trash($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
- {
- /* Save session. */
- $uri = $this->app->getURI(true);
- $this->session->set('productList', $uri);
- $this->session->set('productPlanList', $uri);
- $this->session->set('releaseList', $uri);
- $this->session->set('storyList', $uri);
- $this->session->set('projectList', $uri);
- $this->session->set('taskList', $uri);
- $this->session->set('buildList', $uri);
- $this->session->set('bugList', $uri);
- $this->session->set('caseList', $uri);
- $this->session->set('testtaskList', $uri);
-
- /* Header and position. */
- $this->view->header->title = $this->lang->action->trash;
- $this->view->position[] = $this->lang->action->trash;
-
- /* Get deleted objects. */
- $this->app->loadClass('pager', $static = true);
- $pager = pager::init($recTotal, $recPerPage, $pageID);
- $this->view->trashes = $this->action->getTrashes($orderBy, $pager);
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
- $this->view->users['system'] = 'system';
- $this->view->orderBy = $orderBy;
- $this->view->pager = $pager;
- $this->display();
- }
-
- /**
- * Undelete an object.
- *
- * @param int $actionID
- * @access public
- * @return void
- */
- public function undelete($actionID)
- {
- $this->action->undelete($actionID);
- die(js::locate(inlink('trash'), 'parent'));
- }
-}
+
+ * @package action
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class action extends control
+{
+ /**
+ * Trash
+ *
+ * @param string $orderBy
+ * @param int $recTotal
+ * @param int $recPerPage
+ * @param int $pageID
+ * @access public
+ * @return void
+ */
+ public function trash($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
+ {
+ /* Save session. */
+ $uri = $this->app->getURI(true);
+ $this->session->set('productList', $uri);
+ $this->session->set('productPlanList', $uri);
+ $this->session->set('releaseList', $uri);
+ $this->session->set('storyList', $uri);
+ $this->session->set('projectList', $uri);
+ $this->session->set('taskList', $uri);
+ $this->session->set('buildList', $uri);
+ $this->session->set('bugList', $uri);
+ $this->session->set('caseList', $uri);
+ $this->session->set('testtaskList', $uri);
+
+ /* Header and position. */
+ $this->view->header->title = $this->lang->action->trash;
+ $this->view->position[] = $this->lang->action->trash;
+
+ /* Get deleted objects. */
+ $this->app->loadClass('pager', $static = true);
+ $pager = pager::init($recTotal, $recPerPage, $pageID);
+ $this->view->trashes = $this->action->getTrashes($orderBy, $pager);
+ $this->view->users = $this->loadModel('user')->getPairs('noletter');
+ $this->view->users['system'] = 'system';
+ $this->view->orderBy = $orderBy;
+ $this->view->pager = $pager;
+ $this->display();
+ }
+
+ /**
+ * Undelete an object.
+ *
+ * @param int $actionID
+ * @access public
+ * @return void
+ */
+ public function undelete($actionID)
+ {
+ $this->action->undelete($actionID);
+ die(js::locate(inlink('trash'), 'parent'));
+ }
+}
diff --git a/module/action/lang/en.php b/module/action/lang/en.php
index aaf6727c75..7671f1bcea 100644
--- a/module/action/lang/en.php
+++ b/module/action/lang/en.php
@@ -1,181 +1,181 @@
-
- * @package action
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->action->common = 'Logs';
-$lang->action->trash = 'Trash';
-$lang->action->undelete = 'Restore';
-
-$lang->action->product = 'Product';
-$lang->action->project = 'Project';
-$lang->action->objectType = 'Object';
-$lang->action->objectID = 'ID';
-$lang->action->objectName = 'Name';
-$lang->action->actor = 'Actor';
-$lang->action->action = 'Action';
-$lang->action->actionID = 'ActionID';
-$lang->action->date = 'Date';
-$lang->action->trashTips = "Tips:The deleting actions in zentao are all logic";
-
-$lang->action->dynamic->today = 'Today';
-$lang->action->dynamic->yesterday = 'Yesterday';
-$lang->action->dynamic->twoDaysAgo = 'Two days ago';
-$lang->action->dynamic->thisWeek = 'This week';
-$lang->action->dynamic->lastWeek = 'Last week';
-$lang->action->dynamic->thisMonth = 'This month';
-$lang->action->dynamic->lastMonth = 'Last month';
-$lang->action->dynamic->all = 'All';
-$lang->action->dynamic->search = 'Search';
-
-$lang->action->objectTypes['product'] = 'PRODUCT';
-$lang->action->objectTypes['story'] = 'STORY';
-$lang->action->objectTypes['productplan'] = 'PLAN';
-$lang->action->objectTypes['release'] = 'RELEASE';
-$lang->action->objectTypes['project'] = 'PROJECT';
-$lang->action->objectTypes['task'] = 'TASK';
-$lang->action->objectTypes['build'] = 'Build';
-$lang->action->objectTypes['bug'] = 'Bug';
-$lang->action->objectTypes['case'] = 'Case';
-$lang->action->objectTypes['testtask'] = 'Test Task';
-$lang->action->objectTypes['user'] = 'User';
-$lang->action->objectTypes['doc'] = 'DOC';
-$lang->action->objectTypes['doclib'] = 'DocLib';
-$lang->action->objectTypes['todo'] = 'TODO';
-
-/* The desc of actions. */
-$lang->action->desc->common = '$date, $action by $actor ';
-$lang->action->desc->extra = '$date, $action as $extra by $actor ';
-$lang->action->desc->opened = '$date, Opened by $actor .';
-$lang->action->desc->created = '$date, Created by $actor .';
-$lang->action->desc->changed = '$date, Changed by $actor .';
-$lang->action->desc->edited = '$date, Edited by $actor .';
-$lang->action->desc->assigned = '$date, $actor assigned task to $extra .' . "\n";
-$lang->action->desc->closed = '$date, Closed by $actor .';
-$lang->action->desc->deleted = '$date, Deleted by $actor .';
-$lang->action->desc->deletedfile = '$date, Deleted file by $actor , the file is $extra ';
-$lang->action->desc->editfile = '$date, Edit file by $actor , the file is $extra ';
-$lang->action->desc->erased = '$date, Erased by $actor .';
-$lang->action->desc->undeleted = '$date, Restored by $actor .';
-$lang->action->desc->commented = '$date, Commented by $actor .';
-$lang->action->desc->activated = '$date, Activated by $actor .';
-$lang->action->desc->moved = '$date, Moved by $actor , previouse is "$extra"';
-$lang->action->desc->confirmed = '$date, Confirmed by $actor , version is#$extra ';
-$lang->action->desc->bugconfirmed = '$date, Confirmed by $actor ';
-$lang->action->desc->frombug = '$date, From Bug by $actor BugID:$extra 。';
-$lang->action->desc->started = '$date, Started by $actor .';
-$lang->action->desc->canceled = '$date, Canceled by $actor .';
-$lang->action->desc->svncommited = '$date, $actor commited to svn,revision is #$extra ' . "\n";
-$lang->action->desc->finished = '$date, Finished by $actor .';
-$lang->action->desc->diff1 = 'Changed %s , old is "%s", new is "%s". ';
-$lang->action->desc->diff2 = 'Changed %s , the diff is:%s ' . "\n";
-$lang->action->desc->diff3 = "Changed file's name %s to %s ";
-
-/* The action labels. */
-$lang->action->label->created = 'created';
-$lang->action->label->opened = 'opened';
-$lang->action->label->changed = 'changed';
-$lang->action->label->edited = 'edited';
-$lang->action->label->assigned = 'assigned';
-$lang->action->label->closed = 'closed';
-$lang->action->label->deleted = 'deleted';
-$lang->action->label->deletedfile = 'deleted file';
-$lang->action->label->editfile = 'edit file name';
-$lang->action->label->erased = 'deleted';
-$lang->action->label->undeleted = 'restore';
-$lang->action->label->commented = 'commented';
-$lang->action->label->activated = 'activated';
-$lang->action->label->resolved = 'resolved';
-$lang->action->label->reviewed = 'reviewed';
-$lang->action->label->moved = 'moded';
-$lang->action->label->confirmed = 'confirmed,';
-$lang->action->label->bugconfirmed = 'confirmed';
-$lang->action->label->tostory = 'converted to story';
-$lang->action->label->frombug = 'converted from bug';
-$lang->action->label->totask = 'converted to task';
-$lang->action->label->svncommited = 'commited code';
-$lang->action->label->linked2plan = 'link to plan';
-$lang->action->label->unlinkedfromplan = 'unlink from plan';
-$lang->action->label->linked2project = 'link to project';
-$lang->action->label->unlinkedfromproject = 'unlik from project';
-$lang->action->label->marked = 'edited';
-$lang->action->label->started = 'started';
-$lang->action->label->canceled = 'canceled';
-$lang->action->label->finished = 'finished';
-$lang->action->label->login = 'login';
-$lang->action->label->logout = "logout";
-
-/* Link of every action. */
-$lang->action->label->product = 'product|product|view|productID=%s';
-$lang->action->label->productplan = 'plan|productplan|view|productID=%s';
-$lang->action->label->release = 'release|release|view|productID=%s';
-$lang->action->label->story = 'story|story|view|storyID=%s';
-$lang->action->label->project = 'project|project|view|projectID=%s';
-$lang->action->label->task = 'task|task|view|taskID=%s';
-$lang->action->label->build = 'build|build|view|buildID=%s';
-$lang->action->label->bug = 'bug|bug|view|bugID=%s';
-$lang->action->label->case = 'case|testcase|view|caseID=%s';
-$lang->action->label->testtask = 'test task|testtask|view|caseID=%s';
-$lang->action->label->todo = 'todo|todo|view|todoID=%s';
-$lang->action->label->doclib = 'doc library|doc|browse|libID=%s';
-$lang->action->label->doc = 'doc|doc|view|docID=%s';
-$lang->action->label->user = 'user';
-$lang->action->label->space = ' ';
-
-/* Object type. */
-$lang->action->search->objectTypeList[''] = '';
-$lang->action->search->objectTypeList['product'] = 'product';
-$lang->action->search->objectTypeList['project'] = 'project';
-$lang->action->search->objectTypeList['bug'] = 'bug';
-$lang->action->search->objectTypeList['case'] = 'case';
-$lang->action->search->objectTypeList['story'] = 'story';
-$lang->action->search->objectTypeList['task'] = 'task';
-$lang->action->search->objectTypeList['testtask'] = 'testtask';
-$lang->action->search->objectTypeList['user'] = 'user';
-$lang->action->search->objectTypeList['doc'] = 'doc';
-$lang->action->search->objectTypeList['doclib'] = 'doclib';
-$lang->action->search->objectTypeList['todo'] = 'todo';
-$lang->action->search->objectTypeList['build'] = 'build';
-$lang->action->search->objectTypeList['release'] = 'release';
-$lang->action->search->objectTypeList['productplan'] = 'productplan';
-
-/* Display action for search. */
-$lang->action->search->label[''] = '';
-$lang->action->search->label['created'] = $lang->action->label->created;
-$lang->action->search->label['opened'] = $lang->action->label->opened;
-$lang->action->search->label['changed'] = $lang->action->label->changed;
-$lang->action->search->label['edited'] = $lang->action->label->edited;
-$lang->action->search->label['assigned'] = $lang->action->label->assigned;
-$lang->action->search->label['closed'] = $lang->action->label->closed;
-$lang->action->search->label['deleted'] = $lang->action->label->deleted;
-$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile;
-$lang->action->search->label['editfile'] = $lang->action->label->editfile;
-$lang->action->search->label['erased'] = $lang->action->label->erased;
-$lang->action->search->label['undeleted'] = $lang->action->label->undeleted;
-$lang->action->search->label['commented'] = $lang->action->label->commented;
-$lang->action->search->label['activated'] = $lang->action->label->activated;
-$lang->action->search->label['resolved'] = $lang->action->label->resolved;
-$lang->action->search->label['reviewed'] = $lang->action->label->reviewed;
-$lang->action->search->label['moved'] = $lang->action->label->moved;
-$lang->action->search->label['confirmed'] = $lang->action->label->confirmed;
-$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed;
-$lang->action->search->label['tostory'] = $lang->action->label->tostory;
-$lang->action->search->label['frombug'] = $lang->action->label->frombug;
-$lang->action->search->label['totask'] = $lang->action->label->totask;
-$lang->action->search->label['svncommited'] = $lang->action->label->svncommited;
-$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan;
-$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan;
-$lang->action->search->label['linked2project'] = $lang->action->label->linked2project;
-$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject;
-$lang->action->search->label['marked'] = $lang->action->label->marked;
-$lang->action->search->label['started'] = $lang->action->label->started;
-$lang->action->search->label['canceled'] = $lang->action->label->canceled;
-$lang->action->search->label['finished'] = $lang->action->label->finished;
-$lang->action->search->label['login'] = $lang->action->label->login;
-$lang->action->search->label['logout'] = $lang->action->label->logout;
+
+ * @package action
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->action->common = 'Logs';
+$lang->action->trash = 'Trash';
+$lang->action->undelete = 'Restore';
+
+$lang->action->product = 'Product';
+$lang->action->project = 'Project';
+$lang->action->objectType = 'Object';
+$lang->action->objectID = 'ID';
+$lang->action->objectName = 'Name';
+$lang->action->actor = 'Actor';
+$lang->action->action = 'Action';
+$lang->action->actionID = 'ActionID';
+$lang->action->date = 'Date';
+$lang->action->trashTips = "Tips:The deleting actions in zentao are all logic";
+
+$lang->action->dynamic->today = 'Today';
+$lang->action->dynamic->yesterday = 'Yesterday';
+$lang->action->dynamic->twoDaysAgo = 'Two days ago';
+$lang->action->dynamic->thisWeek = 'This week';
+$lang->action->dynamic->lastWeek = 'Last week';
+$lang->action->dynamic->thisMonth = 'This month';
+$lang->action->dynamic->lastMonth = 'Last month';
+$lang->action->dynamic->all = 'All';
+$lang->action->dynamic->search = 'Search';
+
+$lang->action->objectTypes['product'] = 'PRODUCT';
+$lang->action->objectTypes['story'] = 'STORY';
+$lang->action->objectTypes['productplan'] = 'PLAN';
+$lang->action->objectTypes['release'] = 'RELEASE';
+$lang->action->objectTypes['project'] = 'PROJECT';
+$lang->action->objectTypes['task'] = 'TASK';
+$lang->action->objectTypes['build'] = 'Build';
+$lang->action->objectTypes['bug'] = 'Bug';
+$lang->action->objectTypes['case'] = 'Case';
+$lang->action->objectTypes['testtask'] = 'Test Task';
+$lang->action->objectTypes['user'] = 'User';
+$lang->action->objectTypes['doc'] = 'DOC';
+$lang->action->objectTypes['doclib'] = 'DocLib';
+$lang->action->objectTypes['todo'] = 'TODO';
+
+/* The desc of actions. */
+$lang->action->desc->common = '$date, $action by $actor ';
+$lang->action->desc->extra = '$date, $action as $extra by $actor ';
+$lang->action->desc->opened = '$date, Opened by $actor .';
+$lang->action->desc->created = '$date, Created by $actor .';
+$lang->action->desc->changed = '$date, Changed by $actor .';
+$lang->action->desc->edited = '$date, Edited by $actor .';
+$lang->action->desc->assigned = '$date, $actor assigned task to $extra .' . "\n";
+$lang->action->desc->closed = '$date, Closed by $actor .';
+$lang->action->desc->deleted = '$date, Deleted by $actor .';
+$lang->action->desc->deletedfile = '$date, Deleted file by $actor , the file is $extra ';
+$lang->action->desc->editfile = '$date, Edit file by $actor , the file is $extra ';
+$lang->action->desc->erased = '$date, Erased by $actor .';
+$lang->action->desc->undeleted = '$date, Restored by $actor .';
+$lang->action->desc->commented = '$date, Commented by $actor .';
+$lang->action->desc->activated = '$date, Activated by $actor .';
+$lang->action->desc->moved = '$date, Moved by $actor , previouse is "$extra"';
+$lang->action->desc->confirmed = '$date, Confirmed by $actor , version is#$extra ';
+$lang->action->desc->bugconfirmed = '$date, Confirmed by $actor ';
+$lang->action->desc->frombug = '$date, From Bug by $actor BugID:$extra 。';
+$lang->action->desc->started = '$date, Started by $actor .';
+$lang->action->desc->canceled = '$date, Canceled by $actor .';
+$lang->action->desc->svncommited = '$date, $actor commited to svn,revision is #$extra ' . "\n";
+$lang->action->desc->finished = '$date, Finished by $actor .';
+$lang->action->desc->diff1 = 'Changed %s , old is "%s", new is "%s". ';
+$lang->action->desc->diff2 = 'Changed %s , the diff is:%s ' . "\n";
+$lang->action->desc->diff3 = "Changed file's name %s to %s ";
+
+/* The action labels. */
+$lang->action->label->created = 'created';
+$lang->action->label->opened = 'opened';
+$lang->action->label->changed = 'changed';
+$lang->action->label->edited = 'edited';
+$lang->action->label->assigned = 'assigned';
+$lang->action->label->closed = 'closed';
+$lang->action->label->deleted = 'deleted';
+$lang->action->label->deletedfile = 'deleted file';
+$lang->action->label->editfile = 'edit file name';
+$lang->action->label->erased = 'deleted';
+$lang->action->label->undeleted = 'restore';
+$lang->action->label->commented = 'commented';
+$lang->action->label->activated = 'activated';
+$lang->action->label->resolved = 'resolved';
+$lang->action->label->reviewed = 'reviewed';
+$lang->action->label->moved = 'moded';
+$lang->action->label->confirmed = 'confirmed,';
+$lang->action->label->bugconfirmed = 'confirmed';
+$lang->action->label->tostory = 'converted to story';
+$lang->action->label->frombug = 'converted from bug';
+$lang->action->label->totask = 'converted to task';
+$lang->action->label->svncommited = 'commited code';
+$lang->action->label->linked2plan = 'link to plan';
+$lang->action->label->unlinkedfromplan = 'unlink from plan';
+$lang->action->label->linked2project = 'link to project';
+$lang->action->label->unlinkedfromproject = 'unlik from project';
+$lang->action->label->marked = 'edited';
+$lang->action->label->started = 'started';
+$lang->action->label->canceled = 'canceled';
+$lang->action->label->finished = 'finished';
+$lang->action->label->login = 'login';
+$lang->action->label->logout = "logout";
+
+/* Link of every action. */
+$lang->action->label->product = 'product|product|view|productID=%s';
+$lang->action->label->productplan = 'plan|productplan|view|productID=%s';
+$lang->action->label->release = 'release|release|view|productID=%s';
+$lang->action->label->story = 'story|story|view|storyID=%s';
+$lang->action->label->project = 'project|project|view|projectID=%s';
+$lang->action->label->task = 'task|task|view|taskID=%s';
+$lang->action->label->build = 'build|build|view|buildID=%s';
+$lang->action->label->bug = 'bug|bug|view|bugID=%s';
+$lang->action->label->case = 'case|testcase|view|caseID=%s';
+$lang->action->label->testtask = 'test task|testtask|view|caseID=%s';
+$lang->action->label->todo = 'todo|todo|view|todoID=%s';
+$lang->action->label->doclib = 'doc library|doc|browse|libID=%s';
+$lang->action->label->doc = 'doc|doc|view|docID=%s';
+$lang->action->label->user = 'user';
+$lang->action->label->space = ' ';
+
+/* Object type. */
+$lang->action->search->objectTypeList[''] = '';
+$lang->action->search->objectTypeList['product'] = 'product';
+$lang->action->search->objectTypeList['project'] = 'project';
+$lang->action->search->objectTypeList['bug'] = 'bug';
+$lang->action->search->objectTypeList['case'] = 'case';
+$lang->action->search->objectTypeList['story'] = 'story';
+$lang->action->search->objectTypeList['task'] = 'task';
+$lang->action->search->objectTypeList['testtask'] = 'testtask';
+$lang->action->search->objectTypeList['user'] = 'user';
+$lang->action->search->objectTypeList['doc'] = 'doc';
+$lang->action->search->objectTypeList['doclib'] = 'doclib';
+$lang->action->search->objectTypeList['todo'] = 'todo';
+$lang->action->search->objectTypeList['build'] = 'build';
+$lang->action->search->objectTypeList['release'] = 'release';
+$lang->action->search->objectTypeList['productplan'] = 'productplan';
+
+/* Display action for search. */
+$lang->action->search->label[''] = '';
+$lang->action->search->label['created'] = $lang->action->label->created;
+$lang->action->search->label['opened'] = $lang->action->label->opened;
+$lang->action->search->label['changed'] = $lang->action->label->changed;
+$lang->action->search->label['edited'] = $lang->action->label->edited;
+$lang->action->search->label['assigned'] = $lang->action->label->assigned;
+$lang->action->search->label['closed'] = $lang->action->label->closed;
+$lang->action->search->label['deleted'] = $lang->action->label->deleted;
+$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile;
+$lang->action->search->label['editfile'] = $lang->action->label->editfile;
+$lang->action->search->label['erased'] = $lang->action->label->erased;
+$lang->action->search->label['undeleted'] = $lang->action->label->undeleted;
+$lang->action->search->label['commented'] = $lang->action->label->commented;
+$lang->action->search->label['activated'] = $lang->action->label->activated;
+$lang->action->search->label['resolved'] = $lang->action->label->resolved;
+$lang->action->search->label['reviewed'] = $lang->action->label->reviewed;
+$lang->action->search->label['moved'] = $lang->action->label->moved;
+$lang->action->search->label['confirmed'] = $lang->action->label->confirmed;
+$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed;
+$lang->action->search->label['tostory'] = $lang->action->label->tostory;
+$lang->action->search->label['frombug'] = $lang->action->label->frombug;
+$lang->action->search->label['totask'] = $lang->action->label->totask;
+$lang->action->search->label['svncommited'] = $lang->action->label->svncommited;
+$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan;
+$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan;
+$lang->action->search->label['linked2project'] = $lang->action->label->linked2project;
+$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject;
+$lang->action->search->label['marked'] = $lang->action->label->marked;
+$lang->action->search->label['started'] = $lang->action->label->started;
+$lang->action->search->label['canceled'] = $lang->action->label->canceled;
+$lang->action->search->label['finished'] = $lang->action->label->finished;
+$lang->action->search->label['login'] = $lang->action->label->login;
+$lang->action->search->label['logout'] = $lang->action->label->logout;
diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php
index 003065bf7f..322adcba1d 100644
--- a/module/action/lang/zh-cn.php
+++ b/module/action/lang/zh-cn.php
@@ -1,181 +1,181 @@
-
- * @package action
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->action->common = '系统日志';
-$lang->action->trash = '回收站';
-$lang->action->undelete = '还原';
-
-$lang->action->product = '产品';
-$lang->action->project = '项目';
-$lang->action->objectType = '对象类型';
-$lang->action->objectID = '对象ID';
-$lang->action->objectName = '对象名称';
-$lang->action->actor = '操作者';
-$lang->action->action = '动作';
-$lang->action->actionID = '记录ID';
-$lang->action->date = '日期';
-$lang->action->trashTips = '提示:为了保证系统的完整性,禅道系统的删除都是标记删除。';
-
-$lang->action->dynamic->today = '今天';
-$lang->action->dynamic->yesterday = '昨天';
-$lang->action->dynamic->twoDaysAgo = '前天';
-$lang->action->dynamic->thisWeek = '本周';
-$lang->action->dynamic->lastWeek = '上周';
-$lang->action->dynamic->thisMonth = '本月';
-$lang->action->dynamic->lastMonth = '上月';
-$lang->action->dynamic->all = '所有';
-$lang->action->dynamic->search = '搜索';
-
-$lang->action->objectTypes['product'] = '产品';
-$lang->action->objectTypes['story'] = '需求';
-$lang->action->objectTypes['productplan'] = '产品计划';
-$lang->action->objectTypes['release'] = '发布';
-$lang->action->objectTypes['project'] = '项目';
-$lang->action->objectTypes['task'] = '任务';
-$lang->action->objectTypes['build'] = 'Build';
-$lang->action->objectTypes['bug'] = 'Bug';
-$lang->action->objectTypes['case'] = '用例';
-$lang->action->objectTypes['testtask'] = '测试任务';
-$lang->action->objectTypes['user'] = '用户';
-$lang->action->objectTypes['doc'] = '文档';
-$lang->action->objectTypes['doclib'] = '文档库';
-$lang->action->objectTypes['todo'] = 'TODO';
-
-/* 用来描述操作历史记录。*/
-$lang->action->desc->common = '$date, $action by $actor ' . "\n";
-$lang->action->desc->extra = '$date, $action as $extra by $actor ' . "\n";
-$lang->action->desc->opened = '$date, 由 $actor 创建。' . "\n";
-$lang->action->desc->created = '$date, 由 $actor 创建。' . "\n";
-$lang->action->desc->changed = '$date, 由 $actor 变更。' . "\n";
-$lang->action->desc->edited = '$date, 由 $actor 编辑。' . "\n";
-$lang->action->desc->assigned = '$date, 由 $actor 指派给 $extra ' . "\n";
-$lang->action->desc->closed = '$date, 由 $actor 关闭。' . "\n";
-$lang->action->desc->deleted = '$date, 由 $actor 删除。' . "\n";
-$lang->action->desc->deletedfile = '$date, 由 $actor 删除了附件:$extra ' . "\n";
-$lang->action->desc->editfile = '$date, 由 $actor 编辑了附件:$extra ' . "\n";
-$lang->action->desc->erased = '$date, 由 $actor 删除。' . "\n";
-$lang->action->desc->undeleted = '$date, 由 $actor 还原。' . "\n";
-$lang->action->desc->commented = '$date, 由 $actor 添加备注。' . "\n";
-$lang->action->desc->activated = '$date, 由 $actor 激活。' . "\n";
-$lang->action->desc->moved = '$date, 由 $actor 移动,之前为 "$extra"' . "\n";
-$lang->action->desc->confirmed = '$date, 由 $actor 确认需求变动,最新版本为#$extra ' . "\n";
-$lang->action->desc->bugconfirmed = '$date, 由 $actor 确认Bug' . "\n";
-$lang->action->desc->frombug = '$date, 由 $actor Bug转化而来,Bug编号为 $extra 。';
-$lang->action->desc->started = '$date, 由 $actor 启动。' . "\n";
-$lang->action->desc->canceled = '$date, 由 $actor 取消。' . "\n";
-$lang->action->desc->svncommited = '$date, 由 $actor 提交代码,版本为#$extra ' . "\n";
-$lang->action->desc->finished = '$date, 由 $actor 完成。' . "\n";
-$lang->action->desc->diff1 = '修改了 %s ,旧值为 "%s",新值为 "%s"。 ' . "\n";
-$lang->action->desc->diff2 = '修改了 %s ,区别为:' . "\n" . '%s ' . "\n";
-$lang->action->desc->diff3 = '将文件名 %s 改为 %s ' . "\n";
-
-/* 用来显示动态信息。*/
-$lang->action->label->created = '创建了';
-$lang->action->label->opened = '创建了';
-$lang->action->label->changed = '变更了';
-$lang->action->label->edited = '编辑了';
-$lang->action->label->assigned = '指派了';
-$lang->action->label->closed = '关闭了';
-$lang->action->label->deleted = '删除了';
-$lang->action->label->deletedfile = '删除附件';
-$lang->action->label->editfile = '编辑附件';
-$lang->action->label->erased = '删除了';
-$lang->action->label->undeleted = '还原了';
-$lang->action->label->commented = '评论了';
-$lang->action->label->activated = '激活了';
-$lang->action->label->resolved = '解决了';
-$lang->action->label->reviewed = '评审了';
-$lang->action->label->moved = '移动了';
-$lang->action->label->confirmed = '确认了需求,';
-$lang->action->label->bugconfirmed = '确认了';
-$lang->action->label->tostory = '转需求';
-$lang->action->label->frombug = '转需求';
-$lang->action->label->totask = '转任务';
-$lang->action->label->svncommited = '提交代码';
-$lang->action->label->linked2plan = '关联计划';
-$lang->action->label->unlinkedfromplan = '移除计划';
-$lang->action->label->linked2project = '关联项目';
-$lang->action->label->unlinkedfromproject = '移除项目';
-$lang->action->label->marked = '编辑了';
-$lang->action->label->started = '开始了';
-$lang->action->label->canceled = '取消了';
-$lang->action->label->finished = '完成了';
-$lang->action->label->login = '登录系统';
-$lang->action->label->logout = "退出登录";
-
-/* 用来生成相应对象的链接。*/
-$lang->action->label->product = '产品|product|view|productID=%s';
-$lang->action->label->productplan = '计划|productplan|view|productID=%s';
-$lang->action->label->release = '发布|release|view|productID=%s';
-$lang->action->label->story = '需求|story|view|storyID=%s';
-$lang->action->label->project = '项目|project|view|projectID=%s';
-$lang->action->label->task = '任务|task|view|taskID=%s';
-$lang->action->label->build = 'Build|build|view|buildID=%s';
-$lang->action->label->bug = 'Bug|bug|view|bugID=%s';
-$lang->action->label->case = '用例|testcase|view|caseID=%s';
-$lang->action->label->testtask = '测试任务|testtask|view|caseID=%s';
-$lang->action->label->todo = 'todo|todo|view|todoID=%s';
-$lang->action->label->doclib = '文档库|doc|browse|libID=%s';
-$lang->action->label->doc = '文档|doc|view|docID=%s';
-$lang->action->label->user = '用户';
-$lang->action->label->space = ' ';
-
-/* Object type. */
-$lang->action->search->objectTypeList[''] = '';
-$lang->action->search->objectTypeList['product'] = '产品';
-$lang->action->search->objectTypeList['project'] = '项目';
-$lang->action->search->objectTypeList['bug'] = 'Bug';
-$lang->action->search->objectTypeList['case'] = '用例';
-$lang->action->search->objectTypeList['story'] = '需求';
-$lang->action->search->objectTypeList['task'] = '任务';
-$lang->action->search->objectTypeList['testtask'] = '测试任务';
-$lang->action->search->objectTypeList['user'] = '用户';
-$lang->action->search->objectTypeList['doc'] = '文档';
-$lang->action->search->objectTypeList['doclib'] = '文档库';
-$lang->action->search->objectTypeList['todo'] = 'TODO';
-$lang->action->search->objectTypeList['build'] = 'Build';
-$lang->action->search->objectTypeList['release'] = '发布';
-$lang->action->search->objectTypeList['productplan'] = '计划';
-
-/* 用来在动态显示中显示动作 */
-$lang->action->search->label[''] = '';
-$lang->action->search->label['created'] = $lang->action->label->created;
-$lang->action->search->label['opened'] = $lang->action->label->opened;
-$lang->action->search->label['changed'] = $lang->action->label->changed;
-$lang->action->search->label['edited'] = $lang->action->label->edited;
-$lang->action->search->label['assigned'] = $lang->action->label->assigned;
-$lang->action->search->label['closed'] = $lang->action->label->closed;
-$lang->action->search->label['deleted'] = $lang->action->label->deleted;
-$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile;
-$lang->action->search->label['editfile'] = $lang->action->label->editfile;
-$lang->action->search->label['erased'] = $lang->action->label->erased;
-$lang->action->search->label['undeleted'] = $lang->action->label->undeleted;
-$lang->action->search->label['commented'] = $lang->action->label->commented;
-$lang->action->search->label['activated'] = $lang->action->label->activated;
-$lang->action->search->label['resolved'] = $lang->action->label->resolved;
-$lang->action->search->label['reviewed'] = $lang->action->label->reviewed;
-$lang->action->search->label['moved'] = $lang->action->label->moved;
-$lang->action->search->label['confirmed'] = $lang->action->label->confirmed;
-$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed;
-$lang->action->search->label['tostory'] = $lang->action->label->tostory;
-$lang->action->search->label['frombug'] = $lang->action->label->frombug;
-$lang->action->search->label['totask'] = $lang->action->label->totask;
-$lang->action->search->label['svncommited'] = $lang->action->label->svncommited;
-$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan;
-$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan;
-$lang->action->search->label['linked2project'] = $lang->action->label->linked2project;
-$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject;
-$lang->action->search->label['marked'] = $lang->action->label->marked;
-$lang->action->search->label['started'] = $lang->action->label->started;
-$lang->action->search->label['canceled'] = $lang->action->label->canceled;
-$lang->action->search->label['finished'] = $lang->action->label->finished;
-$lang->action->search->label['login'] = $lang->action->label->login;
-$lang->action->search->label['logout'] = $lang->action->label->logout;
+
+ * @package action
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->action->common = '系统日志';
+$lang->action->trash = '回收站';
+$lang->action->undelete = '还原';
+
+$lang->action->product = '产品';
+$lang->action->project = '项目';
+$lang->action->objectType = '对象类型';
+$lang->action->objectID = '对象ID';
+$lang->action->objectName = '对象名称';
+$lang->action->actor = '操作者';
+$lang->action->action = '动作';
+$lang->action->actionID = '记录ID';
+$lang->action->date = '日期';
+$lang->action->trashTips = '提示:为了保证系统的完整性,禅道系统的删除都是标记删除。';
+
+$lang->action->dynamic->today = '今天';
+$lang->action->dynamic->yesterday = '昨天';
+$lang->action->dynamic->twoDaysAgo = '前天';
+$lang->action->dynamic->thisWeek = '本周';
+$lang->action->dynamic->lastWeek = '上周';
+$lang->action->dynamic->thisMonth = '本月';
+$lang->action->dynamic->lastMonth = '上月';
+$lang->action->dynamic->all = '所有';
+$lang->action->dynamic->search = '搜索';
+
+$lang->action->objectTypes['product'] = '产品';
+$lang->action->objectTypes['story'] = '需求';
+$lang->action->objectTypes['productplan'] = '产品计划';
+$lang->action->objectTypes['release'] = '发布';
+$lang->action->objectTypes['project'] = '项目';
+$lang->action->objectTypes['task'] = '任务';
+$lang->action->objectTypes['build'] = 'Build';
+$lang->action->objectTypes['bug'] = 'Bug';
+$lang->action->objectTypes['case'] = '用例';
+$lang->action->objectTypes['testtask'] = '测试任务';
+$lang->action->objectTypes['user'] = '用户';
+$lang->action->objectTypes['doc'] = '文档';
+$lang->action->objectTypes['doclib'] = '文档库';
+$lang->action->objectTypes['todo'] = 'TODO';
+
+/* 用来描述操作历史记录。*/
+$lang->action->desc->common = '$date, $action by $actor ' . "\n";
+$lang->action->desc->extra = '$date, $action as $extra by $actor ' . "\n";
+$lang->action->desc->opened = '$date, 由 $actor 创建。' . "\n";
+$lang->action->desc->created = '$date, 由 $actor 创建。' . "\n";
+$lang->action->desc->changed = '$date, 由 $actor 变更。' . "\n";
+$lang->action->desc->edited = '$date, 由 $actor 编辑。' . "\n";
+$lang->action->desc->assigned = '$date, 由 $actor 指派给 $extra ' . "\n";
+$lang->action->desc->closed = '$date, 由 $actor 关闭。' . "\n";
+$lang->action->desc->deleted = '$date, 由 $actor 删除。' . "\n";
+$lang->action->desc->deletedfile = '$date, 由 $actor 删除了附件:$extra ' . "\n";
+$lang->action->desc->editfile = '$date, 由 $actor 编辑了附件:$extra ' . "\n";
+$lang->action->desc->erased = '$date, 由 $actor 删除。' . "\n";
+$lang->action->desc->undeleted = '$date, 由 $actor 还原。' . "\n";
+$lang->action->desc->commented = '$date, 由 $actor 添加备注。' . "\n";
+$lang->action->desc->activated = '$date, 由 $actor 激活。' . "\n";
+$lang->action->desc->moved = '$date, 由 $actor 移动,之前为 "$extra"' . "\n";
+$lang->action->desc->confirmed = '$date, 由 $actor 确认需求变动,最新版本为#$extra ' . "\n";
+$lang->action->desc->bugconfirmed = '$date, 由 $actor 确认Bug' . "\n";
+$lang->action->desc->frombug = '$date, 由 $actor Bug转化而来,Bug编号为 $extra 。';
+$lang->action->desc->started = '$date, 由 $actor 启动。' . "\n";
+$lang->action->desc->canceled = '$date, 由 $actor 取消。' . "\n";
+$lang->action->desc->svncommited = '$date, 由 $actor 提交代码,版本为#$extra ' . "\n";
+$lang->action->desc->finished = '$date, 由 $actor 完成。' . "\n";
+$lang->action->desc->diff1 = '修改了 %s ,旧值为 "%s",新值为 "%s"。 ' . "\n";
+$lang->action->desc->diff2 = '修改了 %s ,区别为:' . "\n" . '%s ' . "\n";
+$lang->action->desc->diff3 = '将文件名 %s 改为 %s ' . "\n";
+
+/* 用来显示动态信息。*/
+$lang->action->label->created = '创建了';
+$lang->action->label->opened = '创建了';
+$lang->action->label->changed = '变更了';
+$lang->action->label->edited = '编辑了';
+$lang->action->label->assigned = '指派了';
+$lang->action->label->closed = '关闭了';
+$lang->action->label->deleted = '删除了';
+$lang->action->label->deletedfile = '删除附件';
+$lang->action->label->editfile = '编辑附件';
+$lang->action->label->erased = '删除了';
+$lang->action->label->undeleted = '还原了';
+$lang->action->label->commented = '评论了';
+$lang->action->label->activated = '激活了';
+$lang->action->label->resolved = '解决了';
+$lang->action->label->reviewed = '评审了';
+$lang->action->label->moved = '移动了';
+$lang->action->label->confirmed = '确认了需求,';
+$lang->action->label->bugconfirmed = '确认了';
+$lang->action->label->tostory = '转需求';
+$lang->action->label->frombug = '转需求';
+$lang->action->label->totask = '转任务';
+$lang->action->label->svncommited = '提交代码';
+$lang->action->label->linked2plan = '关联计划';
+$lang->action->label->unlinkedfromplan = '移除计划';
+$lang->action->label->linked2project = '关联项目';
+$lang->action->label->unlinkedfromproject = '移除项目';
+$lang->action->label->marked = '编辑了';
+$lang->action->label->started = '开始了';
+$lang->action->label->canceled = '取消了';
+$lang->action->label->finished = '完成了';
+$lang->action->label->login = '登录系统';
+$lang->action->label->logout = "退出登录";
+
+/* 用来生成相应对象的链接。*/
+$lang->action->label->product = '产品|product|view|productID=%s';
+$lang->action->label->productplan = '计划|productplan|view|productID=%s';
+$lang->action->label->release = '发布|release|view|productID=%s';
+$lang->action->label->story = '需求|story|view|storyID=%s';
+$lang->action->label->project = '项目|project|view|projectID=%s';
+$lang->action->label->task = '任务|task|view|taskID=%s';
+$lang->action->label->build = 'Build|build|view|buildID=%s';
+$lang->action->label->bug = 'Bug|bug|view|bugID=%s';
+$lang->action->label->case = '用例|testcase|view|caseID=%s';
+$lang->action->label->testtask = '测试任务|testtask|view|caseID=%s';
+$lang->action->label->todo = 'todo|todo|view|todoID=%s';
+$lang->action->label->doclib = '文档库|doc|browse|libID=%s';
+$lang->action->label->doc = '文档|doc|view|docID=%s';
+$lang->action->label->user = '用户';
+$lang->action->label->space = ' ';
+
+/* Object type. */
+$lang->action->search->objectTypeList[''] = '';
+$lang->action->search->objectTypeList['product'] = '产品';
+$lang->action->search->objectTypeList['project'] = '项目';
+$lang->action->search->objectTypeList['bug'] = 'Bug';
+$lang->action->search->objectTypeList['case'] = '用例';
+$lang->action->search->objectTypeList['story'] = '需求';
+$lang->action->search->objectTypeList['task'] = '任务';
+$lang->action->search->objectTypeList['testtask'] = '测试任务';
+$lang->action->search->objectTypeList['user'] = '用户';
+$lang->action->search->objectTypeList['doc'] = '文档';
+$lang->action->search->objectTypeList['doclib'] = '文档库';
+$lang->action->search->objectTypeList['todo'] = 'TODO';
+$lang->action->search->objectTypeList['build'] = 'Build';
+$lang->action->search->objectTypeList['release'] = '发布';
+$lang->action->search->objectTypeList['productplan'] = '计划';
+
+/* 用来在动态显示中显示动作 */
+$lang->action->search->label[''] = '';
+$lang->action->search->label['created'] = $lang->action->label->created;
+$lang->action->search->label['opened'] = $lang->action->label->opened;
+$lang->action->search->label['changed'] = $lang->action->label->changed;
+$lang->action->search->label['edited'] = $lang->action->label->edited;
+$lang->action->search->label['assigned'] = $lang->action->label->assigned;
+$lang->action->search->label['closed'] = $lang->action->label->closed;
+$lang->action->search->label['deleted'] = $lang->action->label->deleted;
+$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile;
+$lang->action->search->label['editfile'] = $lang->action->label->editfile;
+$lang->action->search->label['erased'] = $lang->action->label->erased;
+$lang->action->search->label['undeleted'] = $lang->action->label->undeleted;
+$lang->action->search->label['commented'] = $lang->action->label->commented;
+$lang->action->search->label['activated'] = $lang->action->label->activated;
+$lang->action->search->label['resolved'] = $lang->action->label->resolved;
+$lang->action->search->label['reviewed'] = $lang->action->label->reviewed;
+$lang->action->search->label['moved'] = $lang->action->label->moved;
+$lang->action->search->label['confirmed'] = $lang->action->label->confirmed;
+$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed;
+$lang->action->search->label['tostory'] = $lang->action->label->tostory;
+$lang->action->search->label['frombug'] = $lang->action->label->frombug;
+$lang->action->search->label['totask'] = $lang->action->label->totask;
+$lang->action->search->label['svncommited'] = $lang->action->label->svncommited;
+$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan;
+$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan;
+$lang->action->search->label['linked2project'] = $lang->action->label->linked2project;
+$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject;
+$lang->action->search->label['marked'] = $lang->action->label->marked;
+$lang->action->search->label['started'] = $lang->action->label->started;
+$lang->action->search->label['canceled'] = $lang->action->label->canceled;
+$lang->action->search->label['finished'] = $lang->action->label->finished;
+$lang->action->search->label['login'] = $lang->action->label->login;
+$lang->action->search->label['logout'] = $lang->action->label->logout;
diff --git a/module/action/lang/zh-tw.php b/module/action/lang/zh-tw.php
index 54719a6862..6dae1cd6b6 100644
--- a/module/action/lang/zh-tw.php
+++ b/module/action/lang/zh-tw.php
@@ -1,181 +1,181 @@
-
- * @package action
- * @version $Id: zh-tw.php 2528 2012-01-04 00:33:25Z wwccss $
- * @link http://www.zentao.net
- */
-$lang->action->common = '系統日誌';
-$lang->action->trash = '資源回收筒';
-$lang->action->undelete = '還原';
-
-$lang->action->product = '產品';
-$lang->action->project = '項目';
-$lang->action->objectType = '對象類型';
-$lang->action->objectID = '對象ID';
-$lang->action->objectName = '對象名稱';
-$lang->action->actor = '操作者';
-$lang->action->action = '動作';
-$lang->action->actionID = '記錄ID';
-$lang->action->date = '日期';
-$lang->action->trashTips = '提示:為了保證系統的完整性,禪道系統的刪除都是標記刪除。';
-
-$lang->action->dynamic->today = '今天';
-$lang->action->dynamic->yesterday = '昨天';
-$lang->action->dynamic->twoDaysAgo = '前天';
-$lang->action->dynamic->thisWeek = '本週';
-$lang->action->dynamic->lastWeek = '上周';
-$lang->action->dynamic->thisMonth = '本月';
-$lang->action->dynamic->lastMonth = '上月';
-$lang->action->dynamic->all = '所有';
-$lang->action->dynamic->search = '搜索';
-
-$lang->action->objectTypes['product'] = '產品';
-$lang->action->objectTypes['story'] = '需求';
-$lang->action->objectTypes['productplan'] = '產品計劃';
-$lang->action->objectTypes['release'] = '發佈';
-$lang->action->objectTypes['project'] = '項目';
-$lang->action->objectTypes['task'] = '任務';
-$lang->action->objectTypes['build'] = 'Build';
-$lang->action->objectTypes['bug'] = 'Bug';
-$lang->action->objectTypes['case'] = '用例';
-$lang->action->objectTypes['testtask'] = '測試任務';
-$lang->action->objectTypes['user'] = '用戶';
-$lang->action->objectTypes['doc'] = '文檔';
-$lang->action->objectTypes['doclib'] = '文檔庫';
-$lang->action->objectTypes['todo'] = 'TODO';
-
-/* 用來描述操作歷史記錄。*/
-$lang->action->desc->common = '$date, $action by $actor ' . "\n";
-$lang->action->desc->extra = '$date, $action as $extra by $actor ' . "\n";
-$lang->action->desc->opened = '$date, 由 $actor 創建。' . "\n";
-$lang->action->desc->created = '$date, 由 $actor 創建。' . "\n";
-$lang->action->desc->changed = '$date, 由 $actor 變更。' . "\n";
-$lang->action->desc->edited = '$date, 由 $actor 編輯。' . "\n";
-$lang->action->desc->assigned = '$date, 由 $actor 指派給 $extra ' . "\n";
-$lang->action->desc->closed = '$date, 由 $actor 關閉。' . "\n";
-$lang->action->desc->deleted = '$date, 由 $actor 刪除。' . "\n";
-$lang->action->desc->deletedfile = '$date, 由 $actor 刪除了附件:$extra ' . "\n";
-$lang->action->desc->editfile = '$date, 由 $actor 編輯了附件:$extra ' . "\n";
-$lang->action->desc->erased = '$date, 由 $actor 刪除。' . "\n";
-$lang->action->desc->undeleted = '$date, 由 $actor 還原。' . "\n";
-$lang->action->desc->commented = '$date, 由 $actor 添加備註。' . "\n";
-$lang->action->desc->activated = '$date, 由 $actor 激活。' . "\n";
-$lang->action->desc->moved = '$date, 由 $actor 移動,之前為 "$extra"' . "\n";
-$lang->action->desc->confirmed = '$date, 由 $actor 確認需求變動,最新版本為#$extra ' . "\n";
-$lang->action->desc->bugconfirmed = '$date, 由 $actor 確認Bug' . "\n";
-$lang->action->desc->frombug = '$date, 由 $actor Bug轉化而來,Bug編號為 $extra 。';
-$lang->action->desc->started = '$date, 由 $actor 啟動。' . "\n";
-$lang->action->desc->canceled = '$date, 由 $actor 取消。' . "\n";
-$lang->action->desc->svncommited = '$date, 由 $actor 提交代碼,版本為#$extra ' . "\n";
-$lang->action->desc->finished = '$date, 由 $actor 完成。' . "\n";
-$lang->action->desc->diff1 = '修改了 %s ,舊值為 "%s",新值為 "%s"。 ' . "\n";
-$lang->action->desc->diff2 = '修改了 %s ,區別為:' . "\n" . '%s ' . "\n";
-$lang->action->desc->diff3 = '將檔案名 %s 改為 %s ' . "\n";
-
-/* 用來顯示動態信息。*/
-$lang->action->label->created = '創建了';
-$lang->action->label->opened = '創建了';
-$lang->action->label->changed = '變更了';
-$lang->action->label->edited = '編輯了';
-$lang->action->label->assigned = '指派了';
-$lang->action->label->closed = '關閉了';
-$lang->action->label->deleted = '刪除了';
-$lang->action->label->deletedfile = '刪除附件';
-$lang->action->label->editfile = '編輯附件';
-$lang->action->label->erased = '刪除了';
-$lang->action->label->undeleted = '還原了';
-$lang->action->label->commented = '評論了';
-$lang->action->label->activated = '激活了';
-$lang->action->label->resolved = '解決了';
-$lang->action->label->reviewed = '評審了';
-$lang->action->label->moved = '移動了';
-$lang->action->label->confirmed = '確認了需求,';
-$lang->action->label->bugconfirmed = '確認了';
-$lang->action->label->tostory = '轉需求';
-$lang->action->label->frombug = '轉需求';
-$lang->action->label->totask = '轉任務';
-$lang->action->label->svncommited = '提交代碼';
-$lang->action->label->linked2plan = '關聯計劃';
-$lang->action->label->unlinkedfromplan = '移除計劃';
-$lang->action->label->linked2project = '關聯項目';
-$lang->action->label->unlinkedfromproject = '移除項目';
-$lang->action->label->marked = '編輯了';
-$lang->action->label->started = '開始了';
-$lang->action->label->canceled = '取消了';
-$lang->action->label->finished = '完成了';
-$lang->action->label->login = '登錄系統';
-$lang->action->label->logout = "退出登錄";
-
-/* 用來生成相應對象的連結。*/
-$lang->action->label->product = '產品|product|view|productID=%s';
-$lang->action->label->productplan = '計劃|productplan|view|productID=%s';
-$lang->action->label->release = '發佈|release|view|productID=%s';
-$lang->action->label->story = '需求|story|view|storyID=%s';
-$lang->action->label->project = '項目|project|view|projectID=%s';
-$lang->action->label->task = '任務|task|view|taskID=%s';
-$lang->action->label->build = 'Build|build|view|buildID=%s';
-$lang->action->label->bug = 'Bug|bug|view|bugID=%s';
-$lang->action->label->case = '用例|testcase|view|caseID=%s';
-$lang->action->label->testtask = '測試任務|testtask|view|caseID=%s';
-$lang->action->label->todo = 'todo|todo|view|todoID=%s';
-$lang->action->label->doclib = '文檔庫|doc|browse|libID=%s';
-$lang->action->label->doc = '文檔|doc|view|docID=%s';
-$lang->action->label->user = '用戶';
-$lang->action->label->space = ' ';
-
-/* Object type. */
-$lang->action->search->objectTypeList[''] = '';
-$lang->action->search->objectTypeList['product'] = '產品';
-$lang->action->search->objectTypeList['project'] = '項目';
-$lang->action->search->objectTypeList['bug'] = 'Bug';
-$lang->action->search->objectTypeList['case'] = '用例';
-$lang->action->search->objectTypeList['story'] = '需求';
-$lang->action->search->objectTypeList['task'] = '任務';
-$lang->action->search->objectTypeList['testtask'] = '測試任務';
-$lang->action->search->objectTypeList['user'] = '用戶';
-$lang->action->search->objectTypeList['doc'] = '文檔';
-$lang->action->search->objectTypeList['doclib'] = '文檔庫';
-$lang->action->search->objectTypeList['todo'] = 'TODO';
-$lang->action->search->objectTypeList['build'] = 'Build';
-$lang->action->search->objectTypeList['release'] = '發佈';
-$lang->action->search->objectTypeList['productplan'] = '計劃';
-
-/* 用來在動態顯示中顯示動作 */
-$lang->action->search->label[''] = '';
-$lang->action->search->label['created'] = $lang->action->label->created;
-$lang->action->search->label['opened'] = $lang->action->label->opened;
-$lang->action->search->label['changed'] = $lang->action->label->changed;
-$lang->action->search->label['edited'] = $lang->action->label->edited;
-$lang->action->search->label['assigned'] = $lang->action->label->assigned;
-$lang->action->search->label['closed'] = $lang->action->label->closed;
-$lang->action->search->label['deleted'] = $lang->action->label->deleted;
-$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile;
-$lang->action->search->label['editfile'] = $lang->action->label->editfile;
-$lang->action->search->label['erased'] = $lang->action->label->erased;
-$lang->action->search->label['undeleted'] = $lang->action->label->undeleted;
-$lang->action->search->label['commented'] = $lang->action->label->commented;
-$lang->action->search->label['activated'] = $lang->action->label->activated;
-$lang->action->search->label['resolved'] = $lang->action->label->resolved;
-$lang->action->search->label['reviewed'] = $lang->action->label->reviewed;
-$lang->action->search->label['moved'] = $lang->action->label->moved;
-$lang->action->search->label['confirmed'] = $lang->action->label->confirmed;
-$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed;
-$lang->action->search->label['tostory'] = $lang->action->label->tostory;
-$lang->action->search->label['frombug'] = $lang->action->label->frombug;
-$lang->action->search->label['totask'] = $lang->action->label->totask;
-$lang->action->search->label['svncommited'] = $lang->action->label->svncommited;
-$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan;
-$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan;
-$lang->action->search->label['linked2project'] = $lang->action->label->linked2project;
-$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject;
-$lang->action->search->label['marked'] = $lang->action->label->marked;
-$lang->action->search->label['started'] = $lang->action->label->started;
-$lang->action->search->label['canceled'] = $lang->action->label->canceled;
-$lang->action->search->label['finished'] = $lang->action->label->finished;
-$lang->action->search->label['login'] = $lang->action->label->login;
-$lang->action->search->label['logout'] = $lang->action->label->logout;
+
+ * @package action
+ * @version $Id: zh-tw.php 2528 2012-01-04 00:33:25Z wwccss $
+ * @link http://www.zentao.net
+ */
+$lang->action->common = '系統日誌';
+$lang->action->trash = '資源回收筒';
+$lang->action->undelete = '還原';
+
+$lang->action->product = '產品';
+$lang->action->project = '項目';
+$lang->action->objectType = '對象類型';
+$lang->action->objectID = '對象ID';
+$lang->action->objectName = '對象名稱';
+$lang->action->actor = '操作者';
+$lang->action->action = '動作';
+$lang->action->actionID = '記錄ID';
+$lang->action->date = '日期';
+$lang->action->trashTips = '提示:為了保證系統的完整性,禪道系統的刪除都是標記刪除。';
+
+$lang->action->dynamic->today = '今天';
+$lang->action->dynamic->yesterday = '昨天';
+$lang->action->dynamic->twoDaysAgo = '前天';
+$lang->action->dynamic->thisWeek = '本週';
+$lang->action->dynamic->lastWeek = '上周';
+$lang->action->dynamic->thisMonth = '本月';
+$lang->action->dynamic->lastMonth = '上月';
+$lang->action->dynamic->all = '所有';
+$lang->action->dynamic->search = '搜索';
+
+$lang->action->objectTypes['product'] = '產品';
+$lang->action->objectTypes['story'] = '需求';
+$lang->action->objectTypes['productplan'] = '產品計劃';
+$lang->action->objectTypes['release'] = '發佈';
+$lang->action->objectTypes['project'] = '項目';
+$lang->action->objectTypes['task'] = '任務';
+$lang->action->objectTypes['build'] = 'Build';
+$lang->action->objectTypes['bug'] = 'Bug';
+$lang->action->objectTypes['case'] = '用例';
+$lang->action->objectTypes['testtask'] = '測試任務';
+$lang->action->objectTypes['user'] = '用戶';
+$lang->action->objectTypes['doc'] = '文檔';
+$lang->action->objectTypes['doclib'] = '文檔庫';
+$lang->action->objectTypes['todo'] = 'TODO';
+
+/* 用來描述操作歷史記錄。*/
+$lang->action->desc->common = '$date, $action by $actor ' . "\n";
+$lang->action->desc->extra = '$date, $action as $extra by $actor ' . "\n";
+$lang->action->desc->opened = '$date, 由 $actor 創建。' . "\n";
+$lang->action->desc->created = '$date, 由 $actor 創建。' . "\n";
+$lang->action->desc->changed = '$date, 由 $actor 變更。' . "\n";
+$lang->action->desc->edited = '$date, 由 $actor 編輯。' . "\n";
+$lang->action->desc->assigned = '$date, 由 $actor 指派給 $extra ' . "\n";
+$lang->action->desc->closed = '$date, 由 $actor 關閉。' . "\n";
+$lang->action->desc->deleted = '$date, 由 $actor 刪除。' . "\n";
+$lang->action->desc->deletedfile = '$date, 由 $actor 刪除了附件:$extra ' . "\n";
+$lang->action->desc->editfile = '$date, 由 $actor 編輯了附件:$extra ' . "\n";
+$lang->action->desc->erased = '$date, 由 $actor 刪除。' . "\n";
+$lang->action->desc->undeleted = '$date, 由 $actor 還原。' . "\n";
+$lang->action->desc->commented = '$date, 由 $actor 添加備註。' . "\n";
+$lang->action->desc->activated = '$date, 由 $actor 激活。' . "\n";
+$lang->action->desc->moved = '$date, 由 $actor 移動,之前為 "$extra"' . "\n";
+$lang->action->desc->confirmed = '$date, 由 $actor 確認需求變動,最新版本為#$extra ' . "\n";
+$lang->action->desc->bugconfirmed = '$date, 由 $actor 確認Bug' . "\n";
+$lang->action->desc->frombug = '$date, 由 $actor Bug轉化而來,Bug編號為 $extra 。';
+$lang->action->desc->started = '$date, 由 $actor 啟動。' . "\n";
+$lang->action->desc->canceled = '$date, 由 $actor 取消。' . "\n";
+$lang->action->desc->svncommited = '$date, 由 $actor 提交代碼,版本為#$extra ' . "\n";
+$lang->action->desc->finished = '$date, 由 $actor 完成。' . "\n";
+$lang->action->desc->diff1 = '修改了 %s ,舊值為 "%s",新值為 "%s"。 ' . "\n";
+$lang->action->desc->diff2 = '修改了 %s ,區別為:' . "\n" . '%s ' . "\n";
+$lang->action->desc->diff3 = '將檔案名 %s 改為 %s ' . "\n";
+
+/* 用來顯示動態信息。*/
+$lang->action->label->created = '創建了';
+$lang->action->label->opened = '創建了';
+$lang->action->label->changed = '變更了';
+$lang->action->label->edited = '編輯了';
+$lang->action->label->assigned = '指派了';
+$lang->action->label->closed = '關閉了';
+$lang->action->label->deleted = '刪除了';
+$lang->action->label->deletedfile = '刪除附件';
+$lang->action->label->editfile = '編輯附件';
+$lang->action->label->erased = '刪除了';
+$lang->action->label->undeleted = '還原了';
+$lang->action->label->commented = '評論了';
+$lang->action->label->activated = '激活了';
+$lang->action->label->resolved = '解決了';
+$lang->action->label->reviewed = '評審了';
+$lang->action->label->moved = '移動了';
+$lang->action->label->confirmed = '確認了需求,';
+$lang->action->label->bugconfirmed = '確認了';
+$lang->action->label->tostory = '轉需求';
+$lang->action->label->frombug = '轉需求';
+$lang->action->label->totask = '轉任務';
+$lang->action->label->svncommited = '提交代碼';
+$lang->action->label->linked2plan = '關聯計劃';
+$lang->action->label->unlinkedfromplan = '移除計劃';
+$lang->action->label->linked2project = '關聯項目';
+$lang->action->label->unlinkedfromproject = '移除項目';
+$lang->action->label->marked = '編輯了';
+$lang->action->label->started = '開始了';
+$lang->action->label->canceled = '取消了';
+$lang->action->label->finished = '完成了';
+$lang->action->label->login = '登錄系統';
+$lang->action->label->logout = "退出登錄";
+
+/* 用來生成相應對象的連結。*/
+$lang->action->label->product = '產品|product|view|productID=%s';
+$lang->action->label->productplan = '計劃|productplan|view|productID=%s';
+$lang->action->label->release = '發佈|release|view|productID=%s';
+$lang->action->label->story = '需求|story|view|storyID=%s';
+$lang->action->label->project = '項目|project|view|projectID=%s';
+$lang->action->label->task = '任務|task|view|taskID=%s';
+$lang->action->label->build = 'Build|build|view|buildID=%s';
+$lang->action->label->bug = 'Bug|bug|view|bugID=%s';
+$lang->action->label->case = '用例|testcase|view|caseID=%s';
+$lang->action->label->testtask = '測試任務|testtask|view|caseID=%s';
+$lang->action->label->todo = 'todo|todo|view|todoID=%s';
+$lang->action->label->doclib = '文檔庫|doc|browse|libID=%s';
+$lang->action->label->doc = '文檔|doc|view|docID=%s';
+$lang->action->label->user = '用戶';
+$lang->action->label->space = ' ';
+
+/* Object type. */
+$lang->action->search->objectTypeList[''] = '';
+$lang->action->search->objectTypeList['product'] = '產品';
+$lang->action->search->objectTypeList['project'] = '項目';
+$lang->action->search->objectTypeList['bug'] = 'Bug';
+$lang->action->search->objectTypeList['case'] = '用例';
+$lang->action->search->objectTypeList['story'] = '需求';
+$lang->action->search->objectTypeList['task'] = '任務';
+$lang->action->search->objectTypeList['testtask'] = '測試任務';
+$lang->action->search->objectTypeList['user'] = '用戶';
+$lang->action->search->objectTypeList['doc'] = '文檔';
+$lang->action->search->objectTypeList['doclib'] = '文檔庫';
+$lang->action->search->objectTypeList['todo'] = 'TODO';
+$lang->action->search->objectTypeList['build'] = 'Build';
+$lang->action->search->objectTypeList['release'] = '發佈';
+$lang->action->search->objectTypeList['productplan'] = '計劃';
+
+/* 用來在動態顯示中顯示動作 */
+$lang->action->search->label[''] = '';
+$lang->action->search->label['created'] = $lang->action->label->created;
+$lang->action->search->label['opened'] = $lang->action->label->opened;
+$lang->action->search->label['changed'] = $lang->action->label->changed;
+$lang->action->search->label['edited'] = $lang->action->label->edited;
+$lang->action->search->label['assigned'] = $lang->action->label->assigned;
+$lang->action->search->label['closed'] = $lang->action->label->closed;
+$lang->action->search->label['deleted'] = $lang->action->label->deleted;
+$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile;
+$lang->action->search->label['editfile'] = $lang->action->label->editfile;
+$lang->action->search->label['erased'] = $lang->action->label->erased;
+$lang->action->search->label['undeleted'] = $lang->action->label->undeleted;
+$lang->action->search->label['commented'] = $lang->action->label->commented;
+$lang->action->search->label['activated'] = $lang->action->label->activated;
+$lang->action->search->label['resolved'] = $lang->action->label->resolved;
+$lang->action->search->label['reviewed'] = $lang->action->label->reviewed;
+$lang->action->search->label['moved'] = $lang->action->label->moved;
+$lang->action->search->label['confirmed'] = $lang->action->label->confirmed;
+$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed;
+$lang->action->search->label['tostory'] = $lang->action->label->tostory;
+$lang->action->search->label['frombug'] = $lang->action->label->frombug;
+$lang->action->search->label['totask'] = $lang->action->label->totask;
+$lang->action->search->label['svncommited'] = $lang->action->label->svncommited;
+$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan;
+$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan;
+$lang->action->search->label['linked2project'] = $lang->action->label->linked2project;
+$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject;
+$lang->action->search->label['marked'] = $lang->action->label->marked;
+$lang->action->search->label['started'] = $lang->action->label->started;
+$lang->action->search->label['canceled'] = $lang->action->label->canceled;
+$lang->action->search->label['finished'] = $lang->action->label->finished;
+$lang->action->search->label['login'] = $lang->action->label->login;
+$lang->action->search->label['logout'] = $lang->action->label->logout;
diff --git a/module/action/model.php b/module/action/model.php
index ed317c404c..16ce9ea1ce 100644
--- a/module/action/model.php
+++ b/module/action/model.php
@@ -1,528 +1,528 @@
-
- * @package action
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-objectType = strtolower($objectType);
- $action->objectID = $objectID;
- $action->actor = $this->app->user->account;
- $action->action = strtolower($actionType);
- $action->date = helper::now();
- $action->comment = htmlspecialchars($comment);
- $action->extra = $extra;
-
- /* Get product and project for this object. */
- $productAndProject = $this->getProductAndProject($objectType, $objectID);
- $action->product = $productAndProject['product'];
- $action->project = $productAndProject['project'];
-
- $this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec();
- return $this->dbh->lastInsertID();
- }
-
- /**
- * Get product and project of an object.
- *
- * @param string $objectType
- * @param int $objectID
- * @access public
- * @return array
- */
- public function getProductAndProject($objectType, $objectID)
- {
- $objectType = strtolower($objectType);
- $emptyRecord = array('product' => 0, 'project' => 0);
-
- /* If objectType is product or project, return the objectID. */
- if($objectType == 'product') return array('product' => $objectID, 'project' => 0);
- if($objectType == 'project') return array('project' => $objectID, 'product' => 0);
-
- /* Only process these object types. */
- if(strpos('story, productplan, release, task, build. bug, case, testtask, doc', $objectType) !== false)
- {
- if(!isset($this->config->action->objectTables[$objectType])) return $emptyRecord;
-
- /* Set fields to fetch. */
- if(strpos('story, productplan, case', $objectType) !== false) $fields = 'product';
- if(strpos('build, bug, testtask, doc', $objectType) !== false) $fields = 'product, project';
- if($objectType == 'release') $fields = 'product, build';
- if($objectType == 'task') $fields = 'project, story';
-
- $record = $this->dao->select($fields)->from($this->config->action->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
-
- /* Process story, release and task. */
- if($objectType == 'story') $record->project = $this->dao->select('project')->from(TABLE_PROJECTSTORY)->where('story')->eq($objectID)->fetch('project');
- if($objectType == 'release') $record->project = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($record->build)->fetch('project');
- if($objectType == 'task') $record->product = $this->dao->select('product')->from(TABLE_STORY)->where('id')->eq($record->story)->fetch('product');
-
- if($record)
- {
- $record = (array)$record;
- if(!isset($record['product'])) $record['product'] = 0;
- if(!isset($record['project'])) $record['project'] = 0;
- return $record;
- }
-
- return $emptyRecord;
- }
- return $emptyRecord;
- }
-
- /**
- * Get actions of an object.
- *
- * @param int $objectType
- * @param int $objectID
- * @access public
- * @return array
- */
- public function getList($objectType, $objectID)
- {
- $commiters = $this->loadModel('user')->getCommiters();
- $actions = $this->dao->select('*')->from(TABLE_ACTION)
- ->where('objectType')->eq($objectType)
- ->andWhere('objectID')->eq($objectID)
- ->orderBy('date, id')->fetchAll('id');
- $histories = $this->getHistory(array_keys($actions));
- foreach($actions as $actionID => $action)
- {
- if(strtolower($action->action) == 'svncommited' and isset($commiters[$action->actor])) $action->actor = $commiters[$action->actor];
- $action->history = isset($histories[$actionID]) ? $histories[$actionID] : array();
- $actions[$actionID] = $action;
- }
- return $actions;
- }
-
- /**
- * Get an action record.
- *
- * @param int $actionID
- * @access public
- * @return object
- */
- public function getById($actionID)
- {
- return $this->dao->findById((int)$actionID)->from(TABLE_ACTION)->fetch();
- }
-
- /**
- * Get deleted objects.
- *
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getTrashes($orderBy, $pager)
- {
- $trashes = $this->dao->select('*')->from(TABLE_ACTION)
- ->where('action')->eq('deleted')
- ->andWhere('extra')->eq(self::CAN_UNDELETED)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- if(!$trashes) return array();
-
- /* Group trashes by objectType, and get there name field. */
- foreach($trashes as $object)
- {
- $object->objectType = str_replace('`', '', $object->objectType);
- $typeTrashes[$object->objectType][] = $object->objectID;
- }
- foreach($typeTrashes as $objectType => $objectIds)
- {
- $objectIds = array_unique($objectIds);
- $table = $this->config->action->objectTables[$objectType];
- $field = $this->config->action->objectNameFields[$objectType];
- $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs();
- }
-
- /* Add name field to the trashes. */
- foreach($trashes as $trash) $trash->objectName = $objectNames[$trash->objectType][$trash->objectID];
- return $trashes;
- }
-
- /**
- * Get histories of an action.
- *
- * @param int $actionID
- * @access public
- * @return array
- */
- public function getHistory($actionID)
- {
- return $this->dao->select()->from(TABLE_HISTORY)->where('action')->in($actionID)->orderBy('id')->fetchGroup('action');
- }
-
- /**
- * Log histories for an action.
- *
- * @param int $actionID
- * @param array $changes
- * @access public
- * @return void
- */
- public function logHistory($actionID, $changes)
- {
- foreach($changes as $change)
- {
- $change['action'] = $actionID;
- $this->dao->insert(TABLE_HISTORY)->data($change)->exec();
- }
- }
-
- /**
- * Print actions of an object.
- *
- * @param array $action
- * @access public
- * @return void
- */
- public function printAction($action)
- {
- $objectType = $action->objectType;
- $actionType = strtolower($action->action);
-
- /**
- * Set the desc string of this action.
- *
- * 1. If the module of this action has defined desc of this actionType, use it.
- * 2. If no defined in the module language, search the common action define.
- * 3. If not found in the lang->action->desc, use the $lang->action->desc->common or $lang->action->desc->extra as the default.
- */
- if(isset($this->lang->$objectType->action->$actionType))
- {
- $desc = $this->lang->$objectType->action->$actionType;
- }
- elseif(isset($this->lang->action->desc->$actionType))
- {
- $desc = $this->lang->action->desc->$actionType;
- }
- else
- {
- $desc = $action->extra ? $this->lang->action->desc->extra : $this->lang->action->desc->common;
- }
-
- /* Cycle actions, replace vars. */
- foreach($action as $key => $value)
- {
- if($key == 'history') continue;
-
- /* Desc can be an array or string. */
- if(is_array($desc))
- {
- if($key == 'extra') continue;
- $desc['main'] = str_replace('$' . $key, $value, $desc['main']);
- }
- else
- {
- $desc = str_replace('$' . $key, $value, $desc);
- }
- }
-
- /* If the desc is an array, process extra. Please bug/lang. */
- if(is_array($desc))
- {
- $extra = strtolower($action->extra);
- if(isset($desc['extra'][$extra]))
- {
- echo str_replace('$extra', $desc['extra'][$extra], $desc['main']);
- }
- else
- {
- echo str_replace('$extra', $action->extra, $desc['main']);
- }
- }
- else
- {
- echo $desc;
- }
- }
-
- /**
- * Get actions as dynamic.
- *
- * @param string $objectType
- * @param string $count
- * @param string $period
- * @param string $orderBy
- * @param object $pager
- * @param string|int $productID all|int(like 123)|notzero all => include zeror, notzero, great than 0
- * @param string|int $projectID same as productID
- * @access public
- * @return array
- */
- public function getDynamic($account = 'all', $period = 'all', $orderBy = 'date_desc', $pager = null, $productID = 'all', $projectID = 'all')
- {
- /* Computer the begin and end date of a period. */
- $period = $this->computeBeginAndEnd($period);
- extract($period);
-
- /* Get actions. */
- $actions = $this->dao->select('*')->from(TABLE_ACTION)
- ->where('date')->gt($begin)
- ->andWhere('date')->lt($end)
- ->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi()
- ->beginIF(is_numeric($productID))->andWhere('product')->eq($productID)->fi()
- ->beginIF(is_numeric($projectID))->andWhere('project')->eq($projectID)->fi()
- ->beginIF($productID == 'notzero')->andWhere('product')->gt(0)->fi()
- ->beginIF($projectID == 'notzero')->andWhere('project')->gt(0)->fi()
- ->orderBy($orderBy)->page($pager)->fetchAll();
-
- if(!$actions) return array();
- return $this->transformActions($actions);
- }
-
- /**
- * Get dynamic by search.
- *
- * @param array $products
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getDynamicBySearch($products, $projects, $queryID, $orderBy = 'date_desc', $pager)
- {
- $query = $queryID ? $this->loadModel('search')->getQuery($queryID) : '';
-
- /* Get the sql and form status from the query. */
- if($query)
- {
- $this->session->set('actionQuery', $query->sql);
- $this->session->set('actionForm', $query->form);
- }
- if($this->session->actionQuery == false) $this->session->set('actionQuery', ' 1 = 1');
-
- $allProduct = "`product` = 'all'";
- $allProject = "`project` = 'all'";
- $actionQuery = $this->session->actionQuery;
-
- /* If the sql not include 'product', add check purview for product. */
- if(strpos($actionQuery, $allProduct) === false)
- {
- $actionQuery = $actionQuery . 'AND `product`' . helper::dbIN(array_keys($products));
- }
- else
- {
- $actionQuery = str_replace($allProduct, '1', $actionQuery);
- }
-
- /* If the sql not include 'project', add check purview for project. */
- if(strpos($actionQuery, $allProject) === false)
- {
- $actionQuery = $actionQuery . 'AND `project`' . helper::dbIN(array_keys($projects));
- }
- else
- {
- $actionQuery = str_replace($allProduct, '1', $actionQuery);
- }
-
- $actions = $this->getBySQL($actionQuery, $orderBy, $pager);
- if(!$actions) return array();
- return $this->transformActions($actions);
- }
-
- /**
- * Get actions by SQL.
- *
- * @param string $sql
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getBySQL($sql, $orderBy, $pager = null)
- {
- return $actions = $this->dao->select('*')->from(TABLE_ACTION)
- ->where($sql)
- ->orderBy($orderBy)
- ->page($pager)
- ->fetchAll();
- }
-
- /**
- * Transform the actions for display.
- *
- * @param int $actions
- * @access public
- * @return void
- */
- public function transformActions($actions)
- {
- /* Get commiters. */
- $commiters = $this->loadModel('user')->getCommiters();
-
- /* Group actions by objectType, and get there name field. */
- foreach($actions as $object) $objectTypes[$object->objectType][] = $object->objectID;
- foreach($objectTypes as $objectType => $objectIds)
- {
- if(!isset($this->config->action->objectTables[$objectType])) continue; // If no defination for this type, omit it.
-
- $objectIds = array_unique($objectIds);
- $table = $this->config->action->objectTables[$objectType];
- $field = $this->config->action->objectNameFields[$objectType];
- if($table != '`zt_todo`')
- {
- $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs();
- }
- else
- {
- $todos = $this->dao->select("id, $field AS name, account, private")->from($table)->where('id')->in($objectIds)->fetchAll('id');
- foreach($todos as $id => $todo)
- {
- if($todo->private == 1 and $todo->account != $this->app->user->account)
- {
- $objectNames[$objectType][$id] = $this->lang->todo->thisIsPrivate;
- }
- else
- {
- $objectNames[$objectType][$id] = $todo->name;
- }
- }
- }
- }
- $objectNames['user'][0] = 'guest'; // Add guest account.
-
- foreach($actions as $action)
- {
- /* Add name field to the actions. */
- $action->objectName = isset($objectNames[$action->objectType][$action->objectID]) ? $objectNames[$action->objectType][$action->objectID] : '';
-
- $actionType = strtolower($action->action);
- $objectType = strtolower($action->objectType);
- $action->date = date(DT_MONTHTIME2, strtotime($action->date));
- $action->actionLabel = isset($this->lang->action->label->$actionType) ? $this->lang->action->label->$actionType : $action->action;
- $action->objectLabel = isset($this->lang->action->label->$objectType) ? $this->lang->action->label->$objectType : $objectType;
-
- /* If action type is login or logout, needn't link. */
- if($actionType == 'login' or $actionType == 'logout')
- {
- $action->objectLink = '';
- $action->objectLabel = '';
- continue;
- }
- elseif($actionType == 'svncommited')
- {
- $action->actor = isset($commiters[$action->actor]) ? $commiters[$action->actor] : $action->actor;
- }
-
- /* Other actions, create a link. */
- if(strpos($action->objectLabel, '|') !== false)
- {
- list($objectLabel, $moduleName, $methodName, $vars) = explode('|', $action->objectLabel);
- $action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID));
- $action->objectLabel = $objectLabel;
- }
- else
- {
- $action->objectLink = '';
- }
- }
- return $actions;
- }
-
- /**
- * Compute the begin date and end date of a period.
- *
- * @param string $period
- * @access private
- * @return array
- */
- private function computeBeginAndEnd($period)
- {
- $this->loadModel('todo');
-
- $today = $this->todo->today();
- $tomorrow = $this->todo->tomorrow();
- $yesterday = $this->todo->yesterday();
- $twoDaysAgo = $this->todo->twoDaysAgo();
-
- if($period == 'all') return array('begin' => '1970-1-1', 'end' => '2109-1-1');
- if($period == 'today') return array('begin' => $today, 'end' => $tomorrow);
- if($period == 'yesterday') return array('begin' => $yesterday, 'end' => $today);
- if($period == 'twodaysago') return array('begin' => $twoDaysAgo, 'end' => $yesterday);
-
- /* If the period is by week, add the end time to the end date. */
- if($period == 'thisweek' or $period == 'lastweek')
- {
- $func = "get$period";
- extract($this->todo->$func());
- return array('begin' => $begin, 'end' => $end . ' 23:59:59');
- }
-
- if($period == 'thismonth') return $this->todo->getThisMonth();
- if($period == 'lastmonth') return $this->todo->getLastMonth();
- }
-
- /**
- * Print changes of every action.
- *
- * @param string $objectType
- * @param array $histories
- * @access public
- * @return void
- */
- public function printChanges($objectType, $histories)
- {
- if(empty($histories)) return;
-
- $maxLength = 0; // The max length of fields names.
- $historiesWithDiff = array(); // To save histories without diff info.
- $historiesWithoutDiff = array(); // To save histories with diff info.
-
- /* Diff histories by hasing diff info or not. Thus we can to make sure the field with diff show at last. */
- foreach($histories as $history)
- {
- $fieldName = $history->field;
- $history->fieldLabel = isset($this->lang->$objectType->$fieldName) ? $this->lang->$objectType->$fieldName : $fieldName;
- if(($length = strlen($history->fieldLabel)) > $maxLength) $maxLength = $length;
- $history->diff ? $historiesWithDiff[] = $history : $historiesWithoutDiff[] = $history;
- }
- $histories = array_merge($historiesWithoutDiff, $historiesWithDiff);
-
- foreach($histories as $history)
- {
- $history->fieldLabel = str_pad($history->fieldLabel, $maxLength, $this->lang->action->label->space);
- if($history->diff != '')
- {
- $history->diff = str_replace(array('', ' ', '', ''), array('[ins]', '[/ins]', '[del]', '[/del]'), $history->diff);
- $history->diff = $history->field != 'subversion' ? htmlspecialchars($history->diff) : $history->diff; // Keep the diff link.
- $history->diff = str_replace(array('[ins]', '[/ins]', '[del]', '[/del]'), array('', ' ', '', ''), $history->diff);
- $history->diff = nl2br($history->diff);
- printf($this->lang->action->desc->diff2, $history->fieldLabel, $history->diff);
- }
- else
- {
- printf($this->lang->action->desc->diff1, $history->fieldLabel, $history->old, $history->new);
- }
- }
- }
-}
+
+ * @package action
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+objectType = strtolower($objectType);
+ $action->objectID = $objectID;
+ $action->actor = $this->app->user->account;
+ $action->action = strtolower($actionType);
+ $action->date = helper::now();
+ $action->comment = htmlspecialchars($comment);
+ $action->extra = $extra;
+
+ /* Get product and project for this object. */
+ $productAndProject = $this->getProductAndProject($objectType, $objectID);
+ $action->product = $productAndProject['product'];
+ $action->project = $productAndProject['project'];
+
+ $this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec();
+ return $this->dbh->lastInsertID();
+ }
+
+ /**
+ * Get product and project of an object.
+ *
+ * @param string $objectType
+ * @param int $objectID
+ * @access public
+ * @return array
+ */
+ public function getProductAndProject($objectType, $objectID)
+ {
+ $objectType = strtolower($objectType);
+ $emptyRecord = array('product' => 0, 'project' => 0);
+
+ /* If objectType is product or project, return the objectID. */
+ if($objectType == 'product') return array('product' => $objectID, 'project' => 0);
+ if($objectType == 'project') return array('project' => $objectID, 'product' => 0);
+
+ /* Only process these object types. */
+ if(strpos('story, productplan, release, task, build. bug, case, testtask, doc', $objectType) !== false)
+ {
+ if(!isset($this->config->action->objectTables[$objectType])) return $emptyRecord;
+
+ /* Set fields to fetch. */
+ if(strpos('story, productplan, case', $objectType) !== false) $fields = 'product';
+ if(strpos('build, bug, testtask, doc', $objectType) !== false) $fields = 'product, project';
+ if($objectType == 'release') $fields = 'product, build';
+ if($objectType == 'task') $fields = 'project, story';
+
+ $record = $this->dao->select($fields)->from($this->config->action->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
+
+ /* Process story, release and task. */
+ if($objectType == 'story') $record->project = $this->dao->select('project')->from(TABLE_PROJECTSTORY)->where('story')->eq($objectID)->fetch('project');
+ if($objectType == 'release') $record->project = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($record->build)->fetch('project');
+ if($objectType == 'task') $record->product = $this->dao->select('product')->from(TABLE_STORY)->where('id')->eq($record->story)->fetch('product');
+
+ if($record)
+ {
+ $record = (array)$record;
+ if(!isset($record['product'])) $record['product'] = 0;
+ if(!isset($record['project'])) $record['project'] = 0;
+ return $record;
+ }
+
+ return $emptyRecord;
+ }
+ return $emptyRecord;
+ }
+
+ /**
+ * Get actions of an object.
+ *
+ * @param int $objectType
+ * @param int $objectID
+ * @access public
+ * @return array
+ */
+ public function getList($objectType, $objectID)
+ {
+ $commiters = $this->loadModel('user')->getCommiters();
+ $actions = $this->dao->select('*')->from(TABLE_ACTION)
+ ->where('objectType')->eq($objectType)
+ ->andWhere('objectID')->eq($objectID)
+ ->orderBy('date, id')->fetchAll('id');
+ $histories = $this->getHistory(array_keys($actions));
+ foreach($actions as $actionID => $action)
+ {
+ if(strtolower($action->action) == 'svncommited' and isset($commiters[$action->actor])) $action->actor = $commiters[$action->actor];
+ $action->history = isset($histories[$actionID]) ? $histories[$actionID] : array();
+ $actions[$actionID] = $action;
+ }
+ return $actions;
+ }
+
+ /**
+ * Get an action record.
+ *
+ * @param int $actionID
+ * @access public
+ * @return object
+ */
+ public function getById($actionID)
+ {
+ return $this->dao->findById((int)$actionID)->from(TABLE_ACTION)->fetch();
+ }
+
+ /**
+ * Get deleted objects.
+ *
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getTrashes($orderBy, $pager)
+ {
+ $trashes = $this->dao->select('*')->from(TABLE_ACTION)
+ ->where('action')->eq('deleted')
+ ->andWhere('extra')->eq(self::CAN_UNDELETED)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ if(!$trashes) return array();
+
+ /* Group trashes by objectType, and get there name field. */
+ foreach($trashes as $object)
+ {
+ $object->objectType = str_replace('`', '', $object->objectType);
+ $typeTrashes[$object->objectType][] = $object->objectID;
+ }
+ foreach($typeTrashes as $objectType => $objectIds)
+ {
+ $objectIds = array_unique($objectIds);
+ $table = $this->config->action->objectTables[$objectType];
+ $field = $this->config->action->objectNameFields[$objectType];
+ $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs();
+ }
+
+ /* Add name field to the trashes. */
+ foreach($trashes as $trash) $trash->objectName = $objectNames[$trash->objectType][$trash->objectID];
+ return $trashes;
+ }
+
+ /**
+ * Get histories of an action.
+ *
+ * @param int $actionID
+ * @access public
+ * @return array
+ */
+ public function getHistory($actionID)
+ {
+ return $this->dao->select()->from(TABLE_HISTORY)->where('action')->in($actionID)->orderBy('id')->fetchGroup('action');
+ }
+
+ /**
+ * Log histories for an action.
+ *
+ * @param int $actionID
+ * @param array $changes
+ * @access public
+ * @return void
+ */
+ public function logHistory($actionID, $changes)
+ {
+ foreach($changes as $change)
+ {
+ $change['action'] = $actionID;
+ $this->dao->insert(TABLE_HISTORY)->data($change)->exec();
+ }
+ }
+
+ /**
+ * Print actions of an object.
+ *
+ * @param array $action
+ * @access public
+ * @return void
+ */
+ public function printAction($action)
+ {
+ $objectType = $action->objectType;
+ $actionType = strtolower($action->action);
+
+ /**
+ * Set the desc string of this action.
+ *
+ * 1. If the module of this action has defined desc of this actionType, use it.
+ * 2. If no defined in the module language, search the common action define.
+ * 3. If not found in the lang->action->desc, use the $lang->action->desc->common or $lang->action->desc->extra as the default.
+ */
+ if(isset($this->lang->$objectType->action->$actionType))
+ {
+ $desc = $this->lang->$objectType->action->$actionType;
+ }
+ elseif(isset($this->lang->action->desc->$actionType))
+ {
+ $desc = $this->lang->action->desc->$actionType;
+ }
+ else
+ {
+ $desc = $action->extra ? $this->lang->action->desc->extra : $this->lang->action->desc->common;
+ }
+
+ /* Cycle actions, replace vars. */
+ foreach($action as $key => $value)
+ {
+ if($key == 'history') continue;
+
+ /* Desc can be an array or string. */
+ if(is_array($desc))
+ {
+ if($key == 'extra') continue;
+ $desc['main'] = str_replace('$' . $key, $value, $desc['main']);
+ }
+ else
+ {
+ $desc = str_replace('$' . $key, $value, $desc);
+ }
+ }
+
+ /* If the desc is an array, process extra. Please bug/lang. */
+ if(is_array($desc))
+ {
+ $extra = strtolower($action->extra);
+ if(isset($desc['extra'][$extra]))
+ {
+ echo str_replace('$extra', $desc['extra'][$extra], $desc['main']);
+ }
+ else
+ {
+ echo str_replace('$extra', $action->extra, $desc['main']);
+ }
+ }
+ else
+ {
+ echo $desc;
+ }
+ }
+
+ /**
+ * Get actions as dynamic.
+ *
+ * @param string $objectType
+ * @param string $count
+ * @param string $period
+ * @param string $orderBy
+ * @param object $pager
+ * @param string|int $productID all|int(like 123)|notzero all => include zeror, notzero, great than 0
+ * @param string|int $projectID same as productID
+ * @access public
+ * @return array
+ */
+ public function getDynamic($account = 'all', $period = 'all', $orderBy = 'date_desc', $pager = null, $productID = 'all', $projectID = 'all')
+ {
+ /* Computer the begin and end date of a period. */
+ $period = $this->computeBeginAndEnd($period);
+ extract($period);
+
+ /* Get actions. */
+ $actions = $this->dao->select('*')->from(TABLE_ACTION)
+ ->where('date')->gt($begin)
+ ->andWhere('date')->lt($end)
+ ->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi()
+ ->beginIF(is_numeric($productID))->andWhere('product')->eq($productID)->fi()
+ ->beginIF(is_numeric($projectID))->andWhere('project')->eq($projectID)->fi()
+ ->beginIF($productID == 'notzero')->andWhere('product')->gt(0)->fi()
+ ->beginIF($projectID == 'notzero')->andWhere('project')->gt(0)->fi()
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+
+ if(!$actions) return array();
+ return $this->transformActions($actions);
+ }
+
+ /**
+ * Get dynamic by search.
+ *
+ * @param array $products
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getDynamicBySearch($products, $projects, $queryID, $orderBy = 'date_desc', $pager)
+ {
+ $query = $queryID ? $this->loadModel('search')->getQuery($queryID) : '';
+
+ /* Get the sql and form status from the query. */
+ if($query)
+ {
+ $this->session->set('actionQuery', $query->sql);
+ $this->session->set('actionForm', $query->form);
+ }
+ if($this->session->actionQuery == false) $this->session->set('actionQuery', ' 1 = 1');
+
+ $allProduct = "`product` = 'all'";
+ $allProject = "`project` = 'all'";
+ $actionQuery = $this->session->actionQuery;
+
+ /* If the sql not include 'product', add check purview for product. */
+ if(strpos($actionQuery, $allProduct) === false)
+ {
+ $actionQuery = $actionQuery . 'AND `product`' . helper::dbIN(array_keys($products));
+ }
+ else
+ {
+ $actionQuery = str_replace($allProduct, '1', $actionQuery);
+ }
+
+ /* If the sql not include 'project', add check purview for project. */
+ if(strpos($actionQuery, $allProject) === false)
+ {
+ $actionQuery = $actionQuery . 'AND `project`' . helper::dbIN(array_keys($projects));
+ }
+ else
+ {
+ $actionQuery = str_replace($allProduct, '1', $actionQuery);
+ }
+
+ $actions = $this->getBySQL($actionQuery, $orderBy, $pager);
+ if(!$actions) return array();
+ return $this->transformActions($actions);
+ }
+
+ /**
+ * Get actions by SQL.
+ *
+ * @param string $sql
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getBySQL($sql, $orderBy, $pager = null)
+ {
+ return $actions = $this->dao->select('*')->from(TABLE_ACTION)
+ ->where($sql)
+ ->orderBy($orderBy)
+ ->page($pager)
+ ->fetchAll();
+ }
+
+ /**
+ * Transform the actions for display.
+ *
+ * @param int $actions
+ * @access public
+ * @return void
+ */
+ public function transformActions($actions)
+ {
+ /* Get commiters. */
+ $commiters = $this->loadModel('user')->getCommiters();
+
+ /* Group actions by objectType, and get there name field. */
+ foreach($actions as $object) $objectTypes[$object->objectType][] = $object->objectID;
+ foreach($objectTypes as $objectType => $objectIds)
+ {
+ if(!isset($this->config->action->objectTables[$objectType])) continue; // If no defination for this type, omit it.
+
+ $objectIds = array_unique($objectIds);
+ $table = $this->config->action->objectTables[$objectType];
+ $field = $this->config->action->objectNameFields[$objectType];
+ if($table != '`zt_todo`')
+ {
+ $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs();
+ }
+ else
+ {
+ $todos = $this->dao->select("id, $field AS name, account, private")->from($table)->where('id')->in($objectIds)->fetchAll('id');
+ foreach($todos as $id => $todo)
+ {
+ if($todo->private == 1 and $todo->account != $this->app->user->account)
+ {
+ $objectNames[$objectType][$id] = $this->lang->todo->thisIsPrivate;
+ }
+ else
+ {
+ $objectNames[$objectType][$id] = $todo->name;
+ }
+ }
+ }
+ }
+ $objectNames['user'][0] = 'guest'; // Add guest account.
+
+ foreach($actions as $action)
+ {
+ /* Add name field to the actions. */
+ $action->objectName = isset($objectNames[$action->objectType][$action->objectID]) ? $objectNames[$action->objectType][$action->objectID] : '';
+
+ $actionType = strtolower($action->action);
+ $objectType = strtolower($action->objectType);
+ $action->date = date(DT_MONTHTIME2, strtotime($action->date));
+ $action->actionLabel = isset($this->lang->action->label->$actionType) ? $this->lang->action->label->$actionType : $action->action;
+ $action->objectLabel = isset($this->lang->action->label->$objectType) ? $this->lang->action->label->$objectType : $objectType;
+
+ /* If action type is login or logout, needn't link. */
+ if($actionType == 'login' or $actionType == 'logout')
+ {
+ $action->objectLink = '';
+ $action->objectLabel = '';
+ continue;
+ }
+ elseif($actionType == 'svncommited')
+ {
+ $action->actor = isset($commiters[$action->actor]) ? $commiters[$action->actor] : $action->actor;
+ }
+
+ /* Other actions, create a link. */
+ if(strpos($action->objectLabel, '|') !== false)
+ {
+ list($objectLabel, $moduleName, $methodName, $vars) = explode('|', $action->objectLabel);
+ $action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID));
+ $action->objectLabel = $objectLabel;
+ }
+ else
+ {
+ $action->objectLink = '';
+ }
+ }
+ return $actions;
+ }
+
+ /**
+ * Compute the begin date and end date of a period.
+ *
+ * @param string $period
+ * @access private
+ * @return array
+ */
+ private function computeBeginAndEnd($period)
+ {
+ $this->loadModel('todo');
+
+ $today = $this->todo->today();
+ $tomorrow = $this->todo->tomorrow();
+ $yesterday = $this->todo->yesterday();
+ $twoDaysAgo = $this->todo->twoDaysAgo();
+
+ if($period == 'all') return array('begin' => '1970-1-1', 'end' => '2109-1-1');
+ if($period == 'today') return array('begin' => $today, 'end' => $tomorrow);
+ if($period == 'yesterday') return array('begin' => $yesterday, 'end' => $today);
+ if($period == 'twodaysago') return array('begin' => $twoDaysAgo, 'end' => $yesterday);
+
+ /* If the period is by week, add the end time to the end date. */
+ if($period == 'thisweek' or $period == 'lastweek')
+ {
+ $func = "get$period";
+ extract($this->todo->$func());
+ return array('begin' => $begin, 'end' => $end . ' 23:59:59');
+ }
+
+ if($period == 'thismonth') return $this->todo->getThisMonth();
+ if($period == 'lastmonth') return $this->todo->getLastMonth();
+ }
+
+ /**
+ * Print changes of every action.
+ *
+ * @param string $objectType
+ * @param array $histories
+ * @access public
+ * @return void
+ */
+ public function printChanges($objectType, $histories)
+ {
+ if(empty($histories)) return;
+
+ $maxLength = 0; // The max length of fields names.
+ $historiesWithDiff = array(); // To save histories without diff info.
+ $historiesWithoutDiff = array(); // To save histories with diff info.
+
+ /* Diff histories by hasing diff info or not. Thus we can to make sure the field with diff show at last. */
+ foreach($histories as $history)
+ {
+ $fieldName = $history->field;
+ $history->fieldLabel = isset($this->lang->$objectType->$fieldName) ? $this->lang->$objectType->$fieldName : $fieldName;
+ if(($length = strlen($history->fieldLabel)) > $maxLength) $maxLength = $length;
+ $history->diff ? $historiesWithDiff[] = $history : $historiesWithoutDiff[] = $history;
+ }
+ $histories = array_merge($historiesWithoutDiff, $historiesWithDiff);
+
+ foreach($histories as $history)
+ {
+ $history->fieldLabel = str_pad($history->fieldLabel, $maxLength, $this->lang->action->label->space);
+ if($history->diff != '')
+ {
+ $history->diff = str_replace(array('', ' ', '', ''), array('[ins]', '[/ins]', '[del]', '[/del]'), $history->diff);
+ $history->diff = $history->field != 'subversion' ? htmlspecialchars($history->diff) : $history->diff; // Keep the diff link.
+ $history->diff = str_replace(array('[ins]', '[/ins]', '[del]', '[/del]'), array('', ' ', '', ''), $history->diff);
+ $history->diff = nl2br($history->diff);
+ printf($this->lang->action->desc->diff2, $history->fieldLabel, $history->diff);
+ }
+ else
+ {
+ printf($this->lang->action->desc->diff1, $history->fieldLabel, $history->old, $history->new);
+ }
+ }
+ }
+}
diff --git a/module/action/view/trash.html.php b/module/action/view/trash.html.php
index 39062d7c56..6c83be7bb2 100644
--- a/module/action/view/trash.html.php
+++ b/module/action/view/trash.html.php
@@ -1,49 +1,49 @@
-
- * @package action
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
- recTotal}&recPerPage={$pager->recPerPage}"; ?>
-
-
- action->objectType);?>
- idAB);?>
- action->objectName;?>
- action->actor);?>
- action->date);?>
- actions;?>
-
-
-
-
- objectType == 'case' ? 'testcase' : $action->objectType;?>
-
- action->objectTypes[$action->objectType];?>
- objectID;?>
- createLink($module, 'view', "id=$action->objectID"), $action->objectName);?>
- actor];?>
- date;?>
- id", $lang->action->undelete, 'hiddenwin');?>
-
-
-
-
-
-
- action->trashTips;?>
- show();?>
-
-
-
-
-
+
+ * @package action
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+ recTotal}&recPerPage={$pager->recPerPage}"; ?>
+
+
+ action->objectType);?>
+ idAB);?>
+ action->objectName;?>
+ action->actor);?>
+ action->date);?>
+ actions;?>
+
+
+
+
+ objectType == 'case' ? 'testcase' : $action->objectType;?>
+
+ action->objectTypes[$action->objectType];?>
+ objectID;?>
+ createLink($module, 'view', "id=$action->objectID"), $action->objectName);?>
+ actor];?>
+ date;?>
+ id", $lang->action->undelete, 'hiddenwin');?>
+
+
+
+
+
+
+ action->trashTips;?>
+ show();?>
+
+
+
+
+
diff --git a/module/admin/control.php b/module/admin/control.php
index bb10409ffe..d4529055df 100644
--- a/module/admin/control.php
+++ b/module/admin/control.php
@@ -1,24 +1,24 @@
-
- * @package admin
- * @version $Id$
- * @link http://www.zentao.net
- */
-class admin extends control
-{
- /**
- * Index page of admin module. Locate to action's trash page.
- *
- * @access public
- * @return void
- */
- public function index()
- {
- $this->locate($this->createLink('extension', 'browse'));
- }
-}
+
+ * @package admin
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class admin extends control
+{
+ /**
+ * Index page of admin module. Locate to action's trash page.
+ *
+ * @access public
+ * @return void
+ */
+ public function index()
+ {
+ $this->locate($this->createLink('extension', 'browse'));
+ }
+}
diff --git a/module/admin/lang/en.php b/module/admin/lang/en.php
index cc8c107ef8..c7f856321e 100644
--- a/module/admin/lang/en.php
+++ b/module/admin/lang/en.php
@@ -1,19 +1,19 @@
-
- * @package admin
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->admin->common = 'Admin';
-$lang->admin->index = 'Index';
-$lang->admin->company = 'Company';
-$lang->admin->user = 'User';
-$lang->admin->group = 'Group';
-$lang->admin->welcome = 'Welcome to ZenTaoPMS.';
-
-$lang->admin->browseCompany = 'Browse Company';
+
+ * @package admin
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->admin->common = 'Admin';
+$lang->admin->index = 'Index';
+$lang->admin->company = 'Company';
+$lang->admin->user = 'User';
+$lang->admin->group = 'Group';
+$lang->admin->welcome = 'Welcome to ZenTaoPMS.';
+
+$lang->admin->browseCompany = 'Browse Company';
diff --git a/module/admin/lang/zh-cn.php b/module/admin/lang/zh-cn.php
index 0301a165b7..8553ce8ff5 100644
--- a/module/admin/lang/zh-cn.php
+++ b/module/admin/lang/zh-cn.php
@@ -1,19 +1,19 @@
-
- * @package admin
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->admin->common = '后台管理';
-$lang->admin->index = '后台管理首页';
-$lang->admin->company = '公司管理';
-$lang->admin->user = '用户管理';
-$lang->admin->group = '分组管理';
-$lang->admin->welcome = '欢迎使用禅道管理软件后台管理系统';
-
-$lang->admin->browseCompany = '浏览公司';
+
+ * @package admin
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->admin->common = '后台管理';
+$lang->admin->index = '后台管理首页';
+$lang->admin->company = '公司管理';
+$lang->admin->user = '用户管理';
+$lang->admin->group = '分组管理';
+$lang->admin->welcome = '欢迎使用禅道管理软件后台管理系统';
+
+$lang->admin->browseCompany = '浏览公司';
diff --git a/module/admin/lang/zh-tw.php b/module/admin/lang/zh-tw.php
index fed35d4632..2ce9241b36 100644
--- a/module/admin/lang/zh-tw.php
+++ b/module/admin/lang/zh-tw.php
@@ -1,19 +1,19 @@
-
- * @package admin
- * @version $Id: zh-tw.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $
- * @link http://www.zentao.net
- */
-$lang->admin->common = '後台管理';
-$lang->admin->index = '後台管理首頁';
-$lang->admin->company = '公司管理';
-$lang->admin->user = '用戶管理';
-$lang->admin->group = '分組管理';
-$lang->admin->welcome = '歡迎使用禪道管理軟件後台管理系統';
-
-$lang->admin->browseCompany = '瀏覽公司';
+
+ * @package admin
+ * @version $Id: zh-tw.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $
+ * @link http://www.zentao.net
+ */
+$lang->admin->common = '後台管理';
+$lang->admin->index = '後台管理首頁';
+$lang->admin->company = '公司管理';
+$lang->admin->user = '用戶管理';
+$lang->admin->group = '分組管理';
+$lang->admin->welcome = '歡迎使用禪道管理軟件後台管理系統';
+
+$lang->admin->browseCompany = '瀏覽公司';
diff --git a/module/admin/model.php b/module/admin/model.php
index a5e964baf5..330118119f 100644
--- a/module/admin/model.php
+++ b/module/admin/model.php
@@ -1,48 +1,48 @@
-
- * @package admin
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-dbh->query($sql)->fetchALL();
- }
-
- /**
- * Get state of company.
- *
- * @param int $companyID
- * @access public
- * @return void
- */
- public function getStatOfCompany($companyID)
- {
- }
-
- /**
- * Get system info.
- *
- * @access public
- * @return void
- */
- public function getStatOfSys()
- {
- }
-}
+
+ * @package admin
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+dbh->query($sql)->fetchALL();
+ }
+
+ /**
+ * Get state of company.
+ *
+ * @param int $companyID
+ * @access public
+ * @return void
+ */
+ public function getStatOfCompany($companyID)
+ {
+ }
+
+ /**
+ * Get system info.
+ *
+ * @access public
+ * @return void
+ */
+ public function getStatOfSys()
+ {
+ }
+}
diff --git a/module/admin/view/browsecompany.html.php b/module/admin/view/browsecompany.html.php
index f2c7d40182..1e41fc2eea 100644
--- a/module/admin/view/browsecompany.html.php
+++ b/module/admin/view/browsecompany.html.php
@@ -1,47 +1,47 @@
-
- * @package admin
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
- company->id;?>
- company->name;?>
- company->phone;?>
- company->fax;?>
- company->address;?>
- company->zipcode;?>
- company->website;?>
- company->backyard;?>
- company->pms;?>
- company->guest;?>
- actions;?>
-
-
-
- id;?>
- name;?>
- phone;?>
- fax;?>
- address;?>
- zipcode;?>
- website, $company->website, '_blank');?>
- backyard,$company->backyard, '_blank');?>
- pms, $company->pms, '_blank');?>
- company->guestList[(int)$company->guest];?>
-
- createLink('company', 'edit', "companyID=$company->id"), $this->lang->company->edit);?>
- createLink('company', 'delete', "companyID=$company->id"), $this->lang->company->delete, "hiddenwin");?>
-
-
-
-
-
+
+ * @package admin
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+ company->id;?>
+ company->name;?>
+ company->phone;?>
+ company->fax;?>
+ company->address;?>
+ company->zipcode;?>
+ company->website;?>
+ company->backyard;?>
+ company->pms;?>
+ company->guest;?>
+ actions;?>
+
+
+
+ id;?>
+ name;?>
+ phone;?>
+ fax;?>
+ address;?>
+ zipcode;?>
+ website, $company->website, '_blank');?>
+ backyard,$company->backyard, '_blank');?>
+ pms, $company->pms, '_blank');?>
+ company->guestList[(int)$company->guest];?>
+
+ createLink('company', 'edit', "companyID=$company->id"), $this->lang->company->edit);?>
+ createLink('company', 'delete', "companyID=$company->id"), $this->lang->company->delete, "hiddenwin");?>
+
+
+
+
+
diff --git a/module/api/control.php b/module/api/control.php
index 5508c6dbc2..278278693a 100644
--- a/module/api/control.php
+++ b/module/api/control.php
@@ -1,50 +1,50 @@
-
- * @package api
- * @version $Id$
- * @link http://www.zentao.net
- */
-class api extends control
-{
- /**
- * Return session to the client.
- *
- * @access public
- * @return void
- */
- public function getSessionID()
- {
- $this->session->set('rand', mt_rand(0, 10000));
- $this->view->sessionName = session_name();
- $this->view->sessionID = session_id();
- $this->view->rand = $this->session->rand;
- $this->display();
- }
-
- /**
- * Execute a module's model's method, return the result.
- *
- * @param string $moduleName
- * @param string $methodName
- * @param string $params param1=value1,param2=value2, don't use & to join them.
- * @access public
- * @return string
- */
- public function getModel($moduleName, $methodName, $params = '')
- {
- parse_str(str_replace(',', '&', $params), $params);
- $module = $this->loadModel($moduleName);
- $result = call_user_func_array(array(&$module, $methodName), $params);
- if(dao::isError()) die(json_encode(dao::getError()));
- $output['status'] = $result ? 'success' : 'fail';
- $output['data'] = json_encode($result);
- $output['md5'] = md5($output['data']);
- $this->output = json_encode($output);
- die($this->output);
- }
-}
+
+ * @package api
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class api extends control
+{
+ /**
+ * Return session to the client.
+ *
+ * @access public
+ * @return void
+ */
+ public function getSessionID()
+ {
+ $this->session->set('rand', mt_rand(0, 10000));
+ $this->view->sessionName = session_name();
+ $this->view->sessionID = session_id();
+ $this->view->rand = $this->session->rand;
+ $this->display();
+ }
+
+ /**
+ * Execute a module's model's method, return the result.
+ *
+ * @param string $moduleName
+ * @param string $methodName
+ * @param string $params param1=value1,param2=value2, don't use & to join them.
+ * @access public
+ * @return string
+ */
+ public function getModel($moduleName, $methodName, $params = '')
+ {
+ parse_str(str_replace(',', '&', $params), $params);
+ $module = $this->loadModel($moduleName);
+ $result = call_user_func_array(array(&$module, $methodName), $params);
+ if(dao::isError()) die(json_encode(dao::getError()));
+ $output['status'] = $result ? 'success' : 'fail';
+ $output['data'] = json_encode($result);
+ $output['md5'] = md5($output['data']);
+ $this->output = json_encode($output);
+ die($this->output);
+ }
+}
diff --git a/module/api/lang/en.php b/module/api/lang/en.php
index 99ee0d7991..59555de28f 100644
--- a/module/api/lang/en.php
+++ b/module/api/lang/en.php
@@ -1,13 +1,13 @@
-
- * @package api
- * @version $Id: English.php 824 2010-05-02 15:32:06Z wwccss $
- * @link http://www.zentao.net
- */
-$lang->api->common = 'API';
-$lang->api->getModel = 'Super Model API';
+
+ * @package api
+ * @version $Id: English.php 824 2010-05-02 15:32:06Z wwccss $
+ * @link http://www.zentao.net
+ */
+$lang->api->common = 'API';
+$lang->api->getModel = 'Super Model API';
diff --git a/module/api/lang/zh-cn.php b/module/api/lang/zh-cn.php
index c7446f2e6a..e18a454d8d 100644
--- a/module/api/lang/zh-cn.php
+++ b/module/api/lang/zh-cn.php
@@ -1,13 +1,13 @@
-
- * @package api
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->api->common = 'API接口';
-$lang->api->getModel = '超级model调用接口';
+
+ * @package api
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->api->common = 'API接口';
+$lang->api->getModel = '超级model调用接口';
diff --git a/module/api/lang/zh-tw.php b/module/api/lang/zh-tw.php
index 2a290d4d74..b75d8dae48 100644
--- a/module/api/lang/zh-tw.php
+++ b/module/api/lang/zh-tw.php
@@ -1,13 +1,13 @@
-
- * @package api
- * @version $Id: zh-tw.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $
- * @link http://www.zentao.net
- */
-$lang->api->common = 'API介面';
-$lang->api->getModel = '超級model調用介面';
+
+ * @package api
+ * @version $Id: zh-tw.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $
+ * @link http://www.zentao.net
+ */
+$lang->api->common = 'API介面';
+$lang->api->getModel = '超級model調用介面';
diff --git a/module/api/model.php b/module/api/model.php
index 3d8da69a82..6b6ff00676 100644
--- a/module/api/model.php
+++ b/module/api/model.php
@@ -1,15 +1,15 @@
-
- * @package api
- * @version $Id$
- * @link http://www.zentao.net
- */
-class apiModel extends model
-{
-}
-
+
+ * @package api
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class apiModel extends model
+{
+}
+
diff --git a/module/bug/control.php b/module/bug/control.php
index 04b431bbde..c806429ee8 100644
--- a/module/bug/control.php
+++ b/module/bug/control.php
@@ -1,947 +1,947 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-class bug extends control
-{
- private $products = array();
-
- /**
- * Construct function, load some modules auto.
- *
- * @access public
- * @return void
- */
- public function __construct()
- {
- parent::__construct();
- $this->loadModel('product');
- $this->loadModel('tree');
- $this->loadModel('user');
- $this->loadModel('action');
- $this->loadModel('story');
- $this->loadModel('task');
- $this->products = $this->product->getPairs();
- if(empty($this->products))
- {
- echo js::alert($this->lang->product->errorNoProduct);
- die(js::locate($this->createLink('product', 'create')));
- }
- $this->view->products = $this->products;
- }
-
- /**
- * The index page, locate to browse.
- *
- * @access public
- * @return void
- */
- public function index()
- {
- $this->locate($this->createLink('bug', 'browse'));
- }
-
- /**
- * Browse bugs.
- *
- * @param int $productID
- * @param string $browseType
- * @param int $param
- * @param string $orderBy
- * @param int $recTotal
- * @param int $recPerPage
- * @param int $pageID
- * @access public
- * @return void
- */
- public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1)
- {
- /* Set browseType, productID, moduleID and queryID. */
- $browseType = strtolower($browseType);
- $productID = $this->product->saveState($productID, $this->products);
- $moduleID = ($browseType == 'bymodule') ? (int)$param : 0;
- $queryID = ($browseType == 'bysearch') ? (int)$param : 0;
-
- /* Set menu and save session. */
- $this->bug->setMenu($this->products, $productID);
- $this->session->set('bugList', $this->app->getURI(true));
-
- /* Process the order by field. */
- if(!$orderBy) $orderBy = $this->cookie->qaBugOrder ? $this->cookie->qaBugOrder : 'id_desc';
- setcookie('qaBugOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot);
-
- /* Load pager. */
- $this->app->loadClass('pager', $static = true);
- $pager = pager::init($recTotal, $recPerPage, $pageID);
-
- $projects = $this->loadModel('project')->getPairs();
- $projects[0] = '';
-
- /* Get bugs. */
- $bugs = array();
- if($browseType == 'all') $bugs = $this->bug->getAllBugs($productID, $projects, $orderBy, $pager);
- elseif($browseType == "bymodule")
- {
- $childModuleIds = $this->tree->getAllChildId($moduleID);
- $bugs = $this->bug->getModuleBugs($productID, $childModuleIds, $projects, $orderBy, $pager);
- }
- elseif($browseType == 'assigntome') $bugs = $this->bug->getByAssigntome($productID, $projects, $orderBy, $pager);
- elseif($browseType == 'openedbyme') $bugs = $this->bug->getByOpenedbyme($productID, $projects, $orderBy, $pager);
- elseif($browseType == 'resolvedbyme') $bugs = $this->bug->getByResolvedbyme($productID, $projects, $orderBy, $pager);
- elseif($browseType == 'assigntonull') $bugs = $this->bug->getByAssigntonull($productID, $projects, $orderBy, $pager);
- elseif($browseType == 'unresolved') $bugs = $this->bug->getByStatus($productID, $projects, 'unresolved', $orderBy, $pager);
- elseif($browseType == 'unclosed') $bugs = $this->bug->getByStatus($productID, $projects, 'unclosed', $orderBy, $pager);
- elseif($browseType == 'longlifebugs') $bugs = $this->bug->getByLonglifebugs($productID, $projects, $orderBy, $pager);
- elseif($browseType == 'postponedbugs') $bugs = $this->bug->getByPostponedbugs($productID, $projects, $orderBy, $pager);
- elseif($browseType == 'needconfirm') $bugs = $this->bug->getByNeedconfirm($productID, $projects, $orderBy, $pager);
- elseif($browseType == 'bysearch') $bugs = $this->bug->getBySearch($productID, $projects, $queryID, $orderBy, $pager);
-
- /* Process the sql, get the conditon partion, save it to session. Thus the report page can use the same condition. */
- if($browseType != 'needconfirm')
- {
- $sql = explode('WHERE', $this->dao->get());
- $sql = explode('ORDER', $sql[1]);
- $this->session->set('bugReportCondition', $sql[0]);
- }
-
- /* Get custom fields. */
- $customFields = $this->cookie->bugFields != false ? $this->cookie->bugFields : $this->config->bug->list->defaultFields;
- $customed = !($customFields == $this->config->bug->list->defaultFields);
-
- /* If customed, get related name or titles. */
- if($customed) $bugs = $this->bug->formCustomedBugs($bugs);
-
- /* Build the search form. */
- $this->config->bug->search['actionURL'] = $this->createLink('bug', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID");
- $this->config->bug->search['queryID'] = $queryID;
- $this->config->bug->search['params']['product']['values'] = array($productID => $this->products[$productID], 'all' => $this->lang->bug->allProduct);
- $this->config->bug->search['params']['module']['values'] = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0);
- $this->config->bug->search['params']['project']['values'] = $this->product->getProjectPairs($productID);
- $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID);
- $this->config->bug->search['params']['resolvedBuild']['values'] = $this->build->getProductBuildPairs($productID);
- $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->bug->search);
-
- $users = $this->user->getPairs('noletter');
-
- $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common;
- $position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
- $position[] = $this->lang->bug->common;
-
- $this->view->header = $header;
- $this->view->position = $position;
- $this->view->productID = $productID;
- $this->view->productName = $this->products[$productID];
- $this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'bug', $startModuleID = 0, array('treeModel', 'createBugLink'));
- $this->view->browseType = $browseType;
- $this->view->bugs = $bugs;
- $this->view->users = $users;
- $this->view->pager = $pager;
- $this->view->param = $param;
- $this->view->orderBy = $orderBy;
- $this->view->moduleID = $moduleID;
- $this->view->customed = $customed;
- $this->view->customFields= explode(',', str_replace(' ', '', trim($customFields)));
- $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden';
-
- $this->display();
- }
-
- /**
- * The report page.
- *
- * @param int $productID
- * @param string $browseType
- * @param int $moduleID
- * @access public
- * @return void
- */
- public function report($productID, $browseType, $moduleID)
- {
- $this->loadModel('report');
- $this->view->charts = array();
- $this->view->renderJS = '';
-
- if(!empty($_POST))
- {
- foreach($this->post->charts as $chart)
- {
- $chartFunc = 'getDataOf' . $chart;
- $chartData = $this->bug->$chartFunc();
- $chartOption = $this->lang->bug->report->$chart;
- $this->bug->mergeChartOption($chart);
-
- $chartXML = $this->report->createSingleXML($chartData, $chartOption->graph);
- $this->view->charts[$chart] = $this->report->createJSChart($chartOption->swf, $chartXML, $chartOption->width, $chartOption->height);
- $this->view->datas[$chart] = $this->report->computePercent($chartData);
- }
- $this->view->renderJS = $this->report->renderJsCharts(count($this->view->charts));
- }
-
- $this->bug->setMenu($this->products, $productID);
- $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common;
- $this->view->productID = $productID;
- $this->view->browseType = $browseType;
- $this->view->moduleID = $moduleID;
- $this->view->checkedCharts = $this->post->charts ? join(',', $this->post->charts) : '';
- $this->display();
- }
-
- /**
- * Create a bug.
- *
- * @param int $productID
- * @param string $extras others params, forexample, projectID=10,moduleID=10
- * @access public
- * @return void
- */
- public function create($productID, $extras = '')
- {
- $this->view->users = $this->user->getPairs('nodeleted');
- if(empty($this->products)) $this->locate($this->createLink('product', 'create'));
-
- if(!empty($_POST))
- {
- $bugID = $this->bug->create();
- if(dao::isError()) die(js::error(dao::getError()));
- $actionID = $this->action->create('bug', $bugID, 'Opened');
- $this->sendmail($bugID, $actionID);
- die(js::locate($this->createLink('bug', 'browse', "productID={$this->post->product}&type=byModule¶m={$this->post->module}"), 'parent'));
- }
-
- /* Get product, then set menu. */
- $productID = $this->product->saveState($productID, $this->products);
- $this->bug->setMenu($this->products, $productID);
-
- /* Remove the unused types. */
- unset($this->lang->bug->typeList['designchange']);
- unset($this->lang->bug->typeList['newfeature']);
- unset($this->lang->bug->typeList['trackthings']);
-
- /* Init vars. */
- $moduleID = 0;
- $projectID = 0;
- $taskID = 0;
- $storyID = 0;
- $buildID = 0;
- $caseID = 0;
- $runID = 0;
- $title = '';
- $steps = $this->lang->bug->tplStep . $this->lang->bug->tplResult . $this->lang->bug->tplExpect;
- $os = '';
- $browser = '';
- $assignedTo = '';
- $mailto = '';
- $keywords = '';
- $severity = 3;
- $type = 'codeerror';
-
- /* Parse the extras. */
- $extras = str_replace(array(',', ' '), array('&', ''), $extras);
- parse_str($extras);
-
- /* If set runID, get the last result info as the template. */
- if($runID > 0) $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('run')->eq($runID)->orderBy('id desc')->limit(1)->fetch('id');
- if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID));
-
- /* If set caseID and runID='', get the last result info as the template. */
- if($caseID > 0 && $runID == '')
- {
- $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('`case`')->eq($caseID)->orderBy('date desc')->limit(1)->fetch('id');
- if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID, $caseID, $version));
- }
-
- /* If bugID setted, use this bug as template. */
- if(isset($bugID))
- {
- $bug = $this->bug->getById($bugID);
- extract((array)$bug);
- $projectID = $bug->project;
- $moduleID = $bug->module;
- $taskID = $bug->task;
- $storyID = $bug->story;
- $buildID = $bug->openedBuild;
- $severity = $bug->severity;
- $type = $bug->type;
- }
-
- /* If projectID is setted, get builds and stories of this project. */
- if($projectID)
- {
- $builds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty');
- $stories = $this->story->getProjectStoryPairs($projectID);
- }
- else
- {
- $builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty');
- $stories = $this->story->getProductStoryPairs($productID);
- }
-
- $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->create;
- $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
- $this->view->position[] = $this->lang->bug->create;
-
- $this->view->productID = $productID;
- $this->view->productName = $this->products[$productID];
- $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0);
- $this->view->stories = $stories;
- $this->view->projects = $this->product->getProjectPairs($productID, $params = 'nodeleted');
- $this->view->builds = $builds;
- $this->view->tasks = $this->loadModel('task')->getProjectTaskPairs($projectID);
- $this->view->moduleID = $moduleID;
- $this->view->projectID = $projectID;
- $this->view->taskID = $taskID;
- $this->view->storyID = $storyID;
- $this->view->buildID = $buildID;
- $this->view->caseID = $caseID;
- $this->view->title = $title;
- $this->view->steps = htmlspecialchars($steps);
- $this->view->os = $os;
- $this->view->browser = $browser;
- $this->view->assignedTo = $assignedTo;
- $this->view->mailto = $mailto;
- $this->view->keywords = $keywords;
- $this->view->severity = $severity;
- $this->view->type = $type;
-
- $this->display();
- }
-
- /**
- * View a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function view($bugID)
- {
- /* Judge bug exits or not. */
- $bug = $this->bug->getById($bugID);
- if(!$bug) die(js::error($this->lang->notFound) . js::locate('back'));
-
- /* Set menu. */
- $this->bug->setMenu($this->products, $bug->product);
-
- /* Get product info. */
- $productID = $bug->product;
- $productName = $this->products[$productID];
-
- /* Header and positon. */
- $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->view;
- $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $productName);
- $this->view->position[] = $this->lang->bug->view;
-
- /* Assign. */
- $this->view->productID = $productID;
- $this->view->productName = $productName;
- $this->view->modulePath = $this->tree->getParents($bug->module);
- $this->view->bug = $bug;
- $this->view->users = $this->user->getPairs('noletter');
- $this->view->actions = $this->action->getList('bug', $bugID);
- $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID);
-
- $this->display();
- }
-
- /**
- * Edit a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function edit($bugID, $comment = false)
- {
- if(!empty($_POST))
- {
- $changes = array();
- $files = array();
- if($comment == false)
- {
- $changes = $this->bug->update($bugID);
- if(dao::isError()) die(js::error(dao::getError()));
- $files = $this->loadModel('file')->saveUpload('bug', $bugID);
- }
- if($this->post->comment != '' or !empty($changes) or !empty($files))
- {
- $action = !empty($changes) ? 'Edited' : 'Commented';
- $fileAction = '';
- if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ;
- $actionID = $this->action->create('bug', $bugID, $action, $fileAction . $this->post->comment);
- $this->action->logHistory($actionID, $changes);
- $this->sendmail($bugID, $actionID);
- }
-
- $bug = $this->bug->getById($bugID);
- if($bug->toTask != 0)
- {
- foreach($changes as $change)
- {
- if($change['field'] == 'status')
- {
- $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask");
- $cancelURL = $this->server->HTTP_REFERER;
- die(js::confirm(sprintf($this->lang->task->remindTask, $bug->Task), $confirmURL, $cancelURL, 'parent', 'parent'));
- }
- }
- }
- die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
- }
-
- /* Get the info of bug, current product and modue. */
- $bug = $this->bug->getById($bugID);
- $productID = $bug->product;
- $projectID = $bug->project;
- $currentModuleID = $bug->module;
-
- /**
- * Remove designchange, newfeature, trackings from the typeList, because should be tracked in story or task.
- * These thress types if upgrade from bugfree2.x.
- */
- if($bug->type != 'designchange') unset($this->lang->bug->typeList['designchange']);
- if($bug->type != 'newfeature') unset($this->lang->bug->typeList['newfeature']);
- if($bug->type != 'trackthings') unset($this->lang->bug->typeList['trackthings']);
-
- /* Set the menu. */
- $this->bug->setMenu($this->products, $productID);
-
- /* Set header and position. */
- $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->edit;
- $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
- $this->view->position[] = $this->lang->bug->edit;
-
- /* Assign. */
- if($projectID)
- {
- $this->view->openedBuilds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty');
- }
- else
- {
- $this->view->openedBuilds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty');
- }
- $this->view->bug = $bug;
- $this->view->productID = $productID;
- $this->view->productName = $this->products[$productID];
- $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0);
- $this->view->currentModuleID = $currentModuleID;
- $this->view->projects = $this->product->getProjectPairs($bug->product);
- $this->view->stories = $bug->project ? $this->story->getProjectStoryPairs($bug->project) : $this->story->getProductStoryPairs($bug->product);
- $this->view->tasks = $this->task->getProjectTaskPairs($bug->project);
- $this->view->users = $this->user->appendDeleted($this->user->getPairs('nodeleted'), "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy");
- $this->view->resolvedBuilds = array('' => '') + $this->view->openedBuilds;
- $this->view->actions = $this->action->getList('bug', $bugID);
- $this->view->templates = $this->bug->getUserBugTemplates($this->app->user->account);
-
- $this->display();
- }
-
- /**
- * confirm a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function confirmBug($bugID)
- {
- if(!empty($_POST))
- {
- $this->bug->confirm($bugID);
- if(dao::isError()) die(js::error(dao::getError()));
- $actionID = $this->action->create('bug', $bugID, 'bugConfirmed', $this->post->comment);
- $this->sendmail($bugID, $actionID);
- die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
- }
-
- $bug = $this->bug->getById($bugID);
- $productID = $bug->product;
- $this->bug->setMenu($this->products, $productID);
-
- $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->confirmBug;
- $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
- $this->view->position[] = $this->lang->bug->confirmBug;
-
- $this->view->bug = $bug;
- $this->view->actions = $this->action->getList('bug', $bugID);
- $this->display();
- }
-
- /**
- * Resolve a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function resolve($bugID)
- {
- $this->view->users = $this->user->getPairs('nodeleted');
-
- if(!empty($_POST))
- {
- $this->bug->resolve($bugID);
- if(dao::isError()) die(js::error(dao::getError()));
- $actionID = $this->action->create('bug', $bugID, 'Resolved', $this->post->comment, $this->post->resolution);
- $this->sendmail($bugID, $actionID);
-
- $bug = $this->bug->getById($bugID);
- if($bug->toTask != 0)
- {
- $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask");
- $cancelURL = $this->createLink('bug', 'view', "bugID=$bugID");
- die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->toTask), $confirmURL, $cancelURL, 'parent', 'parent'));
- }
- die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
- }
-
- $bug = $this->bug->getById($bugID);
- $productID = $bug->product;
- $this->bug->setMenu($this->products, $productID);
-
- $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve;
- $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
- $this->view->position[] = $this->lang->bug->resolve;
-
- $this->view->bug = $bug;
- $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID);
- $this->view->actions = $this->action->getList('bug', $bugID);
- $this->display();
- }
-
- /**
- * Activate a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function activate($bugID)
- {
- $this->view->users = $this->user->getPairs('nodeleted');
-
- if(!empty($_POST))
- {
- $this->bug->activate($bugID);
- if(dao::isError()) die(js::error(dao::getError()));
- $files = $this->loadModel('file')->saveUpload('bug', $bugID);
- $actionID = $this->action->create('bug', $bugID, 'Activated', $this->post->comment);
- $this->sendmail($bugID, $actionID);
- die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
- }
-
- $bug = $this->bug->getById($bugID);
- $productID = $bug->product;
- $this->bug->setMenu($this->products, $productID);
-
- $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->activate;
- $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
- $this->view->position[] = $this->lang->bug->activate;
-
- $this->view->bug = $bug;
- $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty');
- $this->view->actions = $this->action->getList('bug', $bugID);
-
- $this->display();
- }
-
- /**
- * Close a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function close($bugID)
- {
- $this->view->users = $this->user->getPairs('noletter');
- if(!empty($_POST))
- {
- $this->bug->close($bugID);
- if(dao::isError()) die(js::error(dao::getError()));
- $actionID = $this->action->create('bug', $bugID, 'Closed', $this->post->comment);
- $this->sendmail($bugID, $actionID);
- die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
- }
-
- $bug = $this->bug->getById($bugID);
- $productID = $bug->product;
- $this->bug->setMenu($this->products, $productID);
-
- $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->close;
- $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
- $this->view->position[] = $this->lang->bug->close;
-
- $this->view->bug = $bug;
- $this->view->actions = $this->action->getList('bug', $bugID);
- $this->display();
- }
-
- /**
- * Confirm story change.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function confirmStoryChange($bugID)
- {
- $bug = $this->bug->getById($bugID);
- $this->dao->update(TABLE_BUG)->set('storyVersion')->eq($bug->latestStoryVersion)->where('id')->eq($bugID)->exec();
- $this->loadModel('action')->create('bug', $bugID, 'confirmed', '', $bug->latestStoryVersion);
- die(js::reload('parent'));
- }
-
- /**
- * Delete a bug.
- *
- * @param int $bugID
- * @param string $confirm yes|no
- * @access public
- * @return void
- */
- public function delete($bugID, $confirm = 'no')
- {
- $bug = $this->bug->getById($bugID);
- if($confirm == 'no')
- {
- die(js::confirm($this->lang->bug->confirmDelete, inlink('delete', "bugID=$bugID&confirm=yes")));
- }
- else
- {
- $this->bug->delete(TABLE_BUG, $bugID);
- if($bug->toTask != 0) echo js::alert($this->lang->bug->remindTask . $bug->toTask);
- die(js::locate($this->session->bugList, 'parent'));
- }
- }
-
- /**
- * Save current template.
- *
- * @access public
- * @return string
- */
- public function saveTemplate()
- {
- $this->bug->saveUserBugTemplate();
- if(dao::isError()) die(js::error(dao::getError()));
- die($this->fetch('bug', 'buildTemplates'));
- }
-
- /**
- * Build the user templates selection code.
- *
- * @access public
- * @return void
- */
- public function buildTemplates()
- {
- $this->view->templates = $this->bug->getUserBugTemplates($this->app->user->account);
- $this->display('bug', 'buildTemplates');
- }
-
- /**
- * Delete a user template.
- *
- * @param int $templateID
- * @access public
- * @return void
- */
- public function deleteTemplate($templateID)
- {
- $this->dao->delete()->from(TABLE_USERTPL)->where('id')->eq($templateID)->andWhere('account')->eq($this->app->user->account)->exec();
- die();
- }
-
- /**
- * Custom fields.
- *
- * @access public
- * @return void
- */
- public function customFields()
- {
- if($_POST)
- {
- $customFields = $this->post->customFields;
- $customFields = join(',', $customFields);
- setcookie('bugFields', $customFields, $this->config->cookieLife, $this->config->webRoot);
- die(js::reload('parent'));
- }
-
- $customFields = $this->cookie->bugFields ? $this->cookie->bugFields : $this->config->bug->list->defaultFields;
-
- $this->view->allFields = $this->bug->getFieldPairs($this->config->bug->list->allFields);
- $this->view->customFields = $this->bug->getFieldPairs($customFields);
- $this->view->defaultFields = $this->bug->getFieldPairs($this->config->bug->list->defaultFields);
- die($this->display());
- }
-
- /**
- * AJAX: get bugs of a user in html select.
- *
- * @param string $account
- * @access public
- * @return string
- */
- public function ajaxGetUserBugs($account = '')
- {
- if($account == '') $account = $this->app->user->account;
- $bugs = $this->bug->getUserBugPairs($account);
- die(html::select('bug', $bugs, '', 'class=select-1'));
- }
-
- /**
- * AJAX: Get bug owner of a module.
- *
- * @param int $moduleID
- * @param int $productID
- * @access public
- * @return string
- */
- public function ajaxGetModuleOwner($moduleID, $productID = 0)
- {
- $owner = '';
- if($moduleID) $owner = $this->dao->findByID($moduleID)->from(TABLE_MODULE)->fetch('owner');
- if(!$owner) $owner = $this->dao->findByID($productID)->from(TABLE_PRODUCT)->fetch('QM');
- die($owner);
- }
-
- /**
- * Send email.
- *
- * @param int $bugID
- * @param int $actionID
- * @access private
- * @return void
- */
- private function sendmail($bugID, $actionID)
- {
- /* Set toList and ccList. */
- $bug = $this->bug->getByID($bugID);
- $productName = $this->products[$bug->product];
- $toList = $bug->assignedTo;
- $ccList = trim($bug->mailto, ',');
- if($toList == '')
- {
- if($ccList == '') return;
- if(strpos($ccList, ',') === false)
- {
- $toList = $ccList;
- $ccList = '';
- }
- else
- {
- $commaPos = strpos($ccList, ',');
- $toList = substr($ccList, 0, $commaPos);
- $ccList = substr($ccList, $commaPos + 1);
- }
- }
- elseif(strtolower($toList) == 'closed')
- {
- $toList = $bug->resolvedBy;
- }
-
- /* Get action info. */
- $action = $this->action->getById($actionID);
- $history = $this->action->getHistory($actionID);
- $action->history = isset($history[$actionID]) ? $history[$actionID] : array();
- if(strtolower($action->action) == 'opened') $action->comment = $bug->steps;
-
- /* Create the mail content. */
- $this->view->bug = $bug;
- $this->view->action = $action;
- $mailContent = $this->parse($this->moduleName, 'sendmail');
-
- /* Send it. */
- $this->loadModel('mail')->send($toList, $productName . ':' . 'BUG #'. $bug->id . $this->lang->colon . $bug->title, $mailContent, $ccList);
- if($this->mail->isError()) echo js::error($this->mail->getError());
- }
-
- /**
- * Get data to export
- *
- * @param string $productID
- * @param string $orderBy
- * @access public
- * @return void
- */
- public function export($productID, $orderBy)
- {
- if($_POST)
- {
- $bugLang = $this->lang->bug;
- $bugConfig = $this->config->bug;
-
- /* Create field lists. */
- $fields = explode(',', $bugConfig->list->exportFields);
- foreach($fields as $key => $fieldName)
- {
- $fieldName = trim($fieldName);
- $fields[$fieldName] = isset($bugLang->$fieldName) ? $bugLang->$fieldName : $fieldName;
- unset($fields[$key]);
- }
-
- /* Get bugs. */
- $bugs = $this->dao->select('*')->from(TABLE_BUG)->alias('t1')->where($this->session->bugReportCondition)->orderBy($orderBy)->fetchAll('id');
-
- /* Get users, products and projects. */
- $users = $this->loadModel('user')->getPairs('noletter');
- $products = $this->loadModel('product')->getPairs();
- $projects = $this->loadModel('project')->getPairs('all');
-
- /* Get related objects id lists. */
- $relatedModuleIdList = array();
- $relatedStoryIdList = array();
- $relatedTaskIdList = array();
- $relatedBugIdList = array();
- $relatedCaseIdList = array();
- $relatedBuildIdList = array();
-
- foreach($bugs as $bug)
- {
- $relatedModuleIdList[$bug->module] = $bug->module;
- $relatedStoryIdList[$bug->story] = $bug->story;
- $relatedTaskIdList[$bug->task] = $bug->task;
- $relatedCaseIdList[$bug->case] = $bug->case;
- $relatedBugIdList[$bug->duplicateBug] = $bug->duplicateBug;
-
- /* Process link bugs. */
- $linkBugs = explode(',', $bug->linkBug);
- foreach($linkBugs as $linkBugID)
- {
- if($linkBugID) $relatedBugIdList[$linkBugID] = trim($linkBugID);
- }
-
- /* Process builds. */
- $builds = $bug->openedBuild . ',' . $bug->resolvedBuild;
- $builds = explode(',', $builds);
- foreach($builds as $buildID)
- {
- if($buildID) $relatedBuildIdList[$buildID] = trim($buildID);
- }
- }
-
- /* Get related objects title or names. */
- $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs();
- $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs();
- $relatedTasks = $this->dao->select('id, name')->from(TABLE_TASK)->where('id')->in($relatedTaskIdList)->fetchPairs();
- $relatedBugs = $this->dao->select('id, title')->from(TABLE_BUG)->where('id')->in($relatedBugIdList)->fetchPairs();
- $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs();
- $relatedBuilds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('id')->in($relatedBuildIdList)->fetchPairs();
- $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('bug')->andWhere('objectID')->in(@array_keys($bugs))->fetchGroup('objectID');
-
- foreach($bugs as $bug)
- {
- if($this->post->fileType == 'csv')
- {
- $bug->steps = htmlspecialchars_decode($bug->steps);
- $bug->steps = str_replace(" ", "\n", $bug->steps);
- $bug->steps = str_replace('"', '""', $bug->steps);
- $bug->steps = str_replace(' ', ' ', $bug->steps);
- $bug->steps = strip_tags($bug->steps);
- }
-
- /* fill some field with useful value. */
- if(isset($products[$bug->product])) $bug->product = $products[$bug->product];
- if(isset($projects[$bug->project])) $bug->project = $projects[$bug->project];
- if(isset($relatedModules[$bug->module])) $bug->module = $relatedModules[$bug->module];
- if(isset($relatedStories[$bug->story])) $bug->story = $relatedStories[$bug->story];
- if(isset($relatedTasks[$bug->task])) $bug->task = $relatedTasks[$bug->task];
- if(isset($relatedBugs[$bug->duplicateBug])) $bug->duplicateBug = $relatedBugs[$bug->duplicateBug];
- if(isset($relatedCases[$bug->case])) $bug->case = $relatedCases[$bug->case];
-
- if(isset($bugLang->priList[$bug->pri])) $bug->pri = $bugLang->priList[$bug->pri];
- if(isset($bugLang->typeList[$bug->type])) $bug->type = $bugLang->typeList[$bug->type];
- if(isset($bugLang->statusList[$bug->status])) $bug->status = $bugLang->statusList[$bug->status];
- if(isset($bugLang->confirmedList[$bug->confirmed])) $bug->confirmed = $bugLang->confirmedList[$bug->confirmed];
- 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->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];
-
- $bug->openedDate = substr($bug->openedDate, 0, 10);
- $bug->assignedDate = substr($bug->assignedDate, 0, 10);
- $bug->closedDate = substr($bug->closedDate, 0, 10);
- $bug->resolvedDate = substr($bug->resolvedDate, 0, 10);
- $bug->lastEditedDate = substr($bug->lastEditedDate, 0, 10);
-
- if($bug->linkBug)
- {
- $tmpLinkBugs = array();
- $linkBugIdList = explode(',', $bug->linkBug);
- foreach($linkBugIdList as $linkBugID)
- {
- $linkBugID = trim($linkBugID);
- $tmpLinkBugs[] = isset($relatedBugs[$linkBugID]) ? $relatedBugs[$linkBugID] : $linkBugID;
- }
- $bug->linkBug = join("; \n", $tmpLinkBugs);
- }
-
- if($bug->openedBuild)
- {
- $tmpOpenedBuilds = array();
- $tmpResolvedBuilds = array();
- $buildIdList = explode(',', $bug->openedBuild);
- foreach($buildIdList as $buildID)
- {
- $buildID = trim($buildID);
- $tmpOpenedBuilds[] = isset($relatedBuilds[$buildID]) ? $relatedBuilds[$buildID] : $buildID;
- }
- $bug->openedBuild = join("; \n", $tmpOpenedBuilds);
- }
-
- if($bug->resolvedBuild)
- {
- $buildIdList = explode(',', $bug->resolvedBuild);
- foreach($buildIdList as $buildID)
- {
- $buildID = trim($buildID);
- $tmpResolvedBuilds[] = isset($relatedBuilds[$buildID]) ? $relatedBuilds[$buildID] : $buildID;
- }
- $bug->resolvedBuild = join("; \n", $tmpResolvedBuilds);
- }
-
- /* Set related files. */
- if(isset($relatedFiles[$bug->id]))
- {
- foreach($relatedFiles[$bug->id] as $file)
- {
- $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/$bug->company/" . $file->pathname;
- $bug->files .= html::a($fileURL, $file->title, '_blank') . ' ';
- }
- }
-
- $bug->mailto = trim(trim($bug->mailto), ',');
- $mailtos = explode(',', $bug->mailto);
- $bug->mailto = '';
- foreach($mailtos as $mailto)
- {
- $mailto = trim($mailto);
- if(isset($users[$mailto])) $bug->mailto .= $users[$mailto] . ',';
- }
-
- /* drop some field that is not needed. */
- unset($bug->company);
- unset($bug->caseVersion);
- unset($bug->result);
- unset($bug->deleted);
- }
-
- $this->post->set('fields', $fields);
- $this->post->set('rows', $bugs);
- $this->fetch('file', 'export2' . $this->post->fileType, $_POST);
- }
-
- $this->display();
- }
-}
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class bug extends control
+{
+ private $products = array();
+
+ /**
+ * Construct function, load some modules auto.
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->loadModel('product');
+ $this->loadModel('tree');
+ $this->loadModel('user');
+ $this->loadModel('action');
+ $this->loadModel('story');
+ $this->loadModel('task');
+ $this->products = $this->product->getPairs();
+ if(empty($this->products))
+ {
+ echo js::alert($this->lang->product->errorNoProduct);
+ die(js::locate($this->createLink('product', 'create')));
+ }
+ $this->view->products = $this->products;
+ }
+
+ /**
+ * The index page, locate to browse.
+ *
+ * @access public
+ * @return void
+ */
+ public function index()
+ {
+ $this->locate($this->createLink('bug', 'browse'));
+ }
+
+ /**
+ * Browse bugs.
+ *
+ * @param int $productID
+ * @param string $browseType
+ * @param int $param
+ * @param string $orderBy
+ * @param int $recTotal
+ * @param int $recPerPage
+ * @param int $pageID
+ * @access public
+ * @return void
+ */
+ public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1)
+ {
+ /* Set browseType, productID, moduleID and queryID. */
+ $browseType = strtolower($browseType);
+ $productID = $this->product->saveState($productID, $this->products);
+ $moduleID = ($browseType == 'bymodule') ? (int)$param : 0;
+ $queryID = ($browseType == 'bysearch') ? (int)$param : 0;
+
+ /* Set menu and save session. */
+ $this->bug->setMenu($this->products, $productID);
+ $this->session->set('bugList', $this->app->getURI(true));
+
+ /* Process the order by field. */
+ if(!$orderBy) $orderBy = $this->cookie->qaBugOrder ? $this->cookie->qaBugOrder : 'id_desc';
+ setcookie('qaBugOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot);
+
+ /* Load pager. */
+ $this->app->loadClass('pager', $static = true);
+ $pager = pager::init($recTotal, $recPerPage, $pageID);
+
+ $projects = $this->loadModel('project')->getPairs();
+ $projects[0] = '';
+
+ /* Get bugs. */
+ $bugs = array();
+ if($browseType == 'all') $bugs = $this->bug->getAllBugs($productID, $projects, $orderBy, $pager);
+ elseif($browseType == "bymodule")
+ {
+ $childModuleIds = $this->tree->getAllChildId($moduleID);
+ $bugs = $this->bug->getModuleBugs($productID, $childModuleIds, $projects, $orderBy, $pager);
+ }
+ elseif($browseType == 'assigntome') $bugs = $this->bug->getByAssigntome($productID, $projects, $orderBy, $pager);
+ elseif($browseType == 'openedbyme') $bugs = $this->bug->getByOpenedbyme($productID, $projects, $orderBy, $pager);
+ elseif($browseType == 'resolvedbyme') $bugs = $this->bug->getByResolvedbyme($productID, $projects, $orderBy, $pager);
+ elseif($browseType == 'assigntonull') $bugs = $this->bug->getByAssigntonull($productID, $projects, $orderBy, $pager);
+ elseif($browseType == 'unresolved') $bugs = $this->bug->getByStatus($productID, $projects, 'unresolved', $orderBy, $pager);
+ elseif($browseType == 'unclosed') $bugs = $this->bug->getByStatus($productID, $projects, 'unclosed', $orderBy, $pager);
+ elseif($browseType == 'longlifebugs') $bugs = $this->bug->getByLonglifebugs($productID, $projects, $orderBy, $pager);
+ elseif($browseType == 'postponedbugs') $bugs = $this->bug->getByPostponedbugs($productID, $projects, $orderBy, $pager);
+ elseif($browseType == 'needconfirm') $bugs = $this->bug->getByNeedconfirm($productID, $projects, $orderBy, $pager);
+ elseif($browseType == 'bysearch') $bugs = $this->bug->getBySearch($productID, $projects, $queryID, $orderBy, $pager);
+
+ /* Process the sql, get the conditon partion, save it to session. Thus the report page can use the same condition. */
+ if($browseType != 'needconfirm')
+ {
+ $sql = explode('WHERE', $this->dao->get());
+ $sql = explode('ORDER', $sql[1]);
+ $this->session->set('bugReportCondition', $sql[0]);
+ }
+
+ /* Get custom fields. */
+ $customFields = $this->cookie->bugFields != false ? $this->cookie->bugFields : $this->config->bug->list->defaultFields;
+ $customed = !($customFields == $this->config->bug->list->defaultFields);
+
+ /* If customed, get related name or titles. */
+ if($customed) $bugs = $this->bug->formCustomedBugs($bugs);
+
+ /* Build the search form. */
+ $this->config->bug->search['actionURL'] = $this->createLink('bug', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID");
+ $this->config->bug->search['queryID'] = $queryID;
+ $this->config->bug->search['params']['product']['values'] = array($productID => $this->products[$productID], 'all' => $this->lang->bug->allProduct);
+ $this->config->bug->search['params']['module']['values'] = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0);
+ $this->config->bug->search['params']['project']['values'] = $this->product->getProjectPairs($productID);
+ $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID);
+ $this->config->bug->search['params']['resolvedBuild']['values'] = $this->build->getProductBuildPairs($productID);
+ $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->bug->search);
+
+ $users = $this->user->getPairs('noletter');
+
+ $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common;
+ $position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
+ $position[] = $this->lang->bug->common;
+
+ $this->view->header = $header;
+ $this->view->position = $position;
+ $this->view->productID = $productID;
+ $this->view->productName = $this->products[$productID];
+ $this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'bug', $startModuleID = 0, array('treeModel', 'createBugLink'));
+ $this->view->browseType = $browseType;
+ $this->view->bugs = $bugs;
+ $this->view->users = $users;
+ $this->view->pager = $pager;
+ $this->view->param = $param;
+ $this->view->orderBy = $orderBy;
+ $this->view->moduleID = $moduleID;
+ $this->view->customed = $customed;
+ $this->view->customFields= explode(',', str_replace(' ', '', trim($customFields)));
+ $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden';
+
+ $this->display();
+ }
+
+ /**
+ * The report page.
+ *
+ * @param int $productID
+ * @param string $browseType
+ * @param int $moduleID
+ * @access public
+ * @return void
+ */
+ public function report($productID, $browseType, $moduleID)
+ {
+ $this->loadModel('report');
+ $this->view->charts = array();
+ $this->view->renderJS = '';
+
+ if(!empty($_POST))
+ {
+ foreach($this->post->charts as $chart)
+ {
+ $chartFunc = 'getDataOf' . $chart;
+ $chartData = $this->bug->$chartFunc();
+ $chartOption = $this->lang->bug->report->$chart;
+ $this->bug->mergeChartOption($chart);
+
+ $chartXML = $this->report->createSingleXML($chartData, $chartOption->graph);
+ $this->view->charts[$chart] = $this->report->createJSChart($chartOption->swf, $chartXML, $chartOption->width, $chartOption->height);
+ $this->view->datas[$chart] = $this->report->computePercent($chartData);
+ }
+ $this->view->renderJS = $this->report->renderJsCharts(count($this->view->charts));
+ }
+
+ $this->bug->setMenu($this->products, $productID);
+ $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common;
+ $this->view->productID = $productID;
+ $this->view->browseType = $browseType;
+ $this->view->moduleID = $moduleID;
+ $this->view->checkedCharts = $this->post->charts ? join(',', $this->post->charts) : '';
+ $this->display();
+ }
+
+ /**
+ * Create a bug.
+ *
+ * @param int $productID
+ * @param string $extras others params, forexample, projectID=10,moduleID=10
+ * @access public
+ * @return void
+ */
+ public function create($productID, $extras = '')
+ {
+ $this->view->users = $this->user->getPairs('nodeleted');
+ if(empty($this->products)) $this->locate($this->createLink('product', 'create'));
+
+ if(!empty($_POST))
+ {
+ $bugID = $this->bug->create();
+ if(dao::isError()) die(js::error(dao::getError()));
+ $actionID = $this->action->create('bug', $bugID, 'Opened');
+ $this->sendmail($bugID, $actionID);
+ die(js::locate($this->createLink('bug', 'browse', "productID={$this->post->product}&type=byModule¶m={$this->post->module}"), 'parent'));
+ }
+
+ /* Get product, then set menu. */
+ $productID = $this->product->saveState($productID, $this->products);
+ $this->bug->setMenu($this->products, $productID);
+
+ /* Remove the unused types. */
+ unset($this->lang->bug->typeList['designchange']);
+ unset($this->lang->bug->typeList['newfeature']);
+ unset($this->lang->bug->typeList['trackthings']);
+
+ /* Init vars. */
+ $moduleID = 0;
+ $projectID = 0;
+ $taskID = 0;
+ $storyID = 0;
+ $buildID = 0;
+ $caseID = 0;
+ $runID = 0;
+ $title = '';
+ $steps = $this->lang->bug->tplStep . $this->lang->bug->tplResult . $this->lang->bug->tplExpect;
+ $os = '';
+ $browser = '';
+ $assignedTo = '';
+ $mailto = '';
+ $keywords = '';
+ $severity = 3;
+ $type = 'codeerror';
+
+ /* Parse the extras. */
+ $extras = str_replace(array(',', ' '), array('&', ''), $extras);
+ parse_str($extras);
+
+ /* If set runID, get the last result info as the template. */
+ if($runID > 0) $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('run')->eq($runID)->orderBy('id desc')->limit(1)->fetch('id');
+ if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID));
+
+ /* If set caseID and runID='', get the last result info as the template. */
+ if($caseID > 0 && $runID == '')
+ {
+ $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('`case`')->eq($caseID)->orderBy('date desc')->limit(1)->fetch('id');
+ if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID, $caseID, $version));
+ }
+
+ /* If bugID setted, use this bug as template. */
+ if(isset($bugID))
+ {
+ $bug = $this->bug->getById($bugID);
+ extract((array)$bug);
+ $projectID = $bug->project;
+ $moduleID = $bug->module;
+ $taskID = $bug->task;
+ $storyID = $bug->story;
+ $buildID = $bug->openedBuild;
+ $severity = $bug->severity;
+ $type = $bug->type;
+ }
+
+ /* If projectID is setted, get builds and stories of this project. */
+ if($projectID)
+ {
+ $builds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty');
+ $stories = $this->story->getProjectStoryPairs($projectID);
+ }
+ else
+ {
+ $builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty');
+ $stories = $this->story->getProductStoryPairs($productID);
+ }
+
+ $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->create;
+ $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
+ $this->view->position[] = $this->lang->bug->create;
+
+ $this->view->productID = $productID;
+ $this->view->productName = $this->products[$productID];
+ $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0);
+ $this->view->stories = $stories;
+ $this->view->projects = $this->product->getProjectPairs($productID, $params = 'nodeleted');
+ $this->view->builds = $builds;
+ $this->view->tasks = $this->loadModel('task')->getProjectTaskPairs($projectID);
+ $this->view->moduleID = $moduleID;
+ $this->view->projectID = $projectID;
+ $this->view->taskID = $taskID;
+ $this->view->storyID = $storyID;
+ $this->view->buildID = $buildID;
+ $this->view->caseID = $caseID;
+ $this->view->title = $title;
+ $this->view->steps = htmlspecialchars($steps);
+ $this->view->os = $os;
+ $this->view->browser = $browser;
+ $this->view->assignedTo = $assignedTo;
+ $this->view->mailto = $mailto;
+ $this->view->keywords = $keywords;
+ $this->view->severity = $severity;
+ $this->view->type = $type;
+
+ $this->display();
+ }
+
+ /**
+ * View a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function view($bugID)
+ {
+ /* Judge bug exits or not. */
+ $bug = $this->bug->getById($bugID);
+ if(!$bug) die(js::error($this->lang->notFound) . js::locate('back'));
+
+ /* Set menu. */
+ $this->bug->setMenu($this->products, $bug->product);
+
+ /* Get product info. */
+ $productID = $bug->product;
+ $productName = $this->products[$productID];
+
+ /* Header and positon. */
+ $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->view;
+ $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $productName);
+ $this->view->position[] = $this->lang->bug->view;
+
+ /* Assign. */
+ $this->view->productID = $productID;
+ $this->view->productName = $productName;
+ $this->view->modulePath = $this->tree->getParents($bug->module);
+ $this->view->bug = $bug;
+ $this->view->users = $this->user->getPairs('noletter');
+ $this->view->actions = $this->action->getList('bug', $bugID);
+ $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID);
+
+ $this->display();
+ }
+
+ /**
+ * Edit a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function edit($bugID, $comment = false)
+ {
+ if(!empty($_POST))
+ {
+ $changes = array();
+ $files = array();
+ if($comment == false)
+ {
+ $changes = $this->bug->update($bugID);
+ if(dao::isError()) die(js::error(dao::getError()));
+ $files = $this->loadModel('file')->saveUpload('bug', $bugID);
+ }
+ if($this->post->comment != '' or !empty($changes) or !empty($files))
+ {
+ $action = !empty($changes) ? 'Edited' : 'Commented';
+ $fileAction = '';
+ if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ;
+ $actionID = $this->action->create('bug', $bugID, $action, $fileAction . $this->post->comment);
+ $this->action->logHistory($actionID, $changes);
+ $this->sendmail($bugID, $actionID);
+ }
+
+ $bug = $this->bug->getById($bugID);
+ if($bug->toTask != 0)
+ {
+ foreach($changes as $change)
+ {
+ if($change['field'] == 'status')
+ {
+ $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask");
+ $cancelURL = $this->server->HTTP_REFERER;
+ die(js::confirm(sprintf($this->lang->task->remindTask, $bug->Task), $confirmURL, $cancelURL, 'parent', 'parent'));
+ }
+ }
+ }
+ die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
+ }
+
+ /* Get the info of bug, current product and modue. */
+ $bug = $this->bug->getById($bugID);
+ $productID = $bug->product;
+ $projectID = $bug->project;
+ $currentModuleID = $bug->module;
+
+ /**
+ * Remove designchange, newfeature, trackings from the typeList, because should be tracked in story or task.
+ * These thress types if upgrade from bugfree2.x.
+ */
+ if($bug->type != 'designchange') unset($this->lang->bug->typeList['designchange']);
+ if($bug->type != 'newfeature') unset($this->lang->bug->typeList['newfeature']);
+ if($bug->type != 'trackthings') unset($this->lang->bug->typeList['trackthings']);
+
+ /* Set the menu. */
+ $this->bug->setMenu($this->products, $productID);
+
+ /* Set header and position. */
+ $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->edit;
+ $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
+ $this->view->position[] = $this->lang->bug->edit;
+
+ /* Assign. */
+ if($projectID)
+ {
+ $this->view->openedBuilds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty');
+ }
+ else
+ {
+ $this->view->openedBuilds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty');
+ }
+ $this->view->bug = $bug;
+ $this->view->productID = $productID;
+ $this->view->productName = $this->products[$productID];
+ $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0);
+ $this->view->currentModuleID = $currentModuleID;
+ $this->view->projects = $this->product->getProjectPairs($bug->product);
+ $this->view->stories = $bug->project ? $this->story->getProjectStoryPairs($bug->project) : $this->story->getProductStoryPairs($bug->product);
+ $this->view->tasks = $this->task->getProjectTaskPairs($bug->project);
+ $this->view->users = $this->user->appendDeleted($this->user->getPairs('nodeleted'), "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy");
+ $this->view->resolvedBuilds = array('' => '') + $this->view->openedBuilds;
+ $this->view->actions = $this->action->getList('bug', $bugID);
+ $this->view->templates = $this->bug->getUserBugTemplates($this->app->user->account);
+
+ $this->display();
+ }
+
+ /**
+ * confirm a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function confirmBug($bugID)
+ {
+ if(!empty($_POST))
+ {
+ $this->bug->confirm($bugID);
+ if(dao::isError()) die(js::error(dao::getError()));
+ $actionID = $this->action->create('bug', $bugID, 'bugConfirmed', $this->post->comment);
+ $this->sendmail($bugID, $actionID);
+ die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
+ }
+
+ $bug = $this->bug->getById($bugID);
+ $productID = $bug->product;
+ $this->bug->setMenu($this->products, $productID);
+
+ $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->confirmBug;
+ $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
+ $this->view->position[] = $this->lang->bug->confirmBug;
+
+ $this->view->bug = $bug;
+ $this->view->actions = $this->action->getList('bug', $bugID);
+ $this->display();
+ }
+
+ /**
+ * Resolve a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function resolve($bugID)
+ {
+ $this->view->users = $this->user->getPairs('nodeleted');
+
+ if(!empty($_POST))
+ {
+ $this->bug->resolve($bugID);
+ if(dao::isError()) die(js::error(dao::getError()));
+ $actionID = $this->action->create('bug', $bugID, 'Resolved', $this->post->comment, $this->post->resolution);
+ $this->sendmail($bugID, $actionID);
+
+ $bug = $this->bug->getById($bugID);
+ if($bug->toTask != 0)
+ {
+ $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask");
+ $cancelURL = $this->createLink('bug', 'view', "bugID=$bugID");
+ die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->toTask), $confirmURL, $cancelURL, 'parent', 'parent'));
+ }
+ die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
+ }
+
+ $bug = $this->bug->getById($bugID);
+ $productID = $bug->product;
+ $this->bug->setMenu($this->products, $productID);
+
+ $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve;
+ $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
+ $this->view->position[] = $this->lang->bug->resolve;
+
+ $this->view->bug = $bug;
+ $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID);
+ $this->view->actions = $this->action->getList('bug', $bugID);
+ $this->display();
+ }
+
+ /**
+ * Activate a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function activate($bugID)
+ {
+ $this->view->users = $this->user->getPairs('nodeleted');
+
+ if(!empty($_POST))
+ {
+ $this->bug->activate($bugID);
+ if(dao::isError()) die(js::error(dao::getError()));
+ $files = $this->loadModel('file')->saveUpload('bug', $bugID);
+ $actionID = $this->action->create('bug', $bugID, 'Activated', $this->post->comment);
+ $this->sendmail($bugID, $actionID);
+ die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
+ }
+
+ $bug = $this->bug->getById($bugID);
+ $productID = $bug->product;
+ $this->bug->setMenu($this->products, $productID);
+
+ $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->activate;
+ $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
+ $this->view->position[] = $this->lang->bug->activate;
+
+ $this->view->bug = $bug;
+ $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty');
+ $this->view->actions = $this->action->getList('bug', $bugID);
+
+ $this->display();
+ }
+
+ /**
+ * Close a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function close($bugID)
+ {
+ $this->view->users = $this->user->getPairs('noletter');
+ if(!empty($_POST))
+ {
+ $this->bug->close($bugID);
+ if(dao::isError()) die(js::error(dao::getError()));
+ $actionID = $this->action->create('bug', $bugID, 'Closed', $this->post->comment);
+ $this->sendmail($bugID, $actionID);
+ die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
+ }
+
+ $bug = $this->bug->getById($bugID);
+ $productID = $bug->product;
+ $this->bug->setMenu($this->products, $productID);
+
+ $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->close;
+ $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
+ $this->view->position[] = $this->lang->bug->close;
+
+ $this->view->bug = $bug;
+ $this->view->actions = $this->action->getList('bug', $bugID);
+ $this->display();
+ }
+
+ /**
+ * Confirm story change.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function confirmStoryChange($bugID)
+ {
+ $bug = $this->bug->getById($bugID);
+ $this->dao->update(TABLE_BUG)->set('storyVersion')->eq($bug->latestStoryVersion)->where('id')->eq($bugID)->exec();
+ $this->loadModel('action')->create('bug', $bugID, 'confirmed', '', $bug->latestStoryVersion);
+ die(js::reload('parent'));
+ }
+
+ /**
+ * Delete a bug.
+ *
+ * @param int $bugID
+ * @param string $confirm yes|no
+ * @access public
+ * @return void
+ */
+ public function delete($bugID, $confirm = 'no')
+ {
+ $bug = $this->bug->getById($bugID);
+ if($confirm == 'no')
+ {
+ die(js::confirm($this->lang->bug->confirmDelete, inlink('delete', "bugID=$bugID&confirm=yes")));
+ }
+ else
+ {
+ $this->bug->delete(TABLE_BUG, $bugID);
+ if($bug->toTask != 0) echo js::alert($this->lang->bug->remindTask . $bug->toTask);
+ die(js::locate($this->session->bugList, 'parent'));
+ }
+ }
+
+ /**
+ * Save current template.
+ *
+ * @access public
+ * @return string
+ */
+ public function saveTemplate()
+ {
+ $this->bug->saveUserBugTemplate();
+ if(dao::isError()) die(js::error(dao::getError()));
+ die($this->fetch('bug', 'buildTemplates'));
+ }
+
+ /**
+ * Build the user templates selection code.
+ *
+ * @access public
+ * @return void
+ */
+ public function buildTemplates()
+ {
+ $this->view->templates = $this->bug->getUserBugTemplates($this->app->user->account);
+ $this->display('bug', 'buildTemplates');
+ }
+
+ /**
+ * Delete a user template.
+ *
+ * @param int $templateID
+ * @access public
+ * @return void
+ */
+ public function deleteTemplate($templateID)
+ {
+ $this->dao->delete()->from(TABLE_USERTPL)->where('id')->eq($templateID)->andWhere('account')->eq($this->app->user->account)->exec();
+ die();
+ }
+
+ /**
+ * Custom fields.
+ *
+ * @access public
+ * @return void
+ */
+ public function customFields()
+ {
+ if($_POST)
+ {
+ $customFields = $this->post->customFields;
+ $customFields = join(',', $customFields);
+ setcookie('bugFields', $customFields, $this->config->cookieLife, $this->config->webRoot);
+ die(js::reload('parent'));
+ }
+
+ $customFields = $this->cookie->bugFields ? $this->cookie->bugFields : $this->config->bug->list->defaultFields;
+
+ $this->view->allFields = $this->bug->getFieldPairs($this->config->bug->list->allFields);
+ $this->view->customFields = $this->bug->getFieldPairs($customFields);
+ $this->view->defaultFields = $this->bug->getFieldPairs($this->config->bug->list->defaultFields);
+ die($this->display());
+ }
+
+ /**
+ * AJAX: get bugs of a user in html select.
+ *
+ * @param string $account
+ * @access public
+ * @return string
+ */
+ public function ajaxGetUserBugs($account = '')
+ {
+ if($account == '') $account = $this->app->user->account;
+ $bugs = $this->bug->getUserBugPairs($account);
+ die(html::select('bug', $bugs, '', 'class=select-1'));
+ }
+
+ /**
+ * AJAX: Get bug owner of a module.
+ *
+ * @param int $moduleID
+ * @param int $productID
+ * @access public
+ * @return string
+ */
+ public function ajaxGetModuleOwner($moduleID, $productID = 0)
+ {
+ $owner = '';
+ if($moduleID) $owner = $this->dao->findByID($moduleID)->from(TABLE_MODULE)->fetch('owner');
+ if(!$owner) $owner = $this->dao->findByID($productID)->from(TABLE_PRODUCT)->fetch('QM');
+ die($owner);
+ }
+
+ /**
+ * Send email.
+ *
+ * @param int $bugID
+ * @param int $actionID
+ * @access private
+ * @return void
+ */
+ private function sendmail($bugID, $actionID)
+ {
+ /* Set toList and ccList. */
+ $bug = $this->bug->getByID($bugID);
+ $productName = $this->products[$bug->product];
+ $toList = $bug->assignedTo;
+ $ccList = trim($bug->mailto, ',');
+ if($toList == '')
+ {
+ if($ccList == '') return;
+ if(strpos($ccList, ',') === false)
+ {
+ $toList = $ccList;
+ $ccList = '';
+ }
+ else
+ {
+ $commaPos = strpos($ccList, ',');
+ $toList = substr($ccList, 0, $commaPos);
+ $ccList = substr($ccList, $commaPos + 1);
+ }
+ }
+ elseif(strtolower($toList) == 'closed')
+ {
+ $toList = $bug->resolvedBy;
+ }
+
+ /* Get action info. */
+ $action = $this->action->getById($actionID);
+ $history = $this->action->getHistory($actionID);
+ $action->history = isset($history[$actionID]) ? $history[$actionID] : array();
+ if(strtolower($action->action) == 'opened') $action->comment = $bug->steps;
+
+ /* Create the mail content. */
+ $this->view->bug = $bug;
+ $this->view->action = $action;
+ $mailContent = $this->parse($this->moduleName, 'sendmail');
+
+ /* Send it. */
+ $this->loadModel('mail')->send($toList, $productName . ':' . 'BUG #'. $bug->id . $this->lang->colon . $bug->title, $mailContent, $ccList);
+ if($this->mail->isError()) echo js::error($this->mail->getError());
+ }
+
+ /**
+ * Get data to export
+ *
+ * @param string $productID
+ * @param string $orderBy
+ * @access public
+ * @return void
+ */
+ public function export($productID, $orderBy)
+ {
+ if($_POST)
+ {
+ $bugLang = $this->lang->bug;
+ $bugConfig = $this->config->bug;
+
+ /* Create field lists. */
+ $fields = explode(',', $bugConfig->list->exportFields);
+ foreach($fields as $key => $fieldName)
+ {
+ $fieldName = trim($fieldName);
+ $fields[$fieldName] = isset($bugLang->$fieldName) ? $bugLang->$fieldName : $fieldName;
+ unset($fields[$key]);
+ }
+
+ /* Get bugs. */
+ $bugs = $this->dao->select('*')->from(TABLE_BUG)->alias('t1')->where($this->session->bugReportCondition)->orderBy($orderBy)->fetchAll('id');
+
+ /* Get users, products and projects. */
+ $users = $this->loadModel('user')->getPairs('noletter');
+ $products = $this->loadModel('product')->getPairs();
+ $projects = $this->loadModel('project')->getPairs('all');
+
+ /* Get related objects id lists. */
+ $relatedModuleIdList = array();
+ $relatedStoryIdList = array();
+ $relatedTaskIdList = array();
+ $relatedBugIdList = array();
+ $relatedCaseIdList = array();
+ $relatedBuildIdList = array();
+
+ foreach($bugs as $bug)
+ {
+ $relatedModuleIdList[$bug->module] = $bug->module;
+ $relatedStoryIdList[$bug->story] = $bug->story;
+ $relatedTaskIdList[$bug->task] = $bug->task;
+ $relatedCaseIdList[$bug->case] = $bug->case;
+ $relatedBugIdList[$bug->duplicateBug] = $bug->duplicateBug;
+
+ /* Process link bugs. */
+ $linkBugs = explode(',', $bug->linkBug);
+ foreach($linkBugs as $linkBugID)
+ {
+ if($linkBugID) $relatedBugIdList[$linkBugID] = trim($linkBugID);
+ }
+
+ /* Process builds. */
+ $builds = $bug->openedBuild . ',' . $bug->resolvedBuild;
+ $builds = explode(',', $builds);
+ foreach($builds as $buildID)
+ {
+ if($buildID) $relatedBuildIdList[$buildID] = trim($buildID);
+ }
+ }
+
+ /* Get related objects title or names. */
+ $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs();
+ $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs();
+ $relatedTasks = $this->dao->select('id, name')->from(TABLE_TASK)->where('id')->in($relatedTaskIdList)->fetchPairs();
+ $relatedBugs = $this->dao->select('id, title')->from(TABLE_BUG)->where('id')->in($relatedBugIdList)->fetchPairs();
+ $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs();
+ $relatedBuilds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('id')->in($relatedBuildIdList)->fetchPairs();
+ $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('bug')->andWhere('objectID')->in(@array_keys($bugs))->fetchGroup('objectID');
+
+ foreach($bugs as $bug)
+ {
+ if($this->post->fileType == 'csv')
+ {
+ $bug->steps = htmlspecialchars_decode($bug->steps);
+ $bug->steps = str_replace(" ", "\n", $bug->steps);
+ $bug->steps = str_replace('"', '""', $bug->steps);
+ $bug->steps = str_replace(' ', ' ', $bug->steps);
+ $bug->steps = strip_tags($bug->steps);
+ }
+
+ /* fill some field with useful value. */
+ if(isset($products[$bug->product])) $bug->product = $products[$bug->product];
+ if(isset($projects[$bug->project])) $bug->project = $projects[$bug->project];
+ if(isset($relatedModules[$bug->module])) $bug->module = $relatedModules[$bug->module];
+ if(isset($relatedStories[$bug->story])) $bug->story = $relatedStories[$bug->story];
+ if(isset($relatedTasks[$bug->task])) $bug->task = $relatedTasks[$bug->task];
+ if(isset($relatedBugs[$bug->duplicateBug])) $bug->duplicateBug = $relatedBugs[$bug->duplicateBug];
+ if(isset($relatedCases[$bug->case])) $bug->case = $relatedCases[$bug->case];
+
+ if(isset($bugLang->priList[$bug->pri])) $bug->pri = $bugLang->priList[$bug->pri];
+ if(isset($bugLang->typeList[$bug->type])) $bug->type = $bugLang->typeList[$bug->type];
+ if(isset($bugLang->statusList[$bug->status])) $bug->status = $bugLang->statusList[$bug->status];
+ if(isset($bugLang->confirmedList[$bug->confirmed])) $bug->confirmed = $bugLang->confirmedList[$bug->confirmed];
+ 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->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];
+
+ $bug->openedDate = substr($bug->openedDate, 0, 10);
+ $bug->assignedDate = substr($bug->assignedDate, 0, 10);
+ $bug->closedDate = substr($bug->closedDate, 0, 10);
+ $bug->resolvedDate = substr($bug->resolvedDate, 0, 10);
+ $bug->lastEditedDate = substr($bug->lastEditedDate, 0, 10);
+
+ if($bug->linkBug)
+ {
+ $tmpLinkBugs = array();
+ $linkBugIdList = explode(',', $bug->linkBug);
+ foreach($linkBugIdList as $linkBugID)
+ {
+ $linkBugID = trim($linkBugID);
+ $tmpLinkBugs[] = isset($relatedBugs[$linkBugID]) ? $relatedBugs[$linkBugID] : $linkBugID;
+ }
+ $bug->linkBug = join("; \n", $tmpLinkBugs);
+ }
+
+ if($bug->openedBuild)
+ {
+ $tmpOpenedBuilds = array();
+ $tmpResolvedBuilds = array();
+ $buildIdList = explode(',', $bug->openedBuild);
+ foreach($buildIdList as $buildID)
+ {
+ $buildID = trim($buildID);
+ $tmpOpenedBuilds[] = isset($relatedBuilds[$buildID]) ? $relatedBuilds[$buildID] : $buildID;
+ }
+ $bug->openedBuild = join("; \n", $tmpOpenedBuilds);
+ }
+
+ if($bug->resolvedBuild)
+ {
+ $buildIdList = explode(',', $bug->resolvedBuild);
+ foreach($buildIdList as $buildID)
+ {
+ $buildID = trim($buildID);
+ $tmpResolvedBuilds[] = isset($relatedBuilds[$buildID]) ? $relatedBuilds[$buildID] : $buildID;
+ }
+ $bug->resolvedBuild = join("; \n", $tmpResolvedBuilds);
+ }
+
+ /* Set related files. */
+ if(isset($relatedFiles[$bug->id]))
+ {
+ foreach($relatedFiles[$bug->id] as $file)
+ {
+ $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/$bug->company/" . $file->pathname;
+ $bug->files .= html::a($fileURL, $file->title, '_blank') . ' ';
+ }
+ }
+
+ $bug->mailto = trim(trim($bug->mailto), ',');
+ $mailtos = explode(',', $bug->mailto);
+ $bug->mailto = '';
+ foreach($mailtos as $mailto)
+ {
+ $mailto = trim($mailto);
+ if(isset($users[$mailto])) $bug->mailto .= $users[$mailto] . ',';
+ }
+
+ /* drop some field that is not needed. */
+ unset($bug->company);
+ unset($bug->caseVersion);
+ unset($bug->result);
+ unset($bug->deleted);
+ }
+
+ $this->post->set('fields', $fields);
+ $this->post->set('rows', $bugs);
+ $this->fetch('file', 'export2' . $this->post->fileType, $_POST);
+ }
+
+ $this->display();
+ }
+}
diff --git a/module/bug/lang/en.php b/module/bug/lang/en.php
index 09db614e9a..23e577b833 100644
--- a/module/bug/lang/en.php
+++ b/module/bug/lang/en.php
@@ -1,312 +1,312 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-/* Fieldlist. */
-$lang->bug->common = 'Bug';
-$lang->bug->id = 'ID';
-$lang->bug->product = 'Product';
-$lang->bug->module = 'Module';
-$lang->bug->path = 'Path';
-$lang->bug->project = 'Project';
-$lang->bug->story = 'Story';
-$lang->bug->storyVersion = 'Story Version';
-$lang->bug->task = 'Task';
-$lang->bug->title = 'Title';
-$lang->bug->severity = 'Severity';
-$lang->bug->severityAB = 'S';
-$lang->bug->pri = 'Priority';
-$lang->bug->type = 'Type';
-$lang->bug->os = 'OS';
-$lang->bug->hardware = 'Hardware';
-$lang->bug->browser = 'Browser';
-$lang->bug->machine = 'Machine';
-$lang->bug->found = 'How found';
-$lang->bug->steps = 'Steps';
-$lang->bug->status = 'Status';
-$lang->bug->statusAB = 'Status';
-$lang->bug->activatedCount = 'Activated count';
-$lang->bug->activatedCountAB = 'Activated count';
-$lang->bug->confirmed = 'Confirmed';
-$lang->bug->toTask = 'To task';
-$lang->bug->toStory = 'To story';
-$lang->bug->mailto = 'Mailto';
-$lang->bug->openedBy = 'Opened By';
-$lang->bug->openedByAB = 'Opened';
-$lang->bug->openedDate = 'Opened date';
-$lang->bug->openedDateAB = 'Date';
-$lang->bug->openedBuild = 'Opened Build';
-$lang->bug->assignedTo = 'Assigned';
-$lang->bug->assignedDate = 'Assigned Date';
-$lang->bug->resolvedBy = 'Resolved By';
-$lang->bug->resolvedByAB = 'Resolve';
-$lang->bug->resolution = 'Resolution';
-$lang->bug->resolutionAB = 'Resolution';
-$lang->bug->resolvedBuild = 'Resolved Build';
-$lang->bug->resolvedDate = 'Resolved Date';
-$lang->bug->resolvedDateAB = 'Date';
-$lang->bug->closedBy = 'Closed By';
-$lang->bug->closedDate = 'Closed Date';
-$lang->bug->duplicateBug = 'Duplicate';
-$lang->bug->lastEditedBy = 'Last Edited By';
-$lang->bug->lastEditedDate = 'Last Edited Date';
-$lang->bug->linkBug = 'Related';
-$lang->bug->case = 'Case';
-$lang->bug->files = 'Files';
-$lang->bug->keywords = 'Keywords';
-$lang->bug->lastEditedByAB = 'Edited';
-$lang->bug->lastEditedDateAB = 'Edited Date';
-
-/* Actions. */
-$lang->bug->index = 'Index';
-$lang->bug->create = 'Create Bug';
-$lang->bug->confirmBug = 'Confirm Bug';
-$lang->bug->edit = 'Edit Bug';
-$lang->bug->browse = 'Browse Bug';
-$lang->bug->view = 'Bug Info';
-$lang->bug->resolve = 'Resolve Bug';
-$lang->bug->close = 'Close Bug';
-$lang->bug->activate = 'Activate Bug';
-$lang->bug->reportChart = 'Report';
-$lang->bug->export = 'Export data';
-$lang->bug->delete = 'Delete Bug';
-$lang->bug->saveTemplate = 'Save template';
-$lang->bug->deleteTemplate = 'Delete template';
-$lang->bug->customFields = 'Custom';
-$lang->bug->restoreDefault = 'Default';
-$lang->bug->ajaxGetUserBugs = 'API: My Bugs';
-$lang->bug->ajaxGetModuleOwner = 'API: Get module default owner';
-$lang->bug->confirmStoryChange = 'Confirm Story Change';
-
-/* Browse tabs. */
-$lang->bug->selectProduct = 'Select product';
-$lang->bug->byModule = 'ByModule';
-$lang->bug->assignToMe = 'MyBugs';
-$lang->bug->openedByMe = 'MyOpen';
-$lang->bug->resolvedByMe = 'MyResolve';
-$lang->bug->closedByMe = 'MyClose';
-$lang->bug->assignToNull = 'Unassigned';
-$lang->bug->unResolved = 'Unresolved';
-$lang->bug->unclosed = 'Unclosed';
-$lang->bug->longLifeBugs = 'Longlife';
-$lang->bug->postponedBugs = 'Postponed';
-$lang->bug->allBugs = 'Allbug';
-$lang->bug->moduleBugs = 'ByModule';
-$lang->bug->byQuery = 'Search';
-$lang->bug->needConfirm = 'StoryChanged';
-$lang->bug->allProduct = 'All products';
-
-/* Labels. */
-$lang->bug->lblProductAndModule = 'Product&Module';
-$lang->bug->lblProjectAndTask = 'Project&Task';
-$lang->bug->lblStory = 'Story';
-$lang->bug->lblTypeAndSeverity = 'Type&Severity';
-$lang->bug->lblSystemBrowserAndHardware = 'OS&Browser';
-$lang->bug->lblAssignedTo = 'Assigned to';
-$lang->bug->lblMailto = 'Mailto';
-$lang->bug->lblLastEdited = 'Last edited';
-$lang->bug->lblResolved = 'Resolved';
-$lang->bug->lblAllFields = 'All Fields';
-$lang->bug->lblCustomFields = 'Custom Fields';
-
-/* Legends. */
-$lang->bug->legendBasicInfo = 'Basic info';
-$lang->bug->legendMailto = 'Mailto';
-$lang->bug->legendAttatch = 'Files';
-$lang->bug->legendLinkBugs = 'Related bug';
-$lang->bug->legendPrjStoryTask = 'Project, story & task';
-$lang->bug->legendCases = 'Related case';
-$lang->bug->legendSteps = 'Steps';
-$lang->bug->legendAction = 'Action';
-$lang->bug->legendHistory = 'History';
-$lang->bug->legendComment = 'Comment';
-$lang->bug->legendLife = 'Lifetime';
-$lang->bug->legendMisc = 'Misc';
-
-/* Action buttons. */
-$lang->bug->buttonConfirm = 'Confirm';
-$lang->bug->buttonCopy = 'Copy';
-$lang->bug->buttonEdit = 'Edit';
-$lang->bug->buttonActivate = 'Activate';
-$lang->bug->buttonResolve = 'Resolve';
-$lang->bug->buttonClose = 'Close';
-$lang->bug->buttonToList = 'Back';
-$lang->bug->buttonCreateTestcase = 'Create case';
-
-/* Confirm messags. */
-$lang->bug->confirmChangeProduct = 'Change product will change project, task and story also, are you sure?';
-$lang->bug->confirmDelete = 'Are you sure to delete this bug?';
-$lang->bug->setTemplateTitle = 'Please input the template title:';
-$lang->bug->remindTask = 'This bug has been to be a task, update the task:%s or not?';
-
-/* Templates. */
-$lang->bug->tplStep = "[Steps]
";
-$lang->bug->tplResult = "[Result]
";
-$lang->bug->tplExpect = "[Expect]
";
-
-/* Field options lists. */
-$lang->bug->severityList[3] = '3';
-$lang->bug->severityList[1] = '1';
-$lang->bug->severityList[2] = '2';
-$lang->bug->severityList[4] = '4';
-
-$lang->bug->priList[0] = '';
-$lang->bug->priList[3] = '3';
-$lang->bug->priList[1] = '1';
-$lang->bug->priList[2] = '2';
-$lang->bug->priList[4] = '4';
-
-$lang->bug->osList[''] = '';
-$lang->bug->osList['all'] = 'All';
-$lang->bug->osList['windows'] = 'Windows';
-$lang->bug->osList['winxp'] = 'Windows XP';
-$lang->bug->osList['win7'] = 'Windows 7';
-$lang->bug->osList['vista'] = 'Windows Vista';
-$lang->bug->osList['win2000'] = 'Windows 2000';
-$lang->bug->osList['win2003'] = 'Windows 2003';
-$lang->bug->osList['win2008'] = 'Windows 2008';
-$lang->bug->osList['winnt'] = 'Windows NT';
-$lang->bug->osList['win98'] = 'Windows 98';
-$lang->bug->osList['andriod'] = 'Andriod';
-$lang->bug->osList['ios'] = 'IOS';
-$lang->bug->osList['wp7'] = 'WP7';
-$lang->bug->osList['symbian'] = 'Symbian';
-$lang->bug->osList['linux'] = 'Linux';
-$lang->bug->osList['freebsd'] = 'FreeBSD';
-$lang->bug->osList['mac'] = 'Mac OS';
-$lang->bug->osList['unix'] = 'Unix';
-$lang->bug->osList['others'] = 'Others';
-
-$lang->bug->browserList[''] = '';
-$lang->bug->browserList['all'] = 'All';
-$lang->bug->browserList['ie'] = 'IE';
-$lang->bug->browserList['ie8'] = 'IE8';
-$lang->bug->browserList['ie9'] = 'IE9';
-$lang->bug->browserList['ie6'] = 'IE6';
-$lang->bug->browserList['ie7'] = 'IE7';
-$lang->bug->browserList['chrome'] = 'chrome';
-$lang->bug->browserList['firefox'] = 'Firefox';
-$lang->bug->browserList['firefox2'] = 'Firefox2';
-$lang->bug->browserList['firefox3'] = 'Firefox3';
-$lang->bug->browserList['firefox4'] = 'Firefox4';
-$lang->bug->browserList['opera'] = 'opera';
-$lang->bug->browserList['opera9'] = 'opera9';
-$lang->bug->browserList['oprea10'] = 'opera10';
-$lang->bug->browserList['oprea11'] = 'opera11';
-$lang->bug->browserList['safari'] = 'safari';
-$lang->bug->browserList['maxthon'] = '傲游';
-$lang->bug->browserList['uc'] = 'UC';
-$lang->bug->browserList['other'] = 'Others';
-
-$lang->bug->typeList[''] = '';
-$lang->bug->typeList['codeerror'] = 'Code error';
-$lang->bug->typeList['interface'] = 'Interface';
-$lang->bug->typeList['designchange'] = 'Design change';
-$lang->bug->typeList['newfeature'] = 'New feature';
-$lang->bug->typeList['designdefect'] = 'Design defect';
-$lang->bug->typeList['config'] = 'Config';
-$lang->bug->typeList['install'] = 'Install';
-$lang->bug->typeList['security'] = 'Security';
-$lang->bug->typeList['performance'] = 'Performance';
-$lang->bug->typeList['standard'] = 'Standard';
-$lang->bug->typeList['automation'] = 'Automation';
-$lang->bug->typeList['trackthings'] = 'Tracking';
-$lang->bug->typeList['others'] = 'Others';
-
-$lang->bug->statusList[''] = '';
-$lang->bug->statusList['active'] = 'Active';
-$lang->bug->statusList['resolved'] = 'Resolved';
-$lang->bug->statusList['closed'] = 'Closed';
-
-$lang->bug->confirmedList[1] = 'Confirmed';
-$lang->bug->confirmedList[0] = 'Unconfirmed';
-
-$lang->bug->resolutionList[''] = '';
-$lang->bug->resolutionList['bydesign'] = 'By design';
-$lang->bug->resolutionList['duplicate'] = 'Duplicate';
-$lang->bug->resolutionList['external'] = 'External';
-$lang->bug->resolutionList['fixed'] = 'Fixed';
-$lang->bug->resolutionList['notrepro'] = 'Not reproduce';
-$lang->bug->resolutionList['postponed'] = 'Postponed';
-$lang->bug->resolutionList['willnotfix'] = "Won't fix";
-$lang->bug->resolutionList['tostory'] = 'To story';
-
-/* Report. */
-$lang->bug->report->common = 'Report';
-$lang->bug->report->select = 'Select';
-$lang->bug->report->create = 'Create';
-$lang->bug->report->selectAll = 'All';
-$lang->bug->report->selectReverse = 'Reverse';
-
-$lang->bug->report->charts['bugsPerProject'] = 'Project bugs';
-$lang->bug->report->charts['bugsPerModule'] = 'Module bugs';
-$lang->bug->report->charts['openedBugsPerDay'] = 'Opened bugs per day';
-$lang->bug->report->charts['resolvedBugsPerDay'] = 'Resolved bugs per day';
-$lang->bug->report->charts['closedBugsPerDay'] = 'Closed bugs per day';
-$lang->bug->report->charts['openedBugsPerUser'] = 'Opened bugs per user';
-$lang->bug->report->charts['resolvedBugsPerUser'] = 'Resolved bugs per user';
-$lang->bug->report->charts['closedBugsPerUser'] = 'Closed bugs per user';
-$lang->bug->report->charts['bugsPerSeverity'] = 'Severity';
-$lang->bug->report->charts['bugsPerResolution'] = 'Resolution';
-$lang->bug->report->charts['bugsPerStatus'] = 'Status';
-$lang->bug->report->charts['bugsPerActivatedCount'] = 'Activated count';
-$lang->bug->report->charts['bugsPerType'] = 'Type';
-$lang->bug->report->charts['bugsPerAssignedTo'] = 'AssignedTo';
-//$lang->bug->report->charts['bugLiveDays'] = 'Bug处理时间统计';
-//$lang->bug->report->charts['bugHistories'] = 'Bug处理步骤统计';
-
-$lang->bug->report->options->swf = 'pie2d';
-$lang->bug->report->options->width = 'auto';
-$lang->bug->report->options->height = 300;
-$lang->bug->report->options->graph->baseFontSize = 12;
-$lang->bug->report->options->graph->showNames = 1;
-$lang->bug->report->options->graph->formatNumber = 1;
-$lang->bug->report->options->graph->decimalPrecision = 0;
-$lang->bug->report->options->graph->animation = 0;
-$lang->bug->report->options->graph->rotateNames = 0;
-$lang->bug->report->options->graph->yAxisName = 'COUNT';
-$lang->bug->report->options->graph->pieRadius = 100;
-$lang->bug->report->options->graph->showColumnShadow = 0;
-
-$lang->bug->report->bugsPerProject->graph->xAxisName = 'Project';
-$lang->bug->report->bugsPerModule->graph->xAxisName = 'Module';
-
-$lang->bug->report->openedBugsPerDay->swf = 'column2d';
-$lang->bug->report->openedBugsPerDay->height = 400;
-$lang->bug->report->openedBugsPerDay->graph->xAxisName = 'Date';
-$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->resolvedBugsPerDay->swf = 'column2d';
-$lang->bug->report->resolvedBugsPerDay->height = 400;
-$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = 'Date';
-$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->closedBugsPerDay->swf = 'column2d';
-$lang->bug->report->closedBugsPerDay->height = 400;
-$lang->bug->report->closedBugsPerDay->graph->xAxisName = 'Date';
-$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->openedBugsPerUser->graph->xAxisName = 'User';
-$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= 'User';
-$lang->bug->report->closedBugsPerUser->graph->xAxisName = 'User';
-
-$lang->bug->report->bugsPerSeverity->graph->xAxisName = 'Severity';
-$lang->bug->report->bugsPerResolution->graph->xAxisName = 'Resolution';
-$lang->bug->report->bugsPerStatus->graph->xAxisName = 'Status';
-$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = 'Activated count';
-$lang->bug->report->bugsPerType->graph->xAxisName = 'Type';
-$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = 'AssignedTo';
-$lang->bug->report->bugLiveDays->graph->xAxisName = 'Live days';
-$lang->bug->report->bugHistories->graph->xAxisName = 'Histories';
-
-/* 操作记录。*/
-$lang->bug->action->resolved = array('main' => '$date, Resolved by $actor , resolution is $extra .', 'extra' => $lang->bug->resolutionList);
-$lang->bug->action->tostory = array('main' => '$date, To story by $actor , ID is $extra .');
-$lang->bug->action->totask = array('main' => '$date, To task by $actor , ID is $extra .');
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+/* Fieldlist. */
+$lang->bug->common = 'Bug';
+$lang->bug->id = 'ID';
+$lang->bug->product = 'Product';
+$lang->bug->module = 'Module';
+$lang->bug->path = 'Path';
+$lang->bug->project = 'Project';
+$lang->bug->story = 'Story';
+$lang->bug->storyVersion = 'Story Version';
+$lang->bug->task = 'Task';
+$lang->bug->title = 'Title';
+$lang->bug->severity = 'Severity';
+$lang->bug->severityAB = 'S';
+$lang->bug->pri = 'Priority';
+$lang->bug->type = 'Type';
+$lang->bug->os = 'OS';
+$lang->bug->hardware = 'Hardware';
+$lang->bug->browser = 'Browser';
+$lang->bug->machine = 'Machine';
+$lang->bug->found = 'How found';
+$lang->bug->steps = 'Steps';
+$lang->bug->status = 'Status';
+$lang->bug->statusAB = 'Status';
+$lang->bug->activatedCount = 'Activated count';
+$lang->bug->activatedCountAB = 'Activated count';
+$lang->bug->confirmed = 'Confirmed';
+$lang->bug->toTask = 'To task';
+$lang->bug->toStory = 'To story';
+$lang->bug->mailto = 'Mailto';
+$lang->bug->openedBy = 'Opened By';
+$lang->bug->openedByAB = 'Opened';
+$lang->bug->openedDate = 'Opened date';
+$lang->bug->openedDateAB = 'Date';
+$lang->bug->openedBuild = 'Opened Build';
+$lang->bug->assignedTo = 'Assigned';
+$lang->bug->assignedDate = 'Assigned Date';
+$lang->bug->resolvedBy = 'Resolved By';
+$lang->bug->resolvedByAB = 'Resolve';
+$lang->bug->resolution = 'Resolution';
+$lang->bug->resolutionAB = 'Resolution';
+$lang->bug->resolvedBuild = 'Resolved Build';
+$lang->bug->resolvedDate = 'Resolved Date';
+$lang->bug->resolvedDateAB = 'Date';
+$lang->bug->closedBy = 'Closed By';
+$lang->bug->closedDate = 'Closed Date';
+$lang->bug->duplicateBug = 'Duplicate';
+$lang->bug->lastEditedBy = 'Last Edited By';
+$lang->bug->lastEditedDate = 'Last Edited Date';
+$lang->bug->linkBug = 'Related';
+$lang->bug->case = 'Case';
+$lang->bug->files = 'Files';
+$lang->bug->keywords = 'Keywords';
+$lang->bug->lastEditedByAB = 'Edited';
+$lang->bug->lastEditedDateAB = 'Edited Date';
+
+/* Actions. */
+$lang->bug->index = 'Index';
+$lang->bug->create = 'Create Bug';
+$lang->bug->confirmBug = 'Confirm Bug';
+$lang->bug->edit = 'Edit Bug';
+$lang->bug->browse = 'Browse Bug';
+$lang->bug->view = 'Bug Info';
+$lang->bug->resolve = 'Resolve Bug';
+$lang->bug->close = 'Close Bug';
+$lang->bug->activate = 'Activate Bug';
+$lang->bug->reportChart = 'Report';
+$lang->bug->export = 'Export data';
+$lang->bug->delete = 'Delete Bug';
+$lang->bug->saveTemplate = 'Save template';
+$lang->bug->deleteTemplate = 'Delete template';
+$lang->bug->customFields = 'Custom';
+$lang->bug->restoreDefault = 'Default';
+$lang->bug->ajaxGetUserBugs = 'API: My Bugs';
+$lang->bug->ajaxGetModuleOwner = 'API: Get module default owner';
+$lang->bug->confirmStoryChange = 'Confirm Story Change';
+
+/* Browse tabs. */
+$lang->bug->selectProduct = 'Select product';
+$lang->bug->byModule = 'ByModule';
+$lang->bug->assignToMe = 'MyBugs';
+$lang->bug->openedByMe = 'MyOpen';
+$lang->bug->resolvedByMe = 'MyResolve';
+$lang->bug->closedByMe = 'MyClose';
+$lang->bug->assignToNull = 'Unassigned';
+$lang->bug->unResolved = 'Unresolved';
+$lang->bug->unclosed = 'Unclosed';
+$lang->bug->longLifeBugs = 'Longlife';
+$lang->bug->postponedBugs = 'Postponed';
+$lang->bug->allBugs = 'Allbug';
+$lang->bug->moduleBugs = 'ByModule';
+$lang->bug->byQuery = 'Search';
+$lang->bug->needConfirm = 'StoryChanged';
+$lang->bug->allProduct = 'All products';
+
+/* Labels. */
+$lang->bug->lblProductAndModule = 'Product&Module';
+$lang->bug->lblProjectAndTask = 'Project&Task';
+$lang->bug->lblStory = 'Story';
+$lang->bug->lblTypeAndSeverity = 'Type&Severity';
+$lang->bug->lblSystemBrowserAndHardware = 'OS&Browser';
+$lang->bug->lblAssignedTo = 'Assigned to';
+$lang->bug->lblMailto = 'Mailto';
+$lang->bug->lblLastEdited = 'Last edited';
+$lang->bug->lblResolved = 'Resolved';
+$lang->bug->lblAllFields = 'All Fields';
+$lang->bug->lblCustomFields = 'Custom Fields';
+
+/* Legends. */
+$lang->bug->legendBasicInfo = 'Basic info';
+$lang->bug->legendMailto = 'Mailto';
+$lang->bug->legendAttatch = 'Files';
+$lang->bug->legendLinkBugs = 'Related bug';
+$lang->bug->legendPrjStoryTask = 'Project, story & task';
+$lang->bug->legendCases = 'Related case';
+$lang->bug->legendSteps = 'Steps';
+$lang->bug->legendAction = 'Action';
+$lang->bug->legendHistory = 'History';
+$lang->bug->legendComment = 'Comment';
+$lang->bug->legendLife = 'Lifetime';
+$lang->bug->legendMisc = 'Misc';
+
+/* Action buttons. */
+$lang->bug->buttonConfirm = 'Confirm';
+$lang->bug->buttonCopy = 'Copy';
+$lang->bug->buttonEdit = 'Edit';
+$lang->bug->buttonActivate = 'Activate';
+$lang->bug->buttonResolve = 'Resolve';
+$lang->bug->buttonClose = 'Close';
+$lang->bug->buttonToList = 'Back';
+$lang->bug->buttonCreateTestcase = 'Create case';
+
+/* Confirm messags. */
+$lang->bug->confirmChangeProduct = 'Change product will change project, task and story also, are you sure?';
+$lang->bug->confirmDelete = 'Are you sure to delete this bug?';
+$lang->bug->setTemplateTitle = 'Please input the template title:';
+$lang->bug->remindTask = 'This bug has been to be a task, update the task:%s or not?';
+
+/* Templates. */
+$lang->bug->tplStep = "[Steps]
";
+$lang->bug->tplResult = "[Result]
";
+$lang->bug->tplExpect = "[Expect]
";
+
+/* Field options lists. */
+$lang->bug->severityList[3] = '3';
+$lang->bug->severityList[1] = '1';
+$lang->bug->severityList[2] = '2';
+$lang->bug->severityList[4] = '4';
+
+$lang->bug->priList[0] = '';
+$lang->bug->priList[3] = '3';
+$lang->bug->priList[1] = '1';
+$lang->bug->priList[2] = '2';
+$lang->bug->priList[4] = '4';
+
+$lang->bug->osList[''] = '';
+$lang->bug->osList['all'] = 'All';
+$lang->bug->osList['windows'] = 'Windows';
+$lang->bug->osList['winxp'] = 'Windows XP';
+$lang->bug->osList['win7'] = 'Windows 7';
+$lang->bug->osList['vista'] = 'Windows Vista';
+$lang->bug->osList['win2000'] = 'Windows 2000';
+$lang->bug->osList['win2003'] = 'Windows 2003';
+$lang->bug->osList['win2008'] = 'Windows 2008';
+$lang->bug->osList['winnt'] = 'Windows NT';
+$lang->bug->osList['win98'] = 'Windows 98';
+$lang->bug->osList['andriod'] = 'Andriod';
+$lang->bug->osList['ios'] = 'IOS';
+$lang->bug->osList['wp7'] = 'WP7';
+$lang->bug->osList['symbian'] = 'Symbian';
+$lang->bug->osList['linux'] = 'Linux';
+$lang->bug->osList['freebsd'] = 'FreeBSD';
+$lang->bug->osList['mac'] = 'Mac OS';
+$lang->bug->osList['unix'] = 'Unix';
+$lang->bug->osList['others'] = 'Others';
+
+$lang->bug->browserList[''] = '';
+$lang->bug->browserList['all'] = 'All';
+$lang->bug->browserList['ie'] = 'IE';
+$lang->bug->browserList['ie8'] = 'IE8';
+$lang->bug->browserList['ie9'] = 'IE9';
+$lang->bug->browserList['ie6'] = 'IE6';
+$lang->bug->browserList['ie7'] = 'IE7';
+$lang->bug->browserList['chrome'] = 'chrome';
+$lang->bug->browserList['firefox'] = 'Firefox';
+$lang->bug->browserList['firefox2'] = 'Firefox2';
+$lang->bug->browserList['firefox3'] = 'Firefox3';
+$lang->bug->browserList['firefox4'] = 'Firefox4';
+$lang->bug->browserList['opera'] = 'opera';
+$lang->bug->browserList['opera9'] = 'opera9';
+$lang->bug->browserList['oprea10'] = 'opera10';
+$lang->bug->browserList['oprea11'] = 'opera11';
+$lang->bug->browserList['safari'] = 'safari';
+$lang->bug->browserList['maxthon'] = '傲游';
+$lang->bug->browserList['uc'] = 'UC';
+$lang->bug->browserList['other'] = 'Others';
+
+$lang->bug->typeList[''] = '';
+$lang->bug->typeList['codeerror'] = 'Code error';
+$lang->bug->typeList['interface'] = 'Interface';
+$lang->bug->typeList['designchange'] = 'Design change';
+$lang->bug->typeList['newfeature'] = 'New feature';
+$lang->bug->typeList['designdefect'] = 'Design defect';
+$lang->bug->typeList['config'] = 'Config';
+$lang->bug->typeList['install'] = 'Install';
+$lang->bug->typeList['security'] = 'Security';
+$lang->bug->typeList['performance'] = 'Performance';
+$lang->bug->typeList['standard'] = 'Standard';
+$lang->bug->typeList['automation'] = 'Automation';
+$lang->bug->typeList['trackthings'] = 'Tracking';
+$lang->bug->typeList['others'] = 'Others';
+
+$lang->bug->statusList[''] = '';
+$lang->bug->statusList['active'] = 'Active';
+$lang->bug->statusList['resolved'] = 'Resolved';
+$lang->bug->statusList['closed'] = 'Closed';
+
+$lang->bug->confirmedList[1] = 'Confirmed';
+$lang->bug->confirmedList[0] = 'Unconfirmed';
+
+$lang->bug->resolutionList[''] = '';
+$lang->bug->resolutionList['bydesign'] = 'By design';
+$lang->bug->resolutionList['duplicate'] = 'Duplicate';
+$lang->bug->resolutionList['external'] = 'External';
+$lang->bug->resolutionList['fixed'] = 'Fixed';
+$lang->bug->resolutionList['notrepro'] = 'Not reproduce';
+$lang->bug->resolutionList['postponed'] = 'Postponed';
+$lang->bug->resolutionList['willnotfix'] = "Won't fix";
+$lang->bug->resolutionList['tostory'] = 'To story';
+
+/* Report. */
+$lang->bug->report->common = 'Report';
+$lang->bug->report->select = 'Select';
+$lang->bug->report->create = 'Create';
+$lang->bug->report->selectAll = 'All';
+$lang->bug->report->selectReverse = 'Reverse';
+
+$lang->bug->report->charts['bugsPerProject'] = 'Project bugs';
+$lang->bug->report->charts['bugsPerModule'] = 'Module bugs';
+$lang->bug->report->charts['openedBugsPerDay'] = 'Opened bugs per day';
+$lang->bug->report->charts['resolvedBugsPerDay'] = 'Resolved bugs per day';
+$lang->bug->report->charts['closedBugsPerDay'] = 'Closed bugs per day';
+$lang->bug->report->charts['openedBugsPerUser'] = 'Opened bugs per user';
+$lang->bug->report->charts['resolvedBugsPerUser'] = 'Resolved bugs per user';
+$lang->bug->report->charts['closedBugsPerUser'] = 'Closed bugs per user';
+$lang->bug->report->charts['bugsPerSeverity'] = 'Severity';
+$lang->bug->report->charts['bugsPerResolution'] = 'Resolution';
+$lang->bug->report->charts['bugsPerStatus'] = 'Status';
+$lang->bug->report->charts['bugsPerActivatedCount'] = 'Activated count';
+$lang->bug->report->charts['bugsPerType'] = 'Type';
+$lang->bug->report->charts['bugsPerAssignedTo'] = 'AssignedTo';
+//$lang->bug->report->charts['bugLiveDays'] = 'Bug处理时间统计';
+//$lang->bug->report->charts['bugHistories'] = 'Bug处理步骤统计';
+
+$lang->bug->report->options->swf = 'pie2d';
+$lang->bug->report->options->width = 'auto';
+$lang->bug->report->options->height = 300;
+$lang->bug->report->options->graph->baseFontSize = 12;
+$lang->bug->report->options->graph->showNames = 1;
+$lang->bug->report->options->graph->formatNumber = 1;
+$lang->bug->report->options->graph->decimalPrecision = 0;
+$lang->bug->report->options->graph->animation = 0;
+$lang->bug->report->options->graph->rotateNames = 0;
+$lang->bug->report->options->graph->yAxisName = 'COUNT';
+$lang->bug->report->options->graph->pieRadius = 100;
+$lang->bug->report->options->graph->showColumnShadow = 0;
+
+$lang->bug->report->bugsPerProject->graph->xAxisName = 'Project';
+$lang->bug->report->bugsPerModule->graph->xAxisName = 'Module';
+
+$lang->bug->report->openedBugsPerDay->swf = 'column2d';
+$lang->bug->report->openedBugsPerDay->height = 400;
+$lang->bug->report->openedBugsPerDay->graph->xAxisName = 'Date';
+$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->resolvedBugsPerDay->swf = 'column2d';
+$lang->bug->report->resolvedBugsPerDay->height = 400;
+$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = 'Date';
+$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->closedBugsPerDay->swf = 'column2d';
+$lang->bug->report->closedBugsPerDay->height = 400;
+$lang->bug->report->closedBugsPerDay->graph->xAxisName = 'Date';
+$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->openedBugsPerUser->graph->xAxisName = 'User';
+$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= 'User';
+$lang->bug->report->closedBugsPerUser->graph->xAxisName = 'User';
+
+$lang->bug->report->bugsPerSeverity->graph->xAxisName = 'Severity';
+$lang->bug->report->bugsPerResolution->graph->xAxisName = 'Resolution';
+$lang->bug->report->bugsPerStatus->graph->xAxisName = 'Status';
+$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = 'Activated count';
+$lang->bug->report->bugsPerType->graph->xAxisName = 'Type';
+$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = 'AssignedTo';
+$lang->bug->report->bugLiveDays->graph->xAxisName = 'Live days';
+$lang->bug->report->bugHistories->graph->xAxisName = 'Histories';
+
+/* 操作记录。*/
+$lang->bug->action->resolved = array('main' => '$date, Resolved by $actor , resolution is $extra .', 'extra' => $lang->bug->resolutionList);
+$lang->bug->action->tostory = array('main' => '$date, To story by $actor , ID is $extra .');
+$lang->bug->action->totask = array('main' => '$date, To task by $actor , ID is $extra .');
diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php
index 286e550364..fd5f8ab6d2 100644
--- a/module/bug/lang/zh-cn.php
+++ b/module/bug/lang/zh-cn.php
@@ -1,312 +1,312 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-/* 字段列表。*/
-$lang->bug->common = '缺陷管理';
-$lang->bug->id = 'Bug编号';
-$lang->bug->product = '所属产品';
-$lang->bug->module = '所属模块';
-$lang->bug->path = '模块路径';
-$lang->bug->project = '所属项目';
-$lang->bug->story = '相关需求';
-$lang->bug->storyVersion = '需求版本';
-$lang->bug->task = '相关任务';
-$lang->bug->title = 'Bug标题';
-$lang->bug->severity = '严重程度';
-$lang->bug->severityAB = '级别';
-$lang->bug->pri = '优先级';
-$lang->bug->type = 'Bug类型';
-$lang->bug->os = '操作系统';
-$lang->bug->hardware = '硬件平台';
-$lang->bug->browser = '浏览器';
-$lang->bug->machine = '机器硬件';
-$lang->bug->found = '如何发现';
-$lang->bug->steps = '重现步骤';
-$lang->bug->status = 'Bug状态';
-$lang->bug->statusAB = '状态';
-$lang->bug->activatedCount = '激活次数';
-$lang->bug->activatedCountAB = '激活次数';
-$lang->bug->confirmed = '是否确认';
-$lang->bug->toTask = '转任务';
-$lang->bug->toStory = '转需求';
-$lang->bug->mailto = '抄送给';
-$lang->bug->openedBy = '由谁创建';
-$lang->bug->openedByAB = '创建';
-$lang->bug->openedDate = '创建日期';
-$lang->bug->openedDateAB = '创建日期';
-$lang->bug->openedBuild = '影响版本';
-$lang->bug->assignedTo = '指派给';
-$lang->bug->assignedDate = '指派日期';
-$lang->bug->resolvedBy = '解决者';
-$lang->bug->resolvedByAB = '解决';
-$lang->bug->resolution = '解决方案';
-$lang->bug->resolutionAB = '方案';
-$lang->bug->resolvedBuild = '解决版本';
-$lang->bug->resolvedDate = '解决日期';
-$lang->bug->resolvedDateAB = '解决日期';
-$lang->bug->closedBy = '由谁关闭';
-$lang->bug->closedDate = '关闭日期';
-$lang->bug->duplicateBug = '重复Bug';
-$lang->bug->lastEditedBy = '最后修改者';
-$lang->bug->lastEditedDate = '最后修改日期';
-$lang->bug->linkBug = '相关Bug';
-$lang->bug->case = '相关用例';
-$lang->bug->files = '附件';
-$lang->bug->keywords = '关键词';
-$lang->bug->lastEditedByAB = '修改者';
-$lang->bug->lastEditedDateAB = '修改日期';
-
-/* 方法列表。*/
-$lang->bug->index = '首页';
-$lang->bug->create = '创建Bug';
-$lang->bug->confirmBug = '确认';
-$lang->bug->edit = '编辑Bug';
-$lang->bug->browse = 'Bug列表';
-$lang->bug->view = 'Bug详情';
-$lang->bug->resolve = '解决Bug';
-$lang->bug->close = '关闭Bug';
-$lang->bug->activate = '激活Bug';
-$lang->bug->reportChart = '报表统计';
-$lang->bug->export = '导出数据';
-$lang->bug->delete = '删除Bug';
-$lang->bug->saveTemplate = '保存模板';
-$lang->bug->deleteTemplate = '删除模板';
-$lang->bug->customFields = '自定义字段';
-$lang->bug->restoreDefault = '恢复默认';
-$lang->bug->ajaxGetUserBugs = '接口:我的Bug';
-$lang->bug->ajaxGetModuleOwner = '接口:获得模块的默认指派人';
-$lang->bug->confirmStoryChange = '确认需求变动';
-
-/* 查询条件列表。*/
-$lang->bug->selectProduct = '请选择产品';
-$lang->bug->byModule = '按模块';
-$lang->bug->assignToMe = '指派给我';
-$lang->bug->openedByMe = '由我创建';
-$lang->bug->resolvedByMe = '由我解决';
-$lang->bug->closedByMe = '由我关闭';
-$lang->bug->assignToNull = '未指派';
-$lang->bug->unResolved = '未解决';
-$lang->bug->unclosed = '未关闭';
-$lang->bug->longLifeBugs = '久未处理';
-$lang->bug->postponedBugs = '被延期';
-$lang->bug->allBugs = '所有Bug';
-$lang->bug->moduleBugs = '按模块浏览';
-$lang->bug->byQuery = '搜索';
-$lang->bug->needConfirm = '需求变动';
-$lang->bug->allProduct = '所有产品';
-
-/* 页面标签。*/
-$lang->bug->lblProductAndModule = '产品模块';
-$lang->bug->lblProjectAndTask = '项目任务';
-$lang->bug->lblStory = '相关需求';
-$lang->bug->lblTypeAndSeverity = '类型/严重程度';
-$lang->bug->lblSystemBrowserAndHardware = '系统/浏览器';
-$lang->bug->lblAssignedTo = '当前指派';
-$lang->bug->lblMailto = '抄送给';
-$lang->bug->lblLastEdited = '最后修改';
-$lang->bug->lblResolved = '由谁解决';
-$lang->bug->lblAllFields = '所有字段';
-$lang->bug->lblCustomFields = '自定义字段';
-
-/* legend列表。*/
-$lang->bug->legendBasicInfo = '基本信息';
-$lang->bug->legendMailto = '抄送给';
-$lang->bug->legendAttatch = '附件';
-$lang->bug->legendLinkBugs = '相关Bug';
-$lang->bug->legendPrjStoryTask = '项目/需求/任务';
-$lang->bug->legendCases = '相关用例';
-$lang->bug->legendSteps = '重现步骤';
-$lang->bug->legendAction = '操作';
-$lang->bug->legendHistory = '历史记录';
-$lang->bug->legendComment = '备注';
-$lang->bug->legendLife = 'BUG的一生';
-$lang->bug->legendMisc = '其相关他';
-
-/* 功能按钮。*/
-$lang->bug->buttonConfirm = '确认';
-$lang->bug->buttonCopy = '复制';
-$lang->bug->buttonEdit = '编辑';
-$lang->bug->buttonActivate = '激活';
-$lang->bug->buttonResolve = '解决';
-$lang->bug->buttonClose = '关闭';
-$lang->bug->buttonToList = '返回';
-$lang->bug->buttonCreateTestcase = '建用例';
-
-/* 交互提示。*/
-$lang->bug->confirmChangeProduct = '修改产品会导致相应的项目、需求和任务发生变化,确定吗?';
-$lang->bug->confirmDelete = '您确认要删除该Bug吗?';
-$lang->bug->setTemplateTitle = '请输入bug模板标题(保存之前请先填写bug重现步骤):';
-$lang->bug->remindTask = '该Bug已经转化为任务,是否更新任务(编号:%s)状态 ?';
-
-/* 模板。*/
-$lang->bug->tplStep = "[步骤]
";
-$lang->bug->tplResult = "[结果]
";
-$lang->bug->tplExpect = "[期望]
";
-
-/* 各个字段取值列表。*/
-$lang->bug->severityList[3] = '3';
-$lang->bug->severityList[1] = '1';
-$lang->bug->severityList[2] = '2';
-$lang->bug->severityList[4] = '4';
-
-$lang->bug->priList[0] = '';
-$lang->bug->priList[3] = '3';
-$lang->bug->priList[1] = '1';
-$lang->bug->priList[2] = '2';
-$lang->bug->priList[4] = '4';
-
-$lang->bug->osList[''] = '';
-$lang->bug->osList['all'] = '全部';
-$lang->bug->osList['windows'] = 'Windows';
-$lang->bug->osList['winxp'] = 'Windows XP';
-$lang->bug->osList['win7'] = 'Windows 7';
-$lang->bug->osList['vista'] = 'Windows Vista';
-$lang->bug->osList['win2000'] = 'Windows 2000';
-$lang->bug->osList['win2003'] = 'Windows 2003';
-$lang->bug->osList['win2008'] = 'Windows 2008';
-$lang->bug->osList['winnt'] = 'Windows NT';
-$lang->bug->osList['win98'] = 'Windows 98';
-$lang->bug->osList['andriod'] = 'Andriod';
-$lang->bug->osList['ios'] = 'IOS';
-$lang->bug->osList['wp7'] = 'WP7';
-$lang->bug->osList['symbian'] = 'Symbian';
-$lang->bug->osList['linux'] = 'Linux';
-$lang->bug->osList['freebsd'] = 'FreeBSD';
-$lang->bug->osList['mac'] = 'Mac OS';
-$lang->bug->osList['unix'] = 'Unix';
-$lang->bug->osList['others'] = '其他';
-
-$lang->bug->browserList[''] = '';
-$lang->bug->browserList['all'] = '全部';
-$lang->bug->browserList['ie'] = 'IE系列';
-$lang->bug->browserList['ie8'] = 'IE8';
-$lang->bug->browserList['ie9'] = 'IE9';
-$lang->bug->browserList['ie6'] = 'IE6';
-$lang->bug->browserList['ie7'] = 'IE7';
-$lang->bug->browserList['chrome'] = 'chrome';
-$lang->bug->browserList['firefox'] = 'firefox系列';
-$lang->bug->browserList['firefox2'] = 'firefox2';
-$lang->bug->browserList['firefox3'] = 'firefox3';
-$lang->bug->browserList['firefox4'] = 'firefox4';
-$lang->bug->browserList['opera'] = 'opera系列';
-$lang->bug->browserList['opera9'] = 'opera9';
-$lang->bug->browserList['oprea10'] = 'opera10';
-$lang->bug->browserList['oprea11'] = 'opera11';
-$lang->bug->browserList['safari'] = 'safari';
-$lang->bug->browserList['maxthon'] = '傲游';
-$lang->bug->browserList['uc'] = 'UC';
-$lang->bug->browserList['other'] = '其他';
-
-$lang->bug->typeList[''] = '';
-$lang->bug->typeList['codeerror'] = '代码错误';
-$lang->bug->typeList['interface'] = '界面优化';
-$lang->bug->typeList['designchange'] = '设计变更';
-$lang->bug->typeList['newfeature'] = '新增需求';
-$lang->bug->typeList['designdefect'] = '设计缺陷';
-$lang->bug->typeList['config'] = '配置相关';
-$lang->bug->typeList['install'] = '安装部署';
-$lang->bug->typeList['security'] = '安全相关';
-$lang->bug->typeList['performance'] = '性能问题';
-$lang->bug->typeList['standard'] = '标准规范';
-$lang->bug->typeList['automation'] = '测试脚本';
-$lang->bug->typeList['trackthings'] = '事务跟踪';
-$lang->bug->typeList['others'] = '其他';
-
-$lang->bug->statusList[''] = '';
-$lang->bug->statusList['active'] = '激活';
-$lang->bug->statusList['resolved'] = '已解决';
-$lang->bug->statusList['closed'] = '已关闭';
-
-$lang->bug->confirmedList[1] = '已确认';
-$lang->bug->confirmedList[0] = '未确认';
-
-$lang->bug->resolutionList[''] = '';
-$lang->bug->resolutionList['bydesign'] = '设计如此';
-$lang->bug->resolutionList['duplicate'] = '重复Bug';
-$lang->bug->resolutionList['external'] = '外部原因';
-$lang->bug->resolutionList['fixed'] = '已解决';
-$lang->bug->resolutionList['notrepro'] = '无法重现';
-$lang->bug->resolutionList['postponed'] = '延期处理';
-$lang->bug->resolutionList['willnotfix'] = "不予解决";
-$lang->bug->resolutionList['tostory'] = '转为需求';
-
-/* 统计报表。*/
-$lang->bug->report->common = '统计报表';
-$lang->bug->report->select = '请选择报表类型';
-$lang->bug->report->create = '生成报表';
-$lang->bug->report->selectAll = '全选';
-$lang->bug->report->selectReverse = '反选';
-
-$lang->bug->report->charts['bugsPerProject'] = '项目Bug数量';
-$lang->bug->report->charts['bugsPerModule'] = '模块Bug数量';
-$lang->bug->report->charts['openedBugsPerDay'] = '每天新增Bug数';
-$lang->bug->report->charts['resolvedBugsPerDay'] = '每天解决Bug数';
-$lang->bug->report->charts['closedBugsPerDay'] = '每天关闭的Bug数';
-$lang->bug->report->charts['openedBugsPerUser'] = '每人提交的Bug数';
-$lang->bug->report->charts['resolvedBugsPerUser'] = '每人解决的Bug数';
-$lang->bug->report->charts['closedBugsPerUser'] = '每人关闭的Bug数';
-$lang->bug->report->charts['bugsPerSeverity'] = 'Bug严重程度统计';
-$lang->bug->report->charts['bugsPerResolution'] = 'Bug解决方案统计';
-$lang->bug->report->charts['bugsPerStatus'] = 'Bug状态统计';
-$lang->bug->report->charts['bugsPerActivatedCount'] = 'Bug激活次数统计';
-$lang->bug->report->charts['bugsPerType'] = 'Bug类型统计';
-$lang->bug->report->charts['bugsPerAssignedTo'] = '指派给统计';
-//$lang->bug->report->charts['bugLiveDays'] = 'Bug处理时间统计';
-//$lang->bug->report->charts['bugHistories'] = 'Bug处理步骤统计';
-
-$lang->bug->report->options->swf = 'pie2d';
-$lang->bug->report->options->width = 'auto';
-$lang->bug->report->options->height = 300;
-$lang->bug->report->options->graph->baseFontSize = 12;
-$lang->bug->report->options->graph->showNames = 1;
-$lang->bug->report->options->graph->formatNumber = 1;
-$lang->bug->report->options->graph->decimalPrecision = 0;
-$lang->bug->report->options->graph->animation = 0;
-$lang->bug->report->options->graph->rotateNames = 0;
-$lang->bug->report->options->graph->yAxisName = 'COUNT';
-$lang->bug->report->options->graph->pieRadius = 100; // 饼图直径。
-$lang->bug->report->options->graph->showColumnShadow = 0; // 是否显示柱状图阴影。
-
-$lang->bug->report->bugsPerProject->graph->xAxisName = '项目';
-$lang->bug->report->bugsPerModule->graph->xAxisName = '模块';
-
-$lang->bug->report->openedBugsPerDay->swf = 'column2d';
-$lang->bug->report->openedBugsPerDay->height = 400;
-$lang->bug->report->openedBugsPerDay->graph->xAxisName = '日期';
-$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->resolvedBugsPerDay->swf = 'column2d';
-$lang->bug->report->resolvedBugsPerDay->height = 400;
-$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = '日期';
-$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->closedBugsPerDay->swf = 'column2d';
-$lang->bug->report->closedBugsPerDay->height = 400;
-$lang->bug->report->closedBugsPerDay->graph->xAxisName = '日期';
-$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->openedBugsPerUser->graph->xAxisName = '用户';
-$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= '用户';
-$lang->bug->report->closedBugsPerUser->graph->xAxisName = '用户';
-
-$lang->bug->report->bugsPerSeverity->graph->xAxisName = '严重程度';
-$lang->bug->report->bugsPerResolution->graph->xAxisName = '解决方案';
-$lang->bug->report->bugsPerStatus->graph->xAxisName = '状态';
-$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = '激活次数';
-$lang->bug->report->bugsPerType->graph->xAxisName = '类型';
-$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = '指派给';
-$lang->bug->report->bugLiveDays->graph->xAxisName = '处理时间';
-$lang->bug->report->bugHistories->graph->xAxisName = '处理步骤';
-
-/* 操作记录。*/
-$lang->bug->action->resolved = array('main' => '$date, 由 $actor 解决,方案为 $extra 。', 'extra' => $lang->bug->resolutionList);
-$lang->bug->action->tostory = array('main' => '$date, 由 $actor 转为需求 ,编号为 $extra 。');
-$lang->bug->action->totask = array('main' => '$date, 由 $actor 导入为任务 ,编号为 $extra 。');
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+/* 字段列表。*/
+$lang->bug->common = '缺陷管理';
+$lang->bug->id = 'Bug编号';
+$lang->bug->product = '所属产品';
+$lang->bug->module = '所属模块';
+$lang->bug->path = '模块路径';
+$lang->bug->project = '所属项目';
+$lang->bug->story = '相关需求';
+$lang->bug->storyVersion = '需求版本';
+$lang->bug->task = '相关任务';
+$lang->bug->title = 'Bug标题';
+$lang->bug->severity = '严重程度';
+$lang->bug->severityAB = '级别';
+$lang->bug->pri = '优先级';
+$lang->bug->type = 'Bug类型';
+$lang->bug->os = '操作系统';
+$lang->bug->hardware = '硬件平台';
+$lang->bug->browser = '浏览器';
+$lang->bug->machine = '机器硬件';
+$lang->bug->found = '如何发现';
+$lang->bug->steps = '重现步骤';
+$lang->bug->status = 'Bug状态';
+$lang->bug->statusAB = '状态';
+$lang->bug->activatedCount = '激活次数';
+$lang->bug->activatedCountAB = '激活次数';
+$lang->bug->confirmed = '是否确认';
+$lang->bug->toTask = '转任务';
+$lang->bug->toStory = '转需求';
+$lang->bug->mailto = '抄送给';
+$lang->bug->openedBy = '由谁创建';
+$lang->bug->openedByAB = '创建';
+$lang->bug->openedDate = '创建日期';
+$lang->bug->openedDateAB = '创建日期';
+$lang->bug->openedBuild = '影响版本';
+$lang->bug->assignedTo = '指派给';
+$lang->bug->assignedDate = '指派日期';
+$lang->bug->resolvedBy = '解决者';
+$lang->bug->resolvedByAB = '解决';
+$lang->bug->resolution = '解决方案';
+$lang->bug->resolutionAB = '方案';
+$lang->bug->resolvedBuild = '解决版本';
+$lang->bug->resolvedDate = '解决日期';
+$lang->bug->resolvedDateAB = '解决日期';
+$lang->bug->closedBy = '由谁关闭';
+$lang->bug->closedDate = '关闭日期';
+$lang->bug->duplicateBug = '重复Bug';
+$lang->bug->lastEditedBy = '最后修改者';
+$lang->bug->lastEditedDate = '最后修改日期';
+$lang->bug->linkBug = '相关Bug';
+$lang->bug->case = '相关用例';
+$lang->bug->files = '附件';
+$lang->bug->keywords = '关键词';
+$lang->bug->lastEditedByAB = '修改者';
+$lang->bug->lastEditedDateAB = '修改日期';
+
+/* 方法列表。*/
+$lang->bug->index = '首页';
+$lang->bug->create = '创建Bug';
+$lang->bug->confirmBug = '确认';
+$lang->bug->edit = '编辑Bug';
+$lang->bug->browse = 'Bug列表';
+$lang->bug->view = 'Bug详情';
+$lang->bug->resolve = '解决Bug';
+$lang->bug->close = '关闭Bug';
+$lang->bug->activate = '激活Bug';
+$lang->bug->reportChart = '报表统计';
+$lang->bug->export = '导出数据';
+$lang->bug->delete = '删除Bug';
+$lang->bug->saveTemplate = '保存模板';
+$lang->bug->deleteTemplate = '删除模板';
+$lang->bug->customFields = '自定义字段';
+$lang->bug->restoreDefault = '恢复默认';
+$lang->bug->ajaxGetUserBugs = '接口:我的Bug';
+$lang->bug->ajaxGetModuleOwner = '接口:获得模块的默认指派人';
+$lang->bug->confirmStoryChange = '确认需求变动';
+
+/* 查询条件列表。*/
+$lang->bug->selectProduct = '请选择产品';
+$lang->bug->byModule = '按模块';
+$lang->bug->assignToMe = '指派给我';
+$lang->bug->openedByMe = '由我创建';
+$lang->bug->resolvedByMe = '由我解决';
+$lang->bug->closedByMe = '由我关闭';
+$lang->bug->assignToNull = '未指派';
+$lang->bug->unResolved = '未解决';
+$lang->bug->unclosed = '未关闭';
+$lang->bug->longLifeBugs = '久未处理';
+$lang->bug->postponedBugs = '被延期';
+$lang->bug->allBugs = '所有Bug';
+$lang->bug->moduleBugs = '按模块浏览';
+$lang->bug->byQuery = '搜索';
+$lang->bug->needConfirm = '需求变动';
+$lang->bug->allProduct = '所有产品';
+
+/* 页面标签。*/
+$lang->bug->lblProductAndModule = '产品模块';
+$lang->bug->lblProjectAndTask = '项目任务';
+$lang->bug->lblStory = '相关需求';
+$lang->bug->lblTypeAndSeverity = '类型/严重程度';
+$lang->bug->lblSystemBrowserAndHardware = '系统/浏览器';
+$lang->bug->lblAssignedTo = '当前指派';
+$lang->bug->lblMailto = '抄送给';
+$lang->bug->lblLastEdited = '最后修改';
+$lang->bug->lblResolved = '由谁解决';
+$lang->bug->lblAllFields = '所有字段';
+$lang->bug->lblCustomFields = '自定义字段';
+
+/* legend列表。*/
+$lang->bug->legendBasicInfo = '基本信息';
+$lang->bug->legendMailto = '抄送给';
+$lang->bug->legendAttatch = '附件';
+$lang->bug->legendLinkBugs = '相关Bug';
+$lang->bug->legendPrjStoryTask = '项目/需求/任务';
+$lang->bug->legendCases = '相关用例';
+$lang->bug->legendSteps = '重现步骤';
+$lang->bug->legendAction = '操作';
+$lang->bug->legendHistory = '历史记录';
+$lang->bug->legendComment = '备注';
+$lang->bug->legendLife = 'BUG的一生';
+$lang->bug->legendMisc = '其相关他';
+
+/* 功能按钮。*/
+$lang->bug->buttonConfirm = '确认';
+$lang->bug->buttonCopy = '复制';
+$lang->bug->buttonEdit = '编辑';
+$lang->bug->buttonActivate = '激活';
+$lang->bug->buttonResolve = '解决';
+$lang->bug->buttonClose = '关闭';
+$lang->bug->buttonToList = '返回';
+$lang->bug->buttonCreateTestcase = '建用例';
+
+/* 交互提示。*/
+$lang->bug->confirmChangeProduct = '修改产品会导致相应的项目、需求和任务发生变化,确定吗?';
+$lang->bug->confirmDelete = '您确认要删除该Bug吗?';
+$lang->bug->setTemplateTitle = '请输入bug模板标题(保存之前请先填写bug重现步骤):';
+$lang->bug->remindTask = '该Bug已经转化为任务,是否更新任务(编号:%s)状态 ?';
+
+/* 模板。*/
+$lang->bug->tplStep = "[步骤]
";
+$lang->bug->tplResult = "[结果]
";
+$lang->bug->tplExpect = "[期望]
";
+
+/* 各个字段取值列表。*/
+$lang->bug->severityList[3] = '3';
+$lang->bug->severityList[1] = '1';
+$lang->bug->severityList[2] = '2';
+$lang->bug->severityList[4] = '4';
+
+$lang->bug->priList[0] = '';
+$lang->bug->priList[3] = '3';
+$lang->bug->priList[1] = '1';
+$lang->bug->priList[2] = '2';
+$lang->bug->priList[4] = '4';
+
+$lang->bug->osList[''] = '';
+$lang->bug->osList['all'] = '全部';
+$lang->bug->osList['windows'] = 'Windows';
+$lang->bug->osList['winxp'] = 'Windows XP';
+$lang->bug->osList['win7'] = 'Windows 7';
+$lang->bug->osList['vista'] = 'Windows Vista';
+$lang->bug->osList['win2000'] = 'Windows 2000';
+$lang->bug->osList['win2003'] = 'Windows 2003';
+$lang->bug->osList['win2008'] = 'Windows 2008';
+$lang->bug->osList['winnt'] = 'Windows NT';
+$lang->bug->osList['win98'] = 'Windows 98';
+$lang->bug->osList['andriod'] = 'Andriod';
+$lang->bug->osList['ios'] = 'IOS';
+$lang->bug->osList['wp7'] = 'WP7';
+$lang->bug->osList['symbian'] = 'Symbian';
+$lang->bug->osList['linux'] = 'Linux';
+$lang->bug->osList['freebsd'] = 'FreeBSD';
+$lang->bug->osList['mac'] = 'Mac OS';
+$lang->bug->osList['unix'] = 'Unix';
+$lang->bug->osList['others'] = '其他';
+
+$lang->bug->browserList[''] = '';
+$lang->bug->browserList['all'] = '全部';
+$lang->bug->browserList['ie'] = 'IE系列';
+$lang->bug->browserList['ie8'] = 'IE8';
+$lang->bug->browserList['ie9'] = 'IE9';
+$lang->bug->browserList['ie6'] = 'IE6';
+$lang->bug->browserList['ie7'] = 'IE7';
+$lang->bug->browserList['chrome'] = 'chrome';
+$lang->bug->browserList['firefox'] = 'firefox系列';
+$lang->bug->browserList['firefox2'] = 'firefox2';
+$lang->bug->browserList['firefox3'] = 'firefox3';
+$lang->bug->browserList['firefox4'] = 'firefox4';
+$lang->bug->browserList['opera'] = 'opera系列';
+$lang->bug->browserList['opera9'] = 'opera9';
+$lang->bug->browserList['oprea10'] = 'opera10';
+$lang->bug->browserList['oprea11'] = 'opera11';
+$lang->bug->browserList['safari'] = 'safari';
+$lang->bug->browserList['maxthon'] = '傲游';
+$lang->bug->browserList['uc'] = 'UC';
+$lang->bug->browserList['other'] = '其他';
+
+$lang->bug->typeList[''] = '';
+$lang->bug->typeList['codeerror'] = '代码错误';
+$lang->bug->typeList['interface'] = '界面优化';
+$lang->bug->typeList['designchange'] = '设计变更';
+$lang->bug->typeList['newfeature'] = '新增需求';
+$lang->bug->typeList['designdefect'] = '设计缺陷';
+$lang->bug->typeList['config'] = '配置相关';
+$lang->bug->typeList['install'] = '安装部署';
+$lang->bug->typeList['security'] = '安全相关';
+$lang->bug->typeList['performance'] = '性能问题';
+$lang->bug->typeList['standard'] = '标准规范';
+$lang->bug->typeList['automation'] = '测试脚本';
+$lang->bug->typeList['trackthings'] = '事务跟踪';
+$lang->bug->typeList['others'] = '其他';
+
+$lang->bug->statusList[''] = '';
+$lang->bug->statusList['active'] = '激活';
+$lang->bug->statusList['resolved'] = '已解决';
+$lang->bug->statusList['closed'] = '已关闭';
+
+$lang->bug->confirmedList[1] = '已确认';
+$lang->bug->confirmedList[0] = '未确认';
+
+$lang->bug->resolutionList[''] = '';
+$lang->bug->resolutionList['bydesign'] = '设计如此';
+$lang->bug->resolutionList['duplicate'] = '重复Bug';
+$lang->bug->resolutionList['external'] = '外部原因';
+$lang->bug->resolutionList['fixed'] = '已解决';
+$lang->bug->resolutionList['notrepro'] = '无法重现';
+$lang->bug->resolutionList['postponed'] = '延期处理';
+$lang->bug->resolutionList['willnotfix'] = "不予解决";
+$lang->bug->resolutionList['tostory'] = '转为需求';
+
+/* 统计报表。*/
+$lang->bug->report->common = '统计报表';
+$lang->bug->report->select = '请选择报表类型';
+$lang->bug->report->create = '生成报表';
+$lang->bug->report->selectAll = '全选';
+$lang->bug->report->selectReverse = '反选';
+
+$lang->bug->report->charts['bugsPerProject'] = '项目Bug数量';
+$lang->bug->report->charts['bugsPerModule'] = '模块Bug数量';
+$lang->bug->report->charts['openedBugsPerDay'] = '每天新增Bug数';
+$lang->bug->report->charts['resolvedBugsPerDay'] = '每天解决Bug数';
+$lang->bug->report->charts['closedBugsPerDay'] = '每天关闭的Bug数';
+$lang->bug->report->charts['openedBugsPerUser'] = '每人提交的Bug数';
+$lang->bug->report->charts['resolvedBugsPerUser'] = '每人解决的Bug数';
+$lang->bug->report->charts['closedBugsPerUser'] = '每人关闭的Bug数';
+$lang->bug->report->charts['bugsPerSeverity'] = 'Bug严重程度统计';
+$lang->bug->report->charts['bugsPerResolution'] = 'Bug解决方案统计';
+$lang->bug->report->charts['bugsPerStatus'] = 'Bug状态统计';
+$lang->bug->report->charts['bugsPerActivatedCount'] = 'Bug激活次数统计';
+$lang->bug->report->charts['bugsPerType'] = 'Bug类型统计';
+$lang->bug->report->charts['bugsPerAssignedTo'] = '指派给统计';
+//$lang->bug->report->charts['bugLiveDays'] = 'Bug处理时间统计';
+//$lang->bug->report->charts['bugHistories'] = 'Bug处理步骤统计';
+
+$lang->bug->report->options->swf = 'pie2d';
+$lang->bug->report->options->width = 'auto';
+$lang->bug->report->options->height = 300;
+$lang->bug->report->options->graph->baseFontSize = 12;
+$lang->bug->report->options->graph->showNames = 1;
+$lang->bug->report->options->graph->formatNumber = 1;
+$lang->bug->report->options->graph->decimalPrecision = 0;
+$lang->bug->report->options->graph->animation = 0;
+$lang->bug->report->options->graph->rotateNames = 0;
+$lang->bug->report->options->graph->yAxisName = 'COUNT';
+$lang->bug->report->options->graph->pieRadius = 100; // 饼图直径。
+$lang->bug->report->options->graph->showColumnShadow = 0; // 是否显示柱状图阴影。
+
+$lang->bug->report->bugsPerProject->graph->xAxisName = '项目';
+$lang->bug->report->bugsPerModule->graph->xAxisName = '模块';
+
+$lang->bug->report->openedBugsPerDay->swf = 'column2d';
+$lang->bug->report->openedBugsPerDay->height = 400;
+$lang->bug->report->openedBugsPerDay->graph->xAxisName = '日期';
+$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->resolvedBugsPerDay->swf = 'column2d';
+$lang->bug->report->resolvedBugsPerDay->height = 400;
+$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = '日期';
+$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->closedBugsPerDay->swf = 'column2d';
+$lang->bug->report->closedBugsPerDay->height = 400;
+$lang->bug->report->closedBugsPerDay->graph->xAxisName = '日期';
+$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->openedBugsPerUser->graph->xAxisName = '用户';
+$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= '用户';
+$lang->bug->report->closedBugsPerUser->graph->xAxisName = '用户';
+
+$lang->bug->report->bugsPerSeverity->graph->xAxisName = '严重程度';
+$lang->bug->report->bugsPerResolution->graph->xAxisName = '解决方案';
+$lang->bug->report->bugsPerStatus->graph->xAxisName = '状态';
+$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = '激活次数';
+$lang->bug->report->bugsPerType->graph->xAxisName = '类型';
+$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = '指派给';
+$lang->bug->report->bugLiveDays->graph->xAxisName = '处理时间';
+$lang->bug->report->bugHistories->graph->xAxisName = '处理步骤';
+
+/* 操作记录。*/
+$lang->bug->action->resolved = array('main' => '$date, 由 $actor 解决,方案为 $extra 。', 'extra' => $lang->bug->resolutionList);
+$lang->bug->action->tostory = array('main' => '$date, 由 $actor 转为需求 ,编号为 $extra 。');
+$lang->bug->action->totask = array('main' => '$date, 由 $actor 导入为任务 ,编号为 $extra 。');
diff --git a/module/bug/lang/zh-tw.php b/module/bug/lang/zh-tw.php
index 0c02335474..c9e9f4e91a 100644
--- a/module/bug/lang/zh-tw.php
+++ b/module/bug/lang/zh-tw.php
@@ -1,312 +1,312 @@
-
- * @package bug
- * @version $Id: zh-tw.php 2484 2011-12-27 08:45:57Z shiyangyangwork@yahoo.cn $
- * @link http://www.zentao.net
- */
-/* 欄位列表。*/
-$lang->bug->common = '缺陷管理';
-$lang->bug->id = 'Bug編號';
-$lang->bug->product = '所屬產品';
-$lang->bug->module = '所屬模組';
-$lang->bug->path = '模組路徑';
-$lang->bug->project = '所屬項目';
-$lang->bug->story = '相關需求';
-$lang->bug->storyVersion = '需求版本';
-$lang->bug->task = '相關任務';
-$lang->bug->title = 'Bug標題';
-$lang->bug->severity = '嚴重程度';
-$lang->bug->severityAB = '級別';
-$lang->bug->pri = '優先順序';
-$lang->bug->type = 'Bug類型';
-$lang->bug->os = '操作系統';
-$lang->bug->hardware = '硬件平台';
-$lang->bug->browser = '瀏覽器';
-$lang->bug->machine = '機器硬件';
-$lang->bug->found = '如何發現';
-$lang->bug->steps = '重現步驟';
-$lang->bug->status = 'Bug狀態';
-$lang->bug->statusAB = '狀態';
-$lang->bug->activatedCount = '激活次數';
-$lang->bug->activatedCountAB = '激活次數';
-$lang->bug->confirmed = '是否確認';
-$lang->bug->toTask = '轉任務';
-$lang->bug->toStory = '轉需求';
-$lang->bug->mailto = '抄送給';
-$lang->bug->openedBy = '由誰創建';
-$lang->bug->openedByAB = '創建';
-$lang->bug->openedDate = '創建日期';
-$lang->bug->openedDateAB = '創建日期';
-$lang->bug->openedBuild = '影響版本';
-$lang->bug->assignedTo = '指派給';
-$lang->bug->assignedDate = '指派日期';
-$lang->bug->resolvedBy = '解決者';
-$lang->bug->resolvedByAB = '解決';
-$lang->bug->resolution = '解決方案';
-$lang->bug->resolutionAB = '方案';
-$lang->bug->resolvedBuild = '解決版本';
-$lang->bug->resolvedDate = '解決日期';
-$lang->bug->resolvedDateAB = '解決日期';
-$lang->bug->closedBy = '由誰關閉';
-$lang->bug->closedDate = '關閉日期';
-$lang->bug->duplicateBug = '重複Bug';
-$lang->bug->lastEditedBy = '最後修改者';
-$lang->bug->lastEditedDate = '最後修改日期';
-$lang->bug->linkBug = '相關Bug';
-$lang->bug->case = '相關用例';
-$lang->bug->files = '附件';
-$lang->bug->keywords = '關鍵詞';
-$lang->bug->lastEditedByAB = '修改者';
-$lang->bug->lastEditedDateAB = '修改日期';
-
-/* 方法列表。*/
-$lang->bug->index = '首頁';
-$lang->bug->create = '創建Bug';
-$lang->bug->confirmBug = '確認';
-$lang->bug->edit = '編輯Bug';
-$lang->bug->browse = 'Bug列表';
-$lang->bug->view = 'Bug詳情';
-$lang->bug->resolve = '解決Bug';
-$lang->bug->close = '關閉Bug';
-$lang->bug->activate = '激活Bug';
-$lang->bug->reportChart = '報表統計';
-$lang->bug->export = '導出數據';
-$lang->bug->delete = '刪除Bug';
-$lang->bug->saveTemplate = '保存模板';
-$lang->bug->deleteTemplate = '刪除模板';
-$lang->bug->customFields = '自定義欄位';
-$lang->bug->restoreDefault = '恢復預設';
-$lang->bug->ajaxGetUserBugs = '介面:我的Bug';
-$lang->bug->ajaxGetModuleOwner = '介面:獲得模組的預設指派人';
-$lang->bug->confirmStoryChange = '確認需求變動';
-
-/* 查詢條件列表。*/
-$lang->bug->selectProduct = '請選擇產品';
-$lang->bug->byModule = '按模組';
-$lang->bug->assignToMe = '指派給我';
-$lang->bug->openedByMe = '由我創建';
-$lang->bug->resolvedByMe = '由我解決';
-$lang->bug->closedByMe = '由我關閉';
-$lang->bug->assignToNull = '未指派';
-$lang->bug->unResolved = '未解決';
-$lang->bug->unclosed = '未關閉';
-$lang->bug->longLifeBugs = '久未處理';
-$lang->bug->postponedBugs = '被延期';
-$lang->bug->allBugs = '所有Bug';
-$lang->bug->moduleBugs = '按模組瀏覽';
-$lang->bug->byQuery = '搜索';
-$lang->bug->needConfirm = '需求變動';
-$lang->bug->allProduct = '所有產品';
-
-/* 頁面標籤。*/
-$lang->bug->lblProductAndModule = '產品模組';
-$lang->bug->lblProjectAndTask = '項目任務';
-$lang->bug->lblStory = '相關需求';
-$lang->bug->lblTypeAndSeverity = '類型/嚴重程度';
-$lang->bug->lblSystemBrowserAndHardware = '系統/瀏覽器';
-$lang->bug->lblAssignedTo = '當前指派';
-$lang->bug->lblMailto = '抄送給';
-$lang->bug->lblLastEdited = '最後修改';
-$lang->bug->lblResolved = '由誰解決';
-$lang->bug->lblAllFields = '所有欄位';
-$lang->bug->lblCustomFields = '自定義欄位';
-
-/* legend列表。*/
-$lang->bug->legendBasicInfo = '基本信息';
-$lang->bug->legendMailto = '抄送給';
-$lang->bug->legendAttatch = '附件';
-$lang->bug->legendLinkBugs = '相關Bug';
-$lang->bug->legendPrjStoryTask = '項目/需求/任務';
-$lang->bug->legendCases = '相關用例';
-$lang->bug->legendSteps = '重現步驟';
-$lang->bug->legendAction = '操作';
-$lang->bug->legendHistory = '歷史記錄';
-$lang->bug->legendComment = '備註';
-$lang->bug->legendLife = 'BUG的一生';
-$lang->bug->legendMisc = '其相關他';
-
-/* 功能按鈕。*/
-$lang->bug->buttonConfirm = '確認';
-$lang->bug->buttonCopy = '複製';
-$lang->bug->buttonEdit = '編輯';
-$lang->bug->buttonActivate = '激活';
-$lang->bug->buttonResolve = '解決';
-$lang->bug->buttonClose = '關閉';
-$lang->bug->buttonToList = '返回';
-$lang->bug->buttonCreateTestcase = '建用例';
-
-/* 交互提示。*/
-$lang->bug->confirmChangeProduct = '修改產品會導致相應的項目、需求和任務發生變化,確定嗎?';
-$lang->bug->confirmDelete = '您確認要刪除該Bug嗎?';
-$lang->bug->setTemplateTitle = '請輸入bug模板標題(保存之前請先填寫bug重現步驟):';
-$lang->bug->remindTask = '該Bug已經轉化為任務,是否更新任務(編號:%s)狀態 ?';
-
-/* 模板。*/
-$lang->bug->tplStep = "[步驟]
";
-$lang->bug->tplResult = "[結果]
";
-$lang->bug->tplExpect = "[期望]
";
-
-/* 各個欄位取值列表。*/
-$lang->bug->severityList[3] = '3';
-$lang->bug->severityList[1] = '1';
-$lang->bug->severityList[2] = '2';
-$lang->bug->severityList[4] = '4';
-
-$lang->bug->priList[0] = '';
-$lang->bug->priList[3] = '3';
-$lang->bug->priList[1] = '1';
-$lang->bug->priList[2] = '2';
-$lang->bug->priList[4] = '4';
-
-$lang->bug->osList[''] = '';
-$lang->bug->osList['all'] = '全部';
-$lang->bug->osList['windows'] = 'Windows';
-$lang->bug->osList['winxp'] = 'Windows XP';
-$lang->bug->osList['win7'] = 'Windows 7';
-$lang->bug->osList['vista'] = 'Windows Vista';
-$lang->bug->osList['win2000'] = 'Windows 2000';
-$lang->bug->osList['win2003'] = 'Windows 2003';
-$lang->bug->osList['win2008'] = 'Windows 2008';
-$lang->bug->osList['winnt'] = 'Windows NT';
-$lang->bug->osList['win98'] = 'Windows 98';
-$lang->bug->osList['andriod'] = 'Andriod';
-$lang->bug->osList['ios'] = 'IOS';
-$lang->bug->osList['wp7'] = 'WP7';
-$lang->bug->osList['symbian'] = 'Symbian';
-$lang->bug->osList['linux'] = 'Linux';
-$lang->bug->osList['freebsd'] = 'FreeBSD';
-$lang->bug->osList['mac'] = 'Mac OS';
-$lang->bug->osList['unix'] = 'Unix';
-$lang->bug->osList['others'] = '其他';
-
-$lang->bug->browserList[''] = '';
-$lang->bug->browserList['all'] = '全部';
-$lang->bug->browserList['ie'] = 'IE系列';
-$lang->bug->browserList['ie8'] = 'IE8';
-$lang->bug->browserList['ie9'] = 'IE9';
-$lang->bug->browserList['ie6'] = 'IE6';
-$lang->bug->browserList['ie7'] = 'IE7';
-$lang->bug->browserList['chrome'] = 'chrome';
-$lang->bug->browserList['firefox'] = 'firefox系列';
-$lang->bug->browserList['firefox2'] = 'firefox2';
-$lang->bug->browserList['firefox3'] = 'firefox3';
-$lang->bug->browserList['firefox4'] = 'firefox4';
-$lang->bug->browserList['opera'] = 'opera系列';
-$lang->bug->browserList['opera9'] = 'opera9';
-$lang->bug->browserList['oprea10'] = 'opera10';
-$lang->bug->browserList['oprea11'] = 'opera11';
-$lang->bug->browserList['safari'] = 'safari';
-$lang->bug->browserList['maxthon'] = '傲游';
-$lang->bug->browserList['uc'] = 'UC';
-$lang->bug->browserList['other'] = '其他';
-
-$lang->bug->typeList[''] = '';
-$lang->bug->typeList['codeerror'] = '代碼錯誤';
-$lang->bug->typeList['interface'] = '界面優化';
-$lang->bug->typeList['designchange'] = '設計變更';
-$lang->bug->typeList['newfeature'] = '新增需求';
-$lang->bug->typeList['designdefect'] = '設計缺陷';
-$lang->bug->typeList['config'] = '配置相關';
-$lang->bug->typeList['install'] = '安裝部署';
-$lang->bug->typeList['security'] = '安全相關';
-$lang->bug->typeList['performance'] = '性能問題';
-$lang->bug->typeList['standard'] = '標準規範';
-$lang->bug->typeList['automation'] = '測試腳本';
-$lang->bug->typeList['trackthings'] = '事務跟蹤';
-$lang->bug->typeList['others'] = '其他';
-
-$lang->bug->statusList[''] = '';
-$lang->bug->statusList['active'] = '激活';
-$lang->bug->statusList['resolved'] = '已解決';
-$lang->bug->statusList['closed'] = '已關閉';
-
-$lang->bug->confirmedList[1] = '已確認';
-$lang->bug->confirmedList[0] = '未確認';
-
-$lang->bug->resolutionList[''] = '';
-$lang->bug->resolutionList['bydesign'] = '設計如此';
-$lang->bug->resolutionList['duplicate'] = '重複Bug';
-$lang->bug->resolutionList['external'] = '外部原因';
-$lang->bug->resolutionList['fixed'] = '已解決';
-$lang->bug->resolutionList['notrepro'] = '無法重現';
-$lang->bug->resolutionList['postponed'] = '延期處理';
-$lang->bug->resolutionList['willnotfix'] = "不予解決";
-$lang->bug->resolutionList['tostory'] = '轉為需求';
-
-/* 統計報表。*/
-$lang->bug->report->common = '統計報表';
-$lang->bug->report->select = '請選擇報表類型';
-$lang->bug->report->create = '生成報表';
-$lang->bug->report->selectAll = '全選';
-$lang->bug->report->selectReverse = '反選';
-
-$lang->bug->report->charts['bugsPerProject'] = '項目Bug數量';
-$lang->bug->report->charts['bugsPerModule'] = '模組Bug數量';
-$lang->bug->report->charts['openedBugsPerDay'] = '每天新增Bug數';
-$lang->bug->report->charts['resolvedBugsPerDay'] = '每天解決Bug數';
-$lang->bug->report->charts['closedBugsPerDay'] = '每天關閉的Bug數';
-$lang->bug->report->charts['openedBugsPerUser'] = '每人提交的Bug數';
-$lang->bug->report->charts['resolvedBugsPerUser'] = '每人解決的Bug數';
-$lang->bug->report->charts['closedBugsPerUser'] = '每人關閉的Bug數';
-$lang->bug->report->charts['bugsPerSeverity'] = 'Bug嚴重程度統計';
-$lang->bug->report->charts['bugsPerResolution'] = 'Bug解決方案統計';
-$lang->bug->report->charts['bugsPerStatus'] = 'Bug狀態統計';
-$lang->bug->report->charts['bugsPerActivatedCount'] = 'Bug激活次數統計';
-$lang->bug->report->charts['bugsPerType'] = 'Bug類型統計';
-$lang->bug->report->charts['bugsPerAssignedTo'] = '指派給統計';
-//$lang->bug->report->charts['bugLiveDays'] = 'Bug處理時間統計';
-//$lang->bug->report->charts['bugHistories'] = 'Bug處理步驟統計';
-
-$lang->bug->report->options->swf = 'pie2d';
-$lang->bug->report->options->width = 'auto';
-$lang->bug->report->options->height = 300;
-$lang->bug->report->options->graph->baseFontSize = 12;
-$lang->bug->report->options->graph->showNames = 1;
-$lang->bug->report->options->graph->formatNumber = 1;
-$lang->bug->report->options->graph->decimalPrecision = 0;
-$lang->bug->report->options->graph->animation = 0;
-$lang->bug->report->options->graph->rotateNames = 0;
-$lang->bug->report->options->graph->yAxisName = 'COUNT';
-$lang->bug->report->options->graph->pieRadius = 100; // 餅圖直徑。
-$lang->bug->report->options->graph->showColumnShadow = 0; // 是否顯示柱狀圖陰影。
-
-$lang->bug->report->bugsPerProject->graph->xAxisName = '項目';
-$lang->bug->report->bugsPerModule->graph->xAxisName = '模組';
-
-$lang->bug->report->openedBugsPerDay->swf = 'column2d';
-$lang->bug->report->openedBugsPerDay->height = 400;
-$lang->bug->report->openedBugsPerDay->graph->xAxisName = '日期';
-$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->resolvedBugsPerDay->swf = 'column2d';
-$lang->bug->report->resolvedBugsPerDay->height = 400;
-$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = '日期';
-$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->closedBugsPerDay->swf = 'column2d';
-$lang->bug->report->closedBugsPerDay->height = 400;
-$lang->bug->report->closedBugsPerDay->graph->xAxisName = '日期';
-$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1;
-
-$lang->bug->report->openedBugsPerUser->graph->xAxisName = '用戶';
-$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= '用戶';
-$lang->bug->report->closedBugsPerUser->graph->xAxisName = '用戶';
-
-$lang->bug->report->bugsPerSeverity->graph->xAxisName = '嚴重程度';
-$lang->bug->report->bugsPerResolution->graph->xAxisName = '解決方案';
-$lang->bug->report->bugsPerStatus->graph->xAxisName = '狀態';
-$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = '激活次數';
-$lang->bug->report->bugsPerType->graph->xAxisName = '類型';
-$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = '指派給';
-$lang->bug->report->bugLiveDays->graph->xAxisName = '處理時間';
-$lang->bug->report->bugHistories->graph->xAxisName = '處理步驟';
-
-/* 操作記錄。*/
-$lang->bug->action->resolved = array('main' => '$date, 由 $actor 解決,方案為 $extra 。', 'extra' => $lang->bug->resolutionList);
-$lang->bug->action->tostory = array('main' => '$date, 由 $actor 轉為需求 ,編號為 $extra 。');
-$lang->bug->action->totask = array('main' => '$date, 由 $actor 導入為任務 ,編號為 $extra 。');
+
+ * @package bug
+ * @version $Id: zh-tw.php 2484 2011-12-27 08:45:57Z shiyangyangwork@yahoo.cn $
+ * @link http://www.zentao.net
+ */
+/* 欄位列表。*/
+$lang->bug->common = '缺陷管理';
+$lang->bug->id = 'Bug編號';
+$lang->bug->product = '所屬產品';
+$lang->bug->module = '所屬模組';
+$lang->bug->path = '模組路徑';
+$lang->bug->project = '所屬項目';
+$lang->bug->story = '相關需求';
+$lang->bug->storyVersion = '需求版本';
+$lang->bug->task = '相關任務';
+$lang->bug->title = 'Bug標題';
+$lang->bug->severity = '嚴重程度';
+$lang->bug->severityAB = '級別';
+$lang->bug->pri = '優先順序';
+$lang->bug->type = 'Bug類型';
+$lang->bug->os = '操作系統';
+$lang->bug->hardware = '硬件平台';
+$lang->bug->browser = '瀏覽器';
+$lang->bug->machine = '機器硬件';
+$lang->bug->found = '如何發現';
+$lang->bug->steps = '重現步驟';
+$lang->bug->status = 'Bug狀態';
+$lang->bug->statusAB = '狀態';
+$lang->bug->activatedCount = '激活次數';
+$lang->bug->activatedCountAB = '激活次數';
+$lang->bug->confirmed = '是否確認';
+$lang->bug->toTask = '轉任務';
+$lang->bug->toStory = '轉需求';
+$lang->bug->mailto = '抄送給';
+$lang->bug->openedBy = '由誰創建';
+$lang->bug->openedByAB = '創建';
+$lang->bug->openedDate = '創建日期';
+$lang->bug->openedDateAB = '創建日期';
+$lang->bug->openedBuild = '影響版本';
+$lang->bug->assignedTo = '指派給';
+$lang->bug->assignedDate = '指派日期';
+$lang->bug->resolvedBy = '解決者';
+$lang->bug->resolvedByAB = '解決';
+$lang->bug->resolution = '解決方案';
+$lang->bug->resolutionAB = '方案';
+$lang->bug->resolvedBuild = '解決版本';
+$lang->bug->resolvedDate = '解決日期';
+$lang->bug->resolvedDateAB = '解決日期';
+$lang->bug->closedBy = '由誰關閉';
+$lang->bug->closedDate = '關閉日期';
+$lang->bug->duplicateBug = '重複Bug';
+$lang->bug->lastEditedBy = '最後修改者';
+$lang->bug->lastEditedDate = '最後修改日期';
+$lang->bug->linkBug = '相關Bug';
+$lang->bug->case = '相關用例';
+$lang->bug->files = '附件';
+$lang->bug->keywords = '關鍵詞';
+$lang->bug->lastEditedByAB = '修改者';
+$lang->bug->lastEditedDateAB = '修改日期';
+
+/* 方法列表。*/
+$lang->bug->index = '首頁';
+$lang->bug->create = '創建Bug';
+$lang->bug->confirmBug = '確認';
+$lang->bug->edit = '編輯Bug';
+$lang->bug->browse = 'Bug列表';
+$lang->bug->view = 'Bug詳情';
+$lang->bug->resolve = '解決Bug';
+$lang->bug->close = '關閉Bug';
+$lang->bug->activate = '激活Bug';
+$lang->bug->reportChart = '報表統計';
+$lang->bug->export = '導出數據';
+$lang->bug->delete = '刪除Bug';
+$lang->bug->saveTemplate = '保存模板';
+$lang->bug->deleteTemplate = '刪除模板';
+$lang->bug->customFields = '自定義欄位';
+$lang->bug->restoreDefault = '恢復預設';
+$lang->bug->ajaxGetUserBugs = '介面:我的Bug';
+$lang->bug->ajaxGetModuleOwner = '介面:獲得模組的預設指派人';
+$lang->bug->confirmStoryChange = '確認需求變動';
+
+/* 查詢條件列表。*/
+$lang->bug->selectProduct = '請選擇產品';
+$lang->bug->byModule = '按模組';
+$lang->bug->assignToMe = '指派給我';
+$lang->bug->openedByMe = '由我創建';
+$lang->bug->resolvedByMe = '由我解決';
+$lang->bug->closedByMe = '由我關閉';
+$lang->bug->assignToNull = '未指派';
+$lang->bug->unResolved = '未解決';
+$lang->bug->unclosed = '未關閉';
+$lang->bug->longLifeBugs = '久未處理';
+$lang->bug->postponedBugs = '被延期';
+$lang->bug->allBugs = '所有Bug';
+$lang->bug->moduleBugs = '按模組瀏覽';
+$lang->bug->byQuery = '搜索';
+$lang->bug->needConfirm = '需求變動';
+$lang->bug->allProduct = '所有產品';
+
+/* 頁面標籤。*/
+$lang->bug->lblProductAndModule = '產品模組';
+$lang->bug->lblProjectAndTask = '項目任務';
+$lang->bug->lblStory = '相關需求';
+$lang->bug->lblTypeAndSeverity = '類型/嚴重程度';
+$lang->bug->lblSystemBrowserAndHardware = '系統/瀏覽器';
+$lang->bug->lblAssignedTo = '當前指派';
+$lang->bug->lblMailto = '抄送給';
+$lang->bug->lblLastEdited = '最後修改';
+$lang->bug->lblResolved = '由誰解決';
+$lang->bug->lblAllFields = '所有欄位';
+$lang->bug->lblCustomFields = '自定義欄位';
+
+/* legend列表。*/
+$lang->bug->legendBasicInfo = '基本信息';
+$lang->bug->legendMailto = '抄送給';
+$lang->bug->legendAttatch = '附件';
+$lang->bug->legendLinkBugs = '相關Bug';
+$lang->bug->legendPrjStoryTask = '項目/需求/任務';
+$lang->bug->legendCases = '相關用例';
+$lang->bug->legendSteps = '重現步驟';
+$lang->bug->legendAction = '操作';
+$lang->bug->legendHistory = '歷史記錄';
+$lang->bug->legendComment = '備註';
+$lang->bug->legendLife = 'BUG的一生';
+$lang->bug->legendMisc = '其相關他';
+
+/* 功能按鈕。*/
+$lang->bug->buttonConfirm = '確認';
+$lang->bug->buttonCopy = '複製';
+$lang->bug->buttonEdit = '編輯';
+$lang->bug->buttonActivate = '激活';
+$lang->bug->buttonResolve = '解決';
+$lang->bug->buttonClose = '關閉';
+$lang->bug->buttonToList = '返回';
+$lang->bug->buttonCreateTestcase = '建用例';
+
+/* 交互提示。*/
+$lang->bug->confirmChangeProduct = '修改產品會導致相應的項目、需求和任務發生變化,確定嗎?';
+$lang->bug->confirmDelete = '您確認要刪除該Bug嗎?';
+$lang->bug->setTemplateTitle = '請輸入bug模板標題(保存之前請先填寫bug重現步驟):';
+$lang->bug->remindTask = '該Bug已經轉化為任務,是否更新任務(編號:%s)狀態 ?';
+
+/* 模板。*/
+$lang->bug->tplStep = "[步驟]
";
+$lang->bug->tplResult = "[結果]
";
+$lang->bug->tplExpect = "[期望]
";
+
+/* 各個欄位取值列表。*/
+$lang->bug->severityList[3] = '3';
+$lang->bug->severityList[1] = '1';
+$lang->bug->severityList[2] = '2';
+$lang->bug->severityList[4] = '4';
+
+$lang->bug->priList[0] = '';
+$lang->bug->priList[3] = '3';
+$lang->bug->priList[1] = '1';
+$lang->bug->priList[2] = '2';
+$lang->bug->priList[4] = '4';
+
+$lang->bug->osList[''] = '';
+$lang->bug->osList['all'] = '全部';
+$lang->bug->osList['windows'] = 'Windows';
+$lang->bug->osList['winxp'] = 'Windows XP';
+$lang->bug->osList['win7'] = 'Windows 7';
+$lang->bug->osList['vista'] = 'Windows Vista';
+$lang->bug->osList['win2000'] = 'Windows 2000';
+$lang->bug->osList['win2003'] = 'Windows 2003';
+$lang->bug->osList['win2008'] = 'Windows 2008';
+$lang->bug->osList['winnt'] = 'Windows NT';
+$lang->bug->osList['win98'] = 'Windows 98';
+$lang->bug->osList['andriod'] = 'Andriod';
+$lang->bug->osList['ios'] = 'IOS';
+$lang->bug->osList['wp7'] = 'WP7';
+$lang->bug->osList['symbian'] = 'Symbian';
+$lang->bug->osList['linux'] = 'Linux';
+$lang->bug->osList['freebsd'] = 'FreeBSD';
+$lang->bug->osList['mac'] = 'Mac OS';
+$lang->bug->osList['unix'] = 'Unix';
+$lang->bug->osList['others'] = '其他';
+
+$lang->bug->browserList[''] = '';
+$lang->bug->browserList['all'] = '全部';
+$lang->bug->browserList['ie'] = 'IE系列';
+$lang->bug->browserList['ie8'] = 'IE8';
+$lang->bug->browserList['ie9'] = 'IE9';
+$lang->bug->browserList['ie6'] = 'IE6';
+$lang->bug->browserList['ie7'] = 'IE7';
+$lang->bug->browserList['chrome'] = 'chrome';
+$lang->bug->browserList['firefox'] = 'firefox系列';
+$lang->bug->browserList['firefox2'] = 'firefox2';
+$lang->bug->browserList['firefox3'] = 'firefox3';
+$lang->bug->browserList['firefox4'] = 'firefox4';
+$lang->bug->browserList['opera'] = 'opera系列';
+$lang->bug->browserList['opera9'] = 'opera9';
+$lang->bug->browserList['oprea10'] = 'opera10';
+$lang->bug->browserList['oprea11'] = 'opera11';
+$lang->bug->browserList['safari'] = 'safari';
+$lang->bug->browserList['maxthon'] = '傲游';
+$lang->bug->browserList['uc'] = 'UC';
+$lang->bug->browserList['other'] = '其他';
+
+$lang->bug->typeList[''] = '';
+$lang->bug->typeList['codeerror'] = '代碼錯誤';
+$lang->bug->typeList['interface'] = '界面優化';
+$lang->bug->typeList['designchange'] = '設計變更';
+$lang->bug->typeList['newfeature'] = '新增需求';
+$lang->bug->typeList['designdefect'] = '設計缺陷';
+$lang->bug->typeList['config'] = '配置相關';
+$lang->bug->typeList['install'] = '安裝部署';
+$lang->bug->typeList['security'] = '安全相關';
+$lang->bug->typeList['performance'] = '性能問題';
+$lang->bug->typeList['standard'] = '標準規範';
+$lang->bug->typeList['automation'] = '測試腳本';
+$lang->bug->typeList['trackthings'] = '事務跟蹤';
+$lang->bug->typeList['others'] = '其他';
+
+$lang->bug->statusList[''] = '';
+$lang->bug->statusList['active'] = '激活';
+$lang->bug->statusList['resolved'] = '已解決';
+$lang->bug->statusList['closed'] = '已關閉';
+
+$lang->bug->confirmedList[1] = '已確認';
+$lang->bug->confirmedList[0] = '未確認';
+
+$lang->bug->resolutionList[''] = '';
+$lang->bug->resolutionList['bydesign'] = '設計如此';
+$lang->bug->resolutionList['duplicate'] = '重複Bug';
+$lang->bug->resolutionList['external'] = '外部原因';
+$lang->bug->resolutionList['fixed'] = '已解決';
+$lang->bug->resolutionList['notrepro'] = '無法重現';
+$lang->bug->resolutionList['postponed'] = '延期處理';
+$lang->bug->resolutionList['willnotfix'] = "不予解決";
+$lang->bug->resolutionList['tostory'] = '轉為需求';
+
+/* 統計報表。*/
+$lang->bug->report->common = '統計報表';
+$lang->bug->report->select = '請選擇報表類型';
+$lang->bug->report->create = '生成報表';
+$lang->bug->report->selectAll = '全選';
+$lang->bug->report->selectReverse = '反選';
+
+$lang->bug->report->charts['bugsPerProject'] = '項目Bug數量';
+$lang->bug->report->charts['bugsPerModule'] = '模組Bug數量';
+$lang->bug->report->charts['openedBugsPerDay'] = '每天新增Bug數';
+$lang->bug->report->charts['resolvedBugsPerDay'] = '每天解決Bug數';
+$lang->bug->report->charts['closedBugsPerDay'] = '每天關閉的Bug數';
+$lang->bug->report->charts['openedBugsPerUser'] = '每人提交的Bug數';
+$lang->bug->report->charts['resolvedBugsPerUser'] = '每人解決的Bug數';
+$lang->bug->report->charts['closedBugsPerUser'] = '每人關閉的Bug數';
+$lang->bug->report->charts['bugsPerSeverity'] = 'Bug嚴重程度統計';
+$lang->bug->report->charts['bugsPerResolution'] = 'Bug解決方案統計';
+$lang->bug->report->charts['bugsPerStatus'] = 'Bug狀態統計';
+$lang->bug->report->charts['bugsPerActivatedCount'] = 'Bug激活次數統計';
+$lang->bug->report->charts['bugsPerType'] = 'Bug類型統計';
+$lang->bug->report->charts['bugsPerAssignedTo'] = '指派給統計';
+//$lang->bug->report->charts['bugLiveDays'] = 'Bug處理時間統計';
+//$lang->bug->report->charts['bugHistories'] = 'Bug處理步驟統計';
+
+$lang->bug->report->options->swf = 'pie2d';
+$lang->bug->report->options->width = 'auto';
+$lang->bug->report->options->height = 300;
+$lang->bug->report->options->graph->baseFontSize = 12;
+$lang->bug->report->options->graph->showNames = 1;
+$lang->bug->report->options->graph->formatNumber = 1;
+$lang->bug->report->options->graph->decimalPrecision = 0;
+$lang->bug->report->options->graph->animation = 0;
+$lang->bug->report->options->graph->rotateNames = 0;
+$lang->bug->report->options->graph->yAxisName = 'COUNT';
+$lang->bug->report->options->graph->pieRadius = 100; // 餅圖直徑。
+$lang->bug->report->options->graph->showColumnShadow = 0; // 是否顯示柱狀圖陰影。
+
+$lang->bug->report->bugsPerProject->graph->xAxisName = '項目';
+$lang->bug->report->bugsPerModule->graph->xAxisName = '模組';
+
+$lang->bug->report->openedBugsPerDay->swf = 'column2d';
+$lang->bug->report->openedBugsPerDay->height = 400;
+$lang->bug->report->openedBugsPerDay->graph->xAxisName = '日期';
+$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->resolvedBugsPerDay->swf = 'column2d';
+$lang->bug->report->resolvedBugsPerDay->height = 400;
+$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = '日期';
+$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->closedBugsPerDay->swf = 'column2d';
+$lang->bug->report->closedBugsPerDay->height = 400;
+$lang->bug->report->closedBugsPerDay->graph->xAxisName = '日期';
+$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1;
+
+$lang->bug->report->openedBugsPerUser->graph->xAxisName = '用戶';
+$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= '用戶';
+$lang->bug->report->closedBugsPerUser->graph->xAxisName = '用戶';
+
+$lang->bug->report->bugsPerSeverity->graph->xAxisName = '嚴重程度';
+$lang->bug->report->bugsPerResolution->graph->xAxisName = '解決方案';
+$lang->bug->report->bugsPerStatus->graph->xAxisName = '狀態';
+$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = '激活次數';
+$lang->bug->report->bugsPerType->graph->xAxisName = '類型';
+$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = '指派給';
+$lang->bug->report->bugLiveDays->graph->xAxisName = '處理時間';
+$lang->bug->report->bugHistories->graph->xAxisName = '處理步驟';
+
+/* 操作記錄。*/
+$lang->bug->action->resolved = array('main' => '$date, 由 $actor 解決,方案為 $extra 。', 'extra' => $lang->bug->resolutionList);
+$lang->bug->action->tostory = array('main' => '$date, 由 $actor 轉為需求 ,編號為 $extra 。');
+$lang->bug->action->totask = array('main' => '$date, 由 $actor 導入為任務 ,編號為 $extra 。');
diff --git a/module/bug/model.php b/module/bug/model.php
index b2cf5064c2..d15a3ca542 100644
--- a/module/bug/model.php
+++ b/module/bug/model.php
@@ -1,988 +1,988 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-loadModel('product')->setMenu($products, $productID);
- $selectHtml = $this->product->select($products, $productID, 'bug', 'browse');
- foreach($this->lang->bug->menu as $key => $menu)
- {
- $replace = ($key == 'product') ? $selectHtml . $this->lang->arrow : $productID;
- common::setMenuVars($this->lang->bug->menu, $key, $replace);
- }
- }
-
- /**
- * Create a bug.
- *
- * @access public
- * @return int|bool
- */
- public function create()
- {
- $now = helper::now();
- $bug = fixer::input('post')
- ->add('openedBy', $this->app->user->account)
- ->add('openedDate', $now)
- ->setDefault('project,story,task', 0)
- ->setDefault('openedBuild', '')
- ->setIF($this->post->assignedTo != '', 'assignedDate', $now)
- ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story))
- ->specialChars('title,keyword')
- ->cleanInt('product, module, severity')
- ->join('openedBuild', ',')
- ->remove('files, labels')
- ->get();
- $this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec();
- if(!dao::isError())
- {
- $bugID = $this->dao->lastInsertID();
- $this->loadModel('file')->saveUpload('bug', $bugID);
- return $bugID;
- }
- return false;
- }
-
- /**
- * Get bugs of a module.
- *
- * @param int $productID
- * @param string|array $moduleIds
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getModuleBugs($productID, $moduleIds = 0, $projects, $orderBy = 'id_desc', $pager = null)
- {
- return $this->dao->select('*')->from(TABLE_BUG)
- ->where('product')->eq((int)$productID)
- ->beginIF(!empty($moduleIds))->andWhere('module')->in($moduleIds)->fi()
- ->andWhere('project')->in(array_keys($projects))
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get info of a bug.
- *
- * @param int $bugID
- * @access public
- * @return object
- */
- public function getById($bugID)
- {
- $bug = $this->dao->select('t1.*, t2.name AS projectName, t3.title AS storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion, t4.name AS taskName')
- ->from(TABLE_BUG)->alias('t1')
- ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
- ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id')
- ->leftJoin(TABLE_TASK)->alias('t4')->on('t1.task = t4.id')
- ->where('t1.id')->eq((int)$bugID)->fetch();
- if(!$bug) return false;
- $bug->steps = $this->loadModel('file')->setImgSize($bug->steps);
- foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $bug->$key = '';
- if($bug->mailto)
- {
- $bug->mailto = ltrim(trim($bug->mailto), ','); // Remove the first ,
- $bug->mailto = str_replace(' ', '', $bug->mailto);
- $bug->mailto = rtrim($bug->mailto, ',') . ',';
- $bug->mailto = str_replace(',', ', ', $bug->mailto);
- }
- if($bug->duplicateBug) $bug->duplicateBugTitle = $this->dao->findById($bug->duplicateBug)->from(TABLE_BUG)->fields('title')->fetch('title');
- if($bug->case) $bug->caseTitle = $this->dao->findById($bug->case)->from(TABLE_CASE)->fields('title')->fetch('title');
- if($bug->linkBug) $bug->linkBugTitles = $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->in($bug->linkBug)->fetchPairs();
- if($bug->toStory > 0) $bug->toStoryTitle = $this->dao->findById($bug->toStory)->from(TABLE_STORY)->fields('title')->fetch('title');
- if($bug->toTask > 0) $bug->toTaskTitle = $this->dao->findById($bug->toTask)->from(TABLE_TASK)->fields('name')->fetch('name');
- $bug->files = $this->loadModel('file')->getByObject('bug', $bugID);
- return $bug;
- }
-
- /**
- * getActiveBugs
- *
- * @param object $pager
- * @param int $projectID
- * @access public
- * @return array
- */
- public function getActiveBugs($pager, $projectID, $products)
- {
- return $this->dao->select('*')->from(TABLE_BUG)
- ->where('status')->eq('active')
- ->andWhere('toTask')->eq(0)
- ->andWhere('tostory')->eq(0)
- ->beginIF(!empty($products))->andWhere('product')->in($products)->fi()
- ->beginIF(empty($products))->andWhere('project')->eq($projectID)->fi()
- ->andWhere('deleted')->eq(0)
- ->orderBy('id desc')
- ->page($pager)
- ->fetchAll();
- }
-
- /**
- * Update a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function update($bugID)
- {
- $oldBug = $this->getById($bugID);
- $now = helper::now();
- $bug = fixer::input('post')
- ->cleanInt('product,module,severity,project,story,task')
- ->specialChars('title,keyword')
- ->remove('comment,files,labels')
- ->setDefault('project,module,project,story,task,duplicateBug', 0)
- ->setDefault('openedBuild', '')
- ->add('lastEditedBy', $this->app->user->account)
- ->add('lastEditedDate', $now)
- ->join('openedBuild', ',')
- ->setIF($this->post->assignedTo != $oldBug->assignedTo, 'assignedDate', $now)
- ->setIF($this->post->resolvedBy != '' and $this->post->resolvedDate == '', 'resolvedDate', $now)
- ->setIF($this->post->resolution != '' and $this->post->resolvedDate == '', 'resolvedDate', $now)
- ->setIF($this->post->resolution != '' and $this->post->resolvedBy == '', 'resolvedBy', $this->app->user->account)
- ->setIF($this->post->closedBy != '' and $this->post->closedDate == '', 'closedDate', $now)
- ->setIF($this->post->closedDate != '' and $this->post->closedBy == '', 'closedBy', $this->app->user->account)
- ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedTo', 'closed')
- ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedDate', $now)
- ->setIF($this->post->resolution != '' or $this->post->resolvedDate != '', 'status', 'resolved')
- ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'status', 'closed')
- ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedTo', $oldBug->openedBy)
- ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedDate', $now)
- ->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active')
- ->setIF($this->post->resolution != '', 'confirmed', 1)
- ->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story))
- ->get();
-
- $this->dao->update(TABLE_BUG)->data($bug)
- ->autoCheck()
- ->batchCheck($this->config->bug->edit->requiredFields, 'notempty')
- ->checkIF($bug->resolvedBy, 'resolution', 'notempty')
- ->checkIF($bug->closedBy, 'resolution', 'notempty')
- ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty')
- ->where('id')->eq((int)$bugID)
- ->exec();
- if(!dao::isError()) return common::createChanges($oldBug, $bug);
- }
-
- /**
- * Confirm a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function confirm($bugID)
- {
- $now = helper::now();
- $bug->confirmed = 1;
- $bug->lastEditedBy = $this->app->user->account;
- $bug->lastEditedDate = $now;
- $this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
- }
-
- /**
- * Resolve a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function resolve($bugID)
- {
- $now = helper::now();
- $bug = fixer::input('post')
- ->add('resolvedBy', $this->app->user->account)
- ->add('resolvedDate', $now)
- ->add('status', 'resolved')
- ->add('confirmed', 1)
- ->add('assignedDate', $now)
- ->add('lastEditedBy', $this->app->user->account)
- ->add('lastEditedDate', $now)
- ->setDefault('duplicateBug', 0)
- ->setDefault('assignedTo', $oldBug->openedBy)
- ->remove('comment')
- ->get();
-
- $this->dao->update(TABLE_BUG)->data($bug)
- ->autoCheck()
- ->batchCheck($this->config->bug->resolve->requiredFields, 'notempty')
- ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty')
- ->checkIF($bug->resolution == 'fixed', 'resolvedBuild','notempty')
- ->where('id')->eq((int)$bugID)
- ->exec();
- }
-
- /**
- * Activate a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function activate($bugID)
- {
- $oldBug = $this->getById($bugID);
- $now = helper::now();
- $bug = fixer::input('post')
- ->setDefault('assignedTo', $oldBug->resolvedBy)
- ->add('assignedDate', $now)
- ->add('resolution', '')
- ->add('status', 'active')
- ->add('resolvedDate', '0000-00-00')
- ->add('resolvedBy', '')
- ->add('resolvedBuild', '')
- ->add('closedBy', '')
- ->add('closedDate', '0000-00-00')
- ->add('duplicateBug', 0)
- ->add('lastEditedBy', $this->app->user->account)
- ->add('lastEditedDate', $now)
- ->join('openedBuild', ',')
- ->remove('comment,files,labels')
- ->get();
-
- $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
- $this->dao->update(TABLE_BUG)->set('activatedCount = activatedCount + 1')->where('id')->eq((int)$bugID)->exec();
- }
-
- /**
- * Close a bug.
- *
- * @param int $bugID
- * @access public
- * @return void
- */
- public function close($bugID)
- {
- $oldBug = $this->getById($bugID);
- $now = helper::now();
- $bug = fixer::input('post')
- ->add('assignedTo', 'closed')
- ->add('assignedDate', $now)
- ->add('status', 'closed')
- ->add('closedBy', $this->app->user->account)
- ->add('closedDate', $now)
- ->add('lastEditedBy', $this->app->user->account)
- ->add('lastEditedDate', $now)
- ->add('confirmed', 1)
- ->remove('comment')
- ->get();
-
- $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
- }
-
- /**
- * Extract accounts from some bugs.
- *
- * @param int $bugs
- * @access public
- * @return array
- */
- public function extractAccountsFromList($bugs)
- {
- $accounts = array();
- foreach($bugs as $bug)
- {
- if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy;
- if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo;
- if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy;
- if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy;
- if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy;
- }
- return array_unique($accounts);
- }
-
- /**
- * Extract accounts from a bug.
- *
- * @param object $bug
- * @access public
- * @return array
- */
- public function extractAccountsFromSingle($bug)
- {
- $accounts = array();
- if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy;
- if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo;
- if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy;
- if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy;
- if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy;
- return array_unique($accounts);
- }
-
- /**
- * Get bug pairs of a user.
- *
- * @param int $account
- * @param bool $appendProduct
- * @param int $limit
- * @access public
- * @return array
- */
- public function getUserBugPairs($account, $appendProduct = true, $limit = 0)
- {
- $bugs = array();
- $stmt = $this->dao->select('t1.id, t1.title, t2.name as product')
- ->from(TABLE_BUG)->alias('t1')
- ->leftJoin(TABLE_PRODUCT)->alias('t2')
- ->on('t1.product=t2.id')
- ->where('t1.assignedTo')->eq($account)
- ->andWhere('t1.deleted')->eq(0)
- ->orderBy('id desc')
- ->beginIF($limit > 0)->limit($limit)->fi()
- ->query();
- while($bug = $stmt->fetch())
- {
- if($appendProduct) $bug->title = $bug->product . ' / ' . $bug->title;
- $bugs[$bug->id] = $bug->title;
- }
- return $bugs;
- }
-
- /**
- * Get bugs of a project.
- *
- * @param int $projectID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getProjectBugs($projectID, $orderBy = 'id_desc', $pager = null, $build = 0)
- {
- return $this->dao->select('*')->from(TABLE_BUG)
- ->where('project')->eq((int)$projectID)
- ->beginIF($build != 0)->andWhere('openedBuild')->eq($build)->fi()
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get bug info from a result.
- *
- * @param int $resultID
- * @param int $caseID
- * @param int $version
- * @access public
- * @return array
- */
- public function getBugInfoFromResult($resultID, $caseID = 0, $version = 0)
- {
- $title = '';
- $bugSteps = '';
-
- $result = $this->dao->findById($resultID)->from(TABLE_TESTRESULT)->fetch();
- if($caseID > 0)
- $run->case = $this->loadModel('testcase')->getById($caseID, $result->version);
- else
- $run = $this->loadModel('testtask')->getRunById($result->run);
- if($result and $result->caseResult == 'fail')
- {
- $title = $run->case->title;
- $caseSteps = $run->case->steps;
- $stepResults = unserialize($result->stepResults);
- if($run->case->precondition != '')
- {
- $bugSteps = "[" . $this->lang->testcase->precondition . "]
" . "\n" . $run->case->precondition;
- }
- $bugSteps .= $this->lang->bug->tplStep;
- if(!empty($stepResults))
- {
- foreach($caseSteps as $key => $step)
- {
- $bugSteps .= ($key + 1) . '. ' .$step->desc . " ";
- if($stepResults[$step->id]['result'] == 'fail')
- {
- $bugSteps .= $this->lang->bug->tplResult;
- $bugSteps .= $stepResults[$step->id]['real'] . " ";
- $bugSteps .= $this->lang->bug->tplExpect;
- $bugSteps .= $step->expect;
- break;
- }
- }
- }
- else
- {
- $bugSteps .= $this->lang->bug->tplResult;
- $bugSteps .= $this->lang->bug->tplExpect;
- }
- }
- return array('title' => $title, 'steps' => $bugSteps, 'storyID' => $run->case->story);
- }
-
- /**
- * Get report data of bugs per project
- *
- * @access public
- * @return array
- */
- public function getDataOfBugsPerProject()
- {
- $datas = $this->dao->select('project as name, count(project) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('project')->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- $projects = $this->loadModel('project')->getPairs();
- foreach($datas as $projectID => $data) $data->name = isset($projects[$projectID]) ? $projects[$projectID] : $this->lang->report->undefined;
- return $datas;
- }
-
- /**
- * Get report data of bugs per module
- *
- * @access public
- * @return array
- */
- public function getDataOfBugsPerModule()
- {
- $datas = $this->dao->select('module as name, count(module) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('module')->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- $modules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in(array_keys($datas))->fetchPairs();
- foreach($datas as $moduleID => $data) $data->name = isset($modules[$moduleID]) ? $modules[$moduleID] : '/';
- return $datas;
- }
-
- /**
- * Get report data of opened bugs per day.
- *
- * @access public
- * @return array
- */
- public function getDataOfOpenedBugsPerDay()
- {
- return $this->dao->select('DATE_FORMAT(openedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('openedDate')->fetchAll();
- }
-
- /**
- * Get report data of resolved bugs per day.
- *
- * @access public
- * @return array
- */
- public function getDataOfResolvedBugsPerDay()
- {
- return $this->dao->select('DATE_FORMAT(resolvedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)
- ->where($this->session->bugReportCondition)->groupBy('name')
- ->having('name != 0000-00-00')
- ->orderBy('resolvedDate')
- ->fetchAll();
- }
-
- /**
- * Get report data of closed bugs per day.
- *
- * @access public
- * @return array
- */
- public function getDataOfClosedBugsPerDay()
- {
- return $this->dao->select('DATE_FORMAT(closedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)
- ->where($this->session->bugReportCondition)->groupBy('name')
- ->having('name != 0000-00-00')
- ->orderBy('closedDate')->fetchAll();
- }
-
- /**
- * Get report data of openeded bugs per user.
- *
- * @access public
- * @return array
- */
- public function getDataOfOpenedBugsPerUser()
- {
- $datas = $this->dao->select('openedBy AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter');
- foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account];
- return $datas;
- }
-
- /**
- * Get report data of resolved bugs per user.
- *
- * @access public
- * @return array
- */
- public function getDataOfResolvedBugsPerUser()
- {
- $datas = $this->dao->select('resolvedBy AS name, COUNT(*) AS value')
- ->from(TABLE_BUG)->where($this->session->bugReportCondition)
- ->andWhere('resolvedBy')->ne('')
- ->groupBy('name')
- ->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter');
- foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account];
- return $datas;
- }
-
- /**
- * Get report data of closed bugs per user.
- *
- * @access public
- * @return array
- */
- public function getDataOfClosedBugsPerUser()
- {
- $datas = $this->dao->select('closedBy AS name, COUNT(*) AS value')
- ->from(TABLE_BUG)
- ->where($this->session->bugReportCondition)
- ->andWhere('closedBy')->ne('')
- ->groupBy('name')
- ->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter');
- foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account];
- return $datas;
- }
-
- /**
- * Get report data of bugs per severity.
- *
- * @access public
- * @return array
- */
- public function getDataOfBugsPerSeverity()
- {
- $datas = $this->dao->select('severity AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- foreach($datas as $severity => $data) if(isset($this->lang->bug->severityList[$severity])) $data->name = $this->lang->bug->severityList[$severity];
- return $datas;
- }
-
- /**
- * Get report data of bugs per resolution.
- *
- * @access public
- * @return array
- */
- public function getDataOfBugsPerResolution()
- {
- $datas = $this->dao->select('resolution AS name, COUNT(*) AS value')
- ->from(TABLE_BUG)
- ->where($this->session->bugReportCondition)
- ->andWhere('resolution')->ne('')
- ->groupBy('name')->orderBy('value DESC')
- ->fetchAll('name');
- if(!$datas) return array();
- foreach($datas as $resolution => $data) if(isset($this->lang->bug->resolutionList[$resolution])) $data->name = $this->lang->bug->resolutionList[$resolution];
- return $datas;
- }
-
- /**
- * Get report data of bugs per status.
- *
- * @access public
- * @return array
- */
- public function getDataOfBugsPerStatus()
- {
- $datas = $this->dao->select('status AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- foreach($datas as $status => $data) if(isset($this->lang->bug->statusList[$status])) $data->name = $this->lang->bug->statusList[$status];
- return $datas;
- }
-
- /**
- * Get report data of bugs per status.
- *
- * @access public
- * @return array
- */
- public function getDataOfBugsPerActivatedCount()
- {
- $datas = $this->dao->select('activatedCount AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- foreach($datas as $data) $data->name = $this->lang->bug->report->bugsPerActivatedCount->graph->xAxisName . ':' . $data->name;
- return $datas;
- }
-
- /**
- * Get report data of bugs per type.
- *
- * @access public
- * @return array
- */
- public function getDataOfBugsPerType()
- {
- $datas = $this->dao->select('type AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- foreach($datas as $type => $data) if(isset($this->lang->bug->typeList[$type])) $data->name = $this->lang->bug->typeList[$type];
- return $datas;
- }
-
- /**
- * getDataOfBugsPerAssignedTo
- *
- * @access public
- * @return void
- */
- public function getDataOfBugsPerAssignedTo()
- {
- $datas = $this->dao->select('assignedTo AS name, COUNT(*) AS value')
- ->from(TABLE_BUG)->where($this->session->bugReportCondition)
- ->groupBy('name')
- ->orderBy('value DESC')->fetchAll('name');
- if(!$datas) return array();
- if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter');
- foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account];
- return $datas;
- }
-
- /**
- * Merge the default chart settings and the settings of current chart.
- *
- * @param string $chartType
- * @access public
- * @return void
- */
- public function mergeChartOption($chartType)
- {
- $chartOption = $this->lang->bug->report->$chartType;
- $commonOption = $this->lang->bug->report->options;
-
- $chartOption->graph->caption = $this->lang->bug->report->charts[$chartType];
- if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf;
- if(!isset($chartOption->width)) $chartOption->width = $commonOption->width;
- if(!isset($chartOption->height)) $chartOption->height = $commonOption->height;
-
- /* 合并配置。*/
- foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value;
- }
-
- /**
- * Get bug templates of a user.
- *
- * @param string $account
- * @access public
- * @return array
- */
- public function getUserBugTemplates($account)
- {
- $templates = $this->dao->select('id, title, content')
- ->from(TABLE_USERTPL)
- ->where('account')->eq($account)
- ->orderBy('id')
- ->fetchAll();
- return $templates;
- }
-
- /**
- * Save user template.
- *
- * @access public
- * @return void
- */
- public function saveUserBugTemplate()
- {
- $template = fixer::input('post')
- ->specialChars('title')
- ->add('account', $this->app->user->account)
- ->add('type', 'bug')
- ->get();
- $this->dao->insert(TABLE_USERTPL)->data($template)->autoCheck('title, content', 'notempty')->check('title', 'unique')->exec();
- }
-
- /**
- * Return the file => label pairs of some fields.
- *
- * @param string $fields
- * @access public
- * @return array
- */
- public function getFieldPairs($fields)
- {
- $fields = explode(',', $fields);
- foreach($fields as $key => $field)
- {
- $field = trim($field);
- $fields[$field] = $this->lang->bug->$field;
- unset($fields[$key]);
- }
- return $fields;
- }
-
- /**
- * Get all bugs.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getAllBugs($productID, $projects, $orderBy, $pager)
- {
- return $this->dao->select('*')->from(TABLE_BUG)->where('product')->eq($productID)
- ->andWhere('project')->in(array_keys($projects))
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get bugs of assign to me.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getByAssigntome($productID, $projects, $orderBy, $pager)
- {
- return $this->dao->findByAssignedTo($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)
- ->andWhere('project')->in(array_keys($projects))
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get bugs of opened by me.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getByOpenedbyme($productID, $projects, $orderBy, $pager)
- {
- return $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)
- ->andWhere('project')->in(array_keys($projects))
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get bugs of resolved by me.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getByResolvedbyme($productID, $projects, $orderBy, $pager)
- {
- return $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)
- ->andWhere('project')->in(array_keys($projects))
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get bugs of nobody to do.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getByAssigntonull($productID, $projects, $orderBy, $pager)
- {
- return $this->dao->findByAssignedTo('')->from(TABLE_BUG)->andWhere('product')->eq($productID)
- ->andWhere('project')->in(array_keys($projects))
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get bugs the status is active or unclosed.
- *
- * @param int $productID
- * @param array $projects
- * @param string $status
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getByStatus($productID, $projects, $status, $orderBy, $pager)
- {
- return $this->dao->select('*')->from(TABLE_BUG)
- ->where('project')->in(array_keys($projects))
- ->andWhere('product')->eq($productID)
- ->beginIF($status == 'unclosed')->andWhere('status')->ne('closed')->fi()
- ->beginIF($status == 'unresolved')->andWhere('status')->eq('active')->fi()
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get unresolve bugs for long time.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getByLonglifebugs($productID, $projects, $orderBy, $pager)
- {
- return $this->dao->findByLastEditedDate("<", date(DT_DATE1, strtotime('-7 days')))->from(TABLE_BUG)->andWhere('product')->eq($productID)
- ->andWhere('project')->in(array_keys($projects))
- ->andWhere('openedDate')->lt(date(DT_DATE1,strtotime('-7 days')))
- ->andWhere('deleted')->eq(0)
- ->andWhere('status')->ne('closed')->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get postponed bugs.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getByPostponedbugs($productID, $projects, $orderBy, $pager)
- {
- return $this->dao->findByResolution('postponed')->from(TABLE_BUG)->andWhere('product')->eq($productID)
- ->andWhere('project')->in(array_keys($projects))
- ->orderBy($orderBy)->page($pager)->fetchAll();
- }
-
- /**
- * Get bugs need confirm.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getByNeedconfirm($productID, $projects, $orderBy, $pager)
- {
- return $this->dao->select('t1.*, t2.title AS storyTitle')->from(TABLE_BUG)->alias('t1')->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
- ->where("t2.status = 'active'")
- ->andWhere('t1.deleted')->eq(0)
- ->andWhere('t2.version > t1.storyVersion')
- ->andWhere('t1.project')->in(array_keys($projects))
- ->orderBy($orderBy)
- ->fetchAll();
- }
-
- /**
- * Get bugs by search.
- *
- * @param int $productID
- * @param array $projects
- * @param int $queryID
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getBySearch($productID, $projects, $queryID, $orderBy, $pager)
- {
- if($queryID)
- {
- $query = $this->loadModel('search')->getQuery($queryID);
- if($query)
- {
- $this->session->set('bugQuery', $query->sql);
- $this->session->set('bugForm', $query->form);
- }
- else
- {
- $this->session->set('bugQuery', ' 1 = 1');
- }
- }
- else
- {
- if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1');
- }
-
- /* check the purview of projects.*/
- if(strpos($this->session->bugQuery, '`project`') === false)
- {
- $var = $this->session->bugQuery . 'AND `project`' . helper::dbIN(array_keys($projects));
- $this->session->set('bugQuery', "$var");
- }
-
- $bugQuery = str_replace("`product` = 'all'", '1', $this->session->bugQuery); // Search all product.
- $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery)
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- return $bugs;
- }
-
- /**
- * Form customed bugs.
- *
- * @param array $bugs
- * @access public
- * @return array
- */
- public function formCustomedBugs($bugs)
- {
- /* Get related objects id lists. */
- $relatedModuleIdList = array();
- $relatedStoryIdList = array();
- $relatedTaskIdList = array();
- $relatedCaseIdList = array();
- $relatedProjectIdList = array();
-
- foreach($bugs as $bug)
- {
- $relatedModuleIdList[$bug->module] = $bug->module;
- $relatedStoryIdList[$bug->story] = $bug->story;
- $relatedTaskIdList[$bug->task] = $bug->task;
- $relatedCaseIdList[$bug->case] = $bug->case;
- $relatedProjectIdList[$bug->project] = $bug->project;
-
- /* Get related objects title or names. */
- $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs();
- $relatedStories = $this->dao->select('id, title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs();
- $relatedTasks = $this->dao->select('id, name')->from(TABLE_TASK)->where('id')->in($relatedTaskIdList)->fetchPairs();
- $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs();
- $relatedProjects = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('id')->in($relatedProjectIdList)->fetchPairs();
-
- /* fill some field with useful value. */
- if(isset($relatedModules[$bug->module])) $bug->module = $relatedModules[$bug->module];
- if(isset($relatedStories[$bug->story])) $bug->story = $relatedStories[$bug->story];
- if(isset($relatedTasks[$bug->task])) $bug->task = $relatedTasks[$bug->task];
- if(isset($relatedCases[$bug->case])) $bug->case = $relatedCases[$bug->case];
- if(isset($relatedProjects[$bug->project])) $bug->project = $relatedProjects[$bug->project];
- }
- return $bugs;
- }
-}
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+loadModel('product')->setMenu($products, $productID);
+ $selectHtml = $this->product->select($products, $productID, 'bug', 'browse');
+ foreach($this->lang->bug->menu as $key => $menu)
+ {
+ $replace = ($key == 'product') ? $selectHtml . $this->lang->arrow : $productID;
+ common::setMenuVars($this->lang->bug->menu, $key, $replace);
+ }
+ }
+
+ /**
+ * Create a bug.
+ *
+ * @access public
+ * @return int|bool
+ */
+ public function create()
+ {
+ $now = helper::now();
+ $bug = fixer::input('post')
+ ->add('openedBy', $this->app->user->account)
+ ->add('openedDate', $now)
+ ->setDefault('project,story,task', 0)
+ ->setDefault('openedBuild', '')
+ ->setIF($this->post->assignedTo != '', 'assignedDate', $now)
+ ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story))
+ ->specialChars('title,keyword')
+ ->cleanInt('product, module, severity')
+ ->join('openedBuild', ',')
+ ->remove('files, labels')
+ ->get();
+ $this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec();
+ if(!dao::isError())
+ {
+ $bugID = $this->dao->lastInsertID();
+ $this->loadModel('file')->saveUpload('bug', $bugID);
+ return $bugID;
+ }
+ return false;
+ }
+
+ /**
+ * Get bugs of a module.
+ *
+ * @param int $productID
+ * @param string|array $moduleIds
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getModuleBugs($productID, $moduleIds = 0, $projects, $orderBy = 'id_desc', $pager = null)
+ {
+ return $this->dao->select('*')->from(TABLE_BUG)
+ ->where('product')->eq((int)$productID)
+ ->beginIF(!empty($moduleIds))->andWhere('module')->in($moduleIds)->fi()
+ ->andWhere('project')->in(array_keys($projects))
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get info of a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return object
+ */
+ public function getById($bugID)
+ {
+ $bug = $this->dao->select('t1.*, t2.name AS projectName, t3.title AS storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion, t4.name AS taskName')
+ ->from(TABLE_BUG)->alias('t1')
+ ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
+ ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id')
+ ->leftJoin(TABLE_TASK)->alias('t4')->on('t1.task = t4.id')
+ ->where('t1.id')->eq((int)$bugID)->fetch();
+ if(!$bug) return false;
+ $bug->steps = $this->loadModel('file')->setImgSize($bug->steps);
+ foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $bug->$key = '';
+ if($bug->mailto)
+ {
+ $bug->mailto = ltrim(trim($bug->mailto), ','); // Remove the first ,
+ $bug->mailto = str_replace(' ', '', $bug->mailto);
+ $bug->mailto = rtrim($bug->mailto, ',') . ',';
+ $bug->mailto = str_replace(',', ', ', $bug->mailto);
+ }
+ if($bug->duplicateBug) $bug->duplicateBugTitle = $this->dao->findById($bug->duplicateBug)->from(TABLE_BUG)->fields('title')->fetch('title');
+ if($bug->case) $bug->caseTitle = $this->dao->findById($bug->case)->from(TABLE_CASE)->fields('title')->fetch('title');
+ if($bug->linkBug) $bug->linkBugTitles = $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->in($bug->linkBug)->fetchPairs();
+ if($bug->toStory > 0) $bug->toStoryTitle = $this->dao->findById($bug->toStory)->from(TABLE_STORY)->fields('title')->fetch('title');
+ if($bug->toTask > 0) $bug->toTaskTitle = $this->dao->findById($bug->toTask)->from(TABLE_TASK)->fields('name')->fetch('name');
+ $bug->files = $this->loadModel('file')->getByObject('bug', $bugID);
+ return $bug;
+ }
+
+ /**
+ * getActiveBugs
+ *
+ * @param object $pager
+ * @param int $projectID
+ * @access public
+ * @return array
+ */
+ public function getActiveBugs($pager, $projectID, $products)
+ {
+ return $this->dao->select('*')->from(TABLE_BUG)
+ ->where('status')->eq('active')
+ ->andWhere('toTask')->eq(0)
+ ->andWhere('tostory')->eq(0)
+ ->beginIF(!empty($products))->andWhere('product')->in($products)->fi()
+ ->beginIF(empty($products))->andWhere('project')->eq($projectID)->fi()
+ ->andWhere('deleted')->eq(0)
+ ->orderBy('id desc')
+ ->page($pager)
+ ->fetchAll();
+ }
+
+ /**
+ * Update a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function update($bugID)
+ {
+ $oldBug = $this->getById($bugID);
+ $now = helper::now();
+ $bug = fixer::input('post')
+ ->cleanInt('product,module,severity,project,story,task')
+ ->specialChars('title,keyword')
+ ->remove('comment,files,labels')
+ ->setDefault('project,module,project,story,task,duplicateBug', 0)
+ ->setDefault('openedBuild', '')
+ ->add('lastEditedBy', $this->app->user->account)
+ ->add('lastEditedDate', $now)
+ ->join('openedBuild', ',')
+ ->setIF($this->post->assignedTo != $oldBug->assignedTo, 'assignedDate', $now)
+ ->setIF($this->post->resolvedBy != '' and $this->post->resolvedDate == '', 'resolvedDate', $now)
+ ->setIF($this->post->resolution != '' and $this->post->resolvedDate == '', 'resolvedDate', $now)
+ ->setIF($this->post->resolution != '' and $this->post->resolvedBy == '', 'resolvedBy', $this->app->user->account)
+ ->setIF($this->post->closedBy != '' and $this->post->closedDate == '', 'closedDate', $now)
+ ->setIF($this->post->closedDate != '' and $this->post->closedBy == '', 'closedBy', $this->app->user->account)
+ ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedTo', 'closed')
+ ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedDate', $now)
+ ->setIF($this->post->resolution != '' or $this->post->resolvedDate != '', 'status', 'resolved')
+ ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'status', 'closed')
+ ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedTo', $oldBug->openedBy)
+ ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedDate', $now)
+ ->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active')
+ ->setIF($this->post->resolution != '', 'confirmed', 1)
+ ->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story))
+ ->get();
+
+ $this->dao->update(TABLE_BUG)->data($bug)
+ ->autoCheck()
+ ->batchCheck($this->config->bug->edit->requiredFields, 'notempty')
+ ->checkIF($bug->resolvedBy, 'resolution', 'notempty')
+ ->checkIF($bug->closedBy, 'resolution', 'notempty')
+ ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty')
+ ->where('id')->eq((int)$bugID)
+ ->exec();
+ if(!dao::isError()) return common::createChanges($oldBug, $bug);
+ }
+
+ /**
+ * Confirm a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function confirm($bugID)
+ {
+ $now = helper::now();
+ $bug->confirmed = 1;
+ $bug->lastEditedBy = $this->app->user->account;
+ $bug->lastEditedDate = $now;
+ $this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
+ }
+
+ /**
+ * Resolve a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function resolve($bugID)
+ {
+ $now = helper::now();
+ $bug = fixer::input('post')
+ ->add('resolvedBy', $this->app->user->account)
+ ->add('resolvedDate', $now)
+ ->add('status', 'resolved')
+ ->add('confirmed', 1)
+ ->add('assignedDate', $now)
+ ->add('lastEditedBy', $this->app->user->account)
+ ->add('lastEditedDate', $now)
+ ->setDefault('duplicateBug', 0)
+ ->setDefault('assignedTo', $oldBug->openedBy)
+ ->remove('comment')
+ ->get();
+
+ $this->dao->update(TABLE_BUG)->data($bug)
+ ->autoCheck()
+ ->batchCheck($this->config->bug->resolve->requiredFields, 'notempty')
+ ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty')
+ ->checkIF($bug->resolution == 'fixed', 'resolvedBuild','notempty')
+ ->where('id')->eq((int)$bugID)
+ ->exec();
+ }
+
+ /**
+ * Activate a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function activate($bugID)
+ {
+ $oldBug = $this->getById($bugID);
+ $now = helper::now();
+ $bug = fixer::input('post')
+ ->setDefault('assignedTo', $oldBug->resolvedBy)
+ ->add('assignedDate', $now)
+ ->add('resolution', '')
+ ->add('status', 'active')
+ ->add('resolvedDate', '0000-00-00')
+ ->add('resolvedBy', '')
+ ->add('resolvedBuild', '')
+ ->add('closedBy', '')
+ ->add('closedDate', '0000-00-00')
+ ->add('duplicateBug', 0)
+ ->add('lastEditedBy', $this->app->user->account)
+ ->add('lastEditedDate', $now)
+ ->join('openedBuild', ',')
+ ->remove('comment,files,labels')
+ ->get();
+
+ $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
+ $this->dao->update(TABLE_BUG)->set('activatedCount = activatedCount + 1')->where('id')->eq((int)$bugID)->exec();
+ }
+
+ /**
+ * Close a bug.
+ *
+ * @param int $bugID
+ * @access public
+ * @return void
+ */
+ public function close($bugID)
+ {
+ $oldBug = $this->getById($bugID);
+ $now = helper::now();
+ $bug = fixer::input('post')
+ ->add('assignedTo', 'closed')
+ ->add('assignedDate', $now)
+ ->add('status', 'closed')
+ ->add('closedBy', $this->app->user->account)
+ ->add('closedDate', $now)
+ ->add('lastEditedBy', $this->app->user->account)
+ ->add('lastEditedDate', $now)
+ ->add('confirmed', 1)
+ ->remove('comment')
+ ->get();
+
+ $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
+ }
+
+ /**
+ * Extract accounts from some bugs.
+ *
+ * @param int $bugs
+ * @access public
+ * @return array
+ */
+ public function extractAccountsFromList($bugs)
+ {
+ $accounts = array();
+ foreach($bugs as $bug)
+ {
+ if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy;
+ if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo;
+ if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy;
+ if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy;
+ if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy;
+ }
+ return array_unique($accounts);
+ }
+
+ /**
+ * Extract accounts from a bug.
+ *
+ * @param object $bug
+ * @access public
+ * @return array
+ */
+ public function extractAccountsFromSingle($bug)
+ {
+ $accounts = array();
+ if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy;
+ if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo;
+ if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy;
+ if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy;
+ if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy;
+ return array_unique($accounts);
+ }
+
+ /**
+ * Get bug pairs of a user.
+ *
+ * @param int $account
+ * @param bool $appendProduct
+ * @param int $limit
+ * @access public
+ * @return array
+ */
+ public function getUserBugPairs($account, $appendProduct = true, $limit = 0)
+ {
+ $bugs = array();
+ $stmt = $this->dao->select('t1.id, t1.title, t2.name as product')
+ ->from(TABLE_BUG)->alias('t1')
+ ->leftJoin(TABLE_PRODUCT)->alias('t2')
+ ->on('t1.product=t2.id')
+ ->where('t1.assignedTo')->eq($account)
+ ->andWhere('t1.deleted')->eq(0)
+ ->orderBy('id desc')
+ ->beginIF($limit > 0)->limit($limit)->fi()
+ ->query();
+ while($bug = $stmt->fetch())
+ {
+ if($appendProduct) $bug->title = $bug->product . ' / ' . $bug->title;
+ $bugs[$bug->id] = $bug->title;
+ }
+ return $bugs;
+ }
+
+ /**
+ * Get bugs of a project.
+ *
+ * @param int $projectID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getProjectBugs($projectID, $orderBy = 'id_desc', $pager = null, $build = 0)
+ {
+ return $this->dao->select('*')->from(TABLE_BUG)
+ ->where('project')->eq((int)$projectID)
+ ->beginIF($build != 0)->andWhere('openedBuild')->eq($build)->fi()
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get bug info from a result.
+ *
+ * @param int $resultID
+ * @param int $caseID
+ * @param int $version
+ * @access public
+ * @return array
+ */
+ public function getBugInfoFromResult($resultID, $caseID = 0, $version = 0)
+ {
+ $title = '';
+ $bugSteps = '';
+
+ $result = $this->dao->findById($resultID)->from(TABLE_TESTRESULT)->fetch();
+ if($caseID > 0)
+ $run->case = $this->loadModel('testcase')->getById($caseID, $result->version);
+ else
+ $run = $this->loadModel('testtask')->getRunById($result->run);
+ if($result and $result->caseResult == 'fail')
+ {
+ $title = $run->case->title;
+ $caseSteps = $run->case->steps;
+ $stepResults = unserialize($result->stepResults);
+ if($run->case->precondition != '')
+ {
+ $bugSteps = "[" . $this->lang->testcase->precondition . "]
" . "\n" . $run->case->precondition;
+ }
+ $bugSteps .= $this->lang->bug->tplStep;
+ if(!empty($stepResults))
+ {
+ foreach($caseSteps as $key => $step)
+ {
+ $bugSteps .= ($key + 1) . '. ' .$step->desc . " ";
+ if($stepResults[$step->id]['result'] == 'fail')
+ {
+ $bugSteps .= $this->lang->bug->tplResult;
+ $bugSteps .= $stepResults[$step->id]['real'] . " ";
+ $bugSteps .= $this->lang->bug->tplExpect;
+ $bugSteps .= $step->expect;
+ break;
+ }
+ }
+ }
+ else
+ {
+ $bugSteps .= $this->lang->bug->tplResult;
+ $bugSteps .= $this->lang->bug->tplExpect;
+ }
+ }
+ return array('title' => $title, 'steps' => $bugSteps, 'storyID' => $run->case->story);
+ }
+
+ /**
+ * Get report data of bugs per project
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfBugsPerProject()
+ {
+ $datas = $this->dao->select('project as name, count(project) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('project')->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ $projects = $this->loadModel('project')->getPairs();
+ foreach($datas as $projectID => $data) $data->name = isset($projects[$projectID]) ? $projects[$projectID] : $this->lang->report->undefined;
+ return $datas;
+ }
+
+ /**
+ * Get report data of bugs per module
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfBugsPerModule()
+ {
+ $datas = $this->dao->select('module as name, count(module) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('module')->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ $modules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in(array_keys($datas))->fetchPairs();
+ foreach($datas as $moduleID => $data) $data->name = isset($modules[$moduleID]) ? $modules[$moduleID] : '/';
+ return $datas;
+ }
+
+ /**
+ * Get report data of opened bugs per day.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfOpenedBugsPerDay()
+ {
+ return $this->dao->select('DATE_FORMAT(openedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('openedDate')->fetchAll();
+ }
+
+ /**
+ * Get report data of resolved bugs per day.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfResolvedBugsPerDay()
+ {
+ return $this->dao->select('DATE_FORMAT(resolvedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)
+ ->where($this->session->bugReportCondition)->groupBy('name')
+ ->having('name != 0000-00-00')
+ ->orderBy('resolvedDate')
+ ->fetchAll();
+ }
+
+ /**
+ * Get report data of closed bugs per day.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfClosedBugsPerDay()
+ {
+ return $this->dao->select('DATE_FORMAT(closedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)
+ ->where($this->session->bugReportCondition)->groupBy('name')
+ ->having('name != 0000-00-00')
+ ->orderBy('closedDate')->fetchAll();
+ }
+
+ /**
+ * Get report data of openeded bugs per user.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfOpenedBugsPerUser()
+ {
+ $datas = $this->dao->select('openedBy AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter');
+ foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account];
+ return $datas;
+ }
+
+ /**
+ * Get report data of resolved bugs per user.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfResolvedBugsPerUser()
+ {
+ $datas = $this->dao->select('resolvedBy AS name, COUNT(*) AS value')
+ ->from(TABLE_BUG)->where($this->session->bugReportCondition)
+ ->andWhere('resolvedBy')->ne('')
+ ->groupBy('name')
+ ->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter');
+ foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account];
+ return $datas;
+ }
+
+ /**
+ * Get report data of closed bugs per user.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfClosedBugsPerUser()
+ {
+ $datas = $this->dao->select('closedBy AS name, COUNT(*) AS value')
+ ->from(TABLE_BUG)
+ ->where($this->session->bugReportCondition)
+ ->andWhere('closedBy')->ne('')
+ ->groupBy('name')
+ ->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter');
+ foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account];
+ return $datas;
+ }
+
+ /**
+ * Get report data of bugs per severity.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfBugsPerSeverity()
+ {
+ $datas = $this->dao->select('severity AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ foreach($datas as $severity => $data) if(isset($this->lang->bug->severityList[$severity])) $data->name = $this->lang->bug->severityList[$severity];
+ return $datas;
+ }
+
+ /**
+ * Get report data of bugs per resolution.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfBugsPerResolution()
+ {
+ $datas = $this->dao->select('resolution AS name, COUNT(*) AS value')
+ ->from(TABLE_BUG)
+ ->where($this->session->bugReportCondition)
+ ->andWhere('resolution')->ne('')
+ ->groupBy('name')->orderBy('value DESC')
+ ->fetchAll('name');
+ if(!$datas) return array();
+ foreach($datas as $resolution => $data) if(isset($this->lang->bug->resolutionList[$resolution])) $data->name = $this->lang->bug->resolutionList[$resolution];
+ return $datas;
+ }
+
+ /**
+ * Get report data of bugs per status.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfBugsPerStatus()
+ {
+ $datas = $this->dao->select('status AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ foreach($datas as $status => $data) if(isset($this->lang->bug->statusList[$status])) $data->name = $this->lang->bug->statusList[$status];
+ return $datas;
+ }
+
+ /**
+ * Get report data of bugs per status.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfBugsPerActivatedCount()
+ {
+ $datas = $this->dao->select('activatedCount AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ foreach($datas as $data) $data->name = $this->lang->bug->report->bugsPerActivatedCount->graph->xAxisName . ':' . $data->name;
+ return $datas;
+ }
+
+ /**
+ * Get report data of bugs per type.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDataOfBugsPerType()
+ {
+ $datas = $this->dao->select('type AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ foreach($datas as $type => $data) if(isset($this->lang->bug->typeList[$type])) $data->name = $this->lang->bug->typeList[$type];
+ return $datas;
+ }
+
+ /**
+ * getDataOfBugsPerAssignedTo
+ *
+ * @access public
+ * @return void
+ */
+ public function getDataOfBugsPerAssignedTo()
+ {
+ $datas = $this->dao->select('assignedTo AS name, COUNT(*) AS value')
+ ->from(TABLE_BUG)->where($this->session->bugReportCondition)
+ ->groupBy('name')
+ ->orderBy('value DESC')->fetchAll('name');
+ if(!$datas) return array();
+ if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter');
+ foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account];
+ return $datas;
+ }
+
+ /**
+ * Merge the default chart settings and the settings of current chart.
+ *
+ * @param string $chartType
+ * @access public
+ * @return void
+ */
+ public function mergeChartOption($chartType)
+ {
+ $chartOption = $this->lang->bug->report->$chartType;
+ $commonOption = $this->lang->bug->report->options;
+
+ $chartOption->graph->caption = $this->lang->bug->report->charts[$chartType];
+ if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf;
+ if(!isset($chartOption->width)) $chartOption->width = $commonOption->width;
+ if(!isset($chartOption->height)) $chartOption->height = $commonOption->height;
+
+ /* 合并配置。*/
+ foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value;
+ }
+
+ /**
+ * Get bug templates of a user.
+ *
+ * @param string $account
+ * @access public
+ * @return array
+ */
+ public function getUserBugTemplates($account)
+ {
+ $templates = $this->dao->select('id, title, content')
+ ->from(TABLE_USERTPL)
+ ->where('account')->eq($account)
+ ->orderBy('id')
+ ->fetchAll();
+ return $templates;
+ }
+
+ /**
+ * Save user template.
+ *
+ * @access public
+ * @return void
+ */
+ public function saveUserBugTemplate()
+ {
+ $template = fixer::input('post')
+ ->specialChars('title')
+ ->add('account', $this->app->user->account)
+ ->add('type', 'bug')
+ ->get();
+ $this->dao->insert(TABLE_USERTPL)->data($template)->autoCheck('title, content', 'notempty')->check('title', 'unique')->exec();
+ }
+
+ /**
+ * Return the file => label pairs of some fields.
+ *
+ * @param string $fields
+ * @access public
+ * @return array
+ */
+ public function getFieldPairs($fields)
+ {
+ $fields = explode(',', $fields);
+ foreach($fields as $key => $field)
+ {
+ $field = trim($field);
+ $fields[$field] = $this->lang->bug->$field;
+ unset($fields[$key]);
+ }
+ return $fields;
+ }
+
+ /**
+ * Get all bugs.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getAllBugs($productID, $projects, $orderBy, $pager)
+ {
+ return $this->dao->select('*')->from(TABLE_BUG)->where('product')->eq($productID)
+ ->andWhere('project')->in(array_keys($projects))
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get bugs of assign to me.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getByAssigntome($productID, $projects, $orderBy, $pager)
+ {
+ return $this->dao->findByAssignedTo($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)
+ ->andWhere('project')->in(array_keys($projects))
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get bugs of opened by me.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getByOpenedbyme($productID, $projects, $orderBy, $pager)
+ {
+ return $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)
+ ->andWhere('project')->in(array_keys($projects))
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get bugs of resolved by me.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getByResolvedbyme($productID, $projects, $orderBy, $pager)
+ {
+ return $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID)
+ ->andWhere('project')->in(array_keys($projects))
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get bugs of nobody to do.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getByAssigntonull($productID, $projects, $orderBy, $pager)
+ {
+ return $this->dao->findByAssignedTo('')->from(TABLE_BUG)->andWhere('product')->eq($productID)
+ ->andWhere('project')->in(array_keys($projects))
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get bugs the status is active or unclosed.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param string $status
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getByStatus($productID, $projects, $status, $orderBy, $pager)
+ {
+ return $this->dao->select('*')->from(TABLE_BUG)
+ ->where('project')->in(array_keys($projects))
+ ->andWhere('product')->eq($productID)
+ ->beginIF($status == 'unclosed')->andWhere('status')->ne('closed')->fi()
+ ->beginIF($status == 'unresolved')->andWhere('status')->eq('active')->fi()
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get unresolve bugs for long time.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getByLonglifebugs($productID, $projects, $orderBy, $pager)
+ {
+ return $this->dao->findByLastEditedDate("<", date(DT_DATE1, strtotime('-7 days')))->from(TABLE_BUG)->andWhere('product')->eq($productID)
+ ->andWhere('project')->in(array_keys($projects))
+ ->andWhere('openedDate')->lt(date(DT_DATE1,strtotime('-7 days')))
+ ->andWhere('deleted')->eq(0)
+ ->andWhere('status')->ne('closed')->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get postponed bugs.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getByPostponedbugs($productID, $projects, $orderBy, $pager)
+ {
+ return $this->dao->findByResolution('postponed')->from(TABLE_BUG)->andWhere('product')->eq($productID)
+ ->andWhere('project')->in(array_keys($projects))
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ }
+
+ /**
+ * Get bugs need confirm.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getByNeedconfirm($productID, $projects, $orderBy, $pager)
+ {
+ return $this->dao->select('t1.*, t2.title AS storyTitle')->from(TABLE_BUG)->alias('t1')->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
+ ->where("t2.status = 'active'")
+ ->andWhere('t1.deleted')->eq(0)
+ ->andWhere('t2.version > t1.storyVersion')
+ ->andWhere('t1.project')->in(array_keys($projects))
+ ->orderBy($orderBy)
+ ->fetchAll();
+ }
+
+ /**
+ * Get bugs by search.
+ *
+ * @param int $productID
+ * @param array $projects
+ * @param int $queryID
+ * @param string $orderBy
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getBySearch($productID, $projects, $queryID, $orderBy, $pager)
+ {
+ if($queryID)
+ {
+ $query = $this->loadModel('search')->getQuery($queryID);
+ if($query)
+ {
+ $this->session->set('bugQuery', $query->sql);
+ $this->session->set('bugForm', $query->form);
+ }
+ else
+ {
+ $this->session->set('bugQuery', ' 1 = 1');
+ }
+ }
+ else
+ {
+ if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1');
+ }
+
+ /* check the purview of projects.*/
+ if(strpos($this->session->bugQuery, '`project`') === false)
+ {
+ $var = $this->session->bugQuery . 'AND `project`' . helper::dbIN(array_keys($projects));
+ $this->session->set('bugQuery', "$var");
+ }
+
+ $bugQuery = str_replace("`product` = 'all'", '1', $this->session->bugQuery); // Search all product.
+ $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery)
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ return $bugs;
+ }
+
+ /**
+ * Form customed bugs.
+ *
+ * @param array $bugs
+ * @access public
+ * @return array
+ */
+ public function formCustomedBugs($bugs)
+ {
+ /* Get related objects id lists. */
+ $relatedModuleIdList = array();
+ $relatedStoryIdList = array();
+ $relatedTaskIdList = array();
+ $relatedCaseIdList = array();
+ $relatedProjectIdList = array();
+
+ foreach($bugs as $bug)
+ {
+ $relatedModuleIdList[$bug->module] = $bug->module;
+ $relatedStoryIdList[$bug->story] = $bug->story;
+ $relatedTaskIdList[$bug->task] = $bug->task;
+ $relatedCaseIdList[$bug->case] = $bug->case;
+ $relatedProjectIdList[$bug->project] = $bug->project;
+
+ /* Get related objects title or names. */
+ $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs();
+ $relatedStories = $this->dao->select('id, title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs();
+ $relatedTasks = $this->dao->select('id, name')->from(TABLE_TASK)->where('id')->in($relatedTaskIdList)->fetchPairs();
+ $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs();
+ $relatedProjects = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('id')->in($relatedProjectIdList)->fetchPairs();
+
+ /* fill some field with useful value. */
+ if(isset($relatedModules[$bug->module])) $bug->module = $relatedModules[$bug->module];
+ if(isset($relatedStories[$bug->story])) $bug->story = $relatedStories[$bug->story];
+ if(isset($relatedTasks[$bug->task])) $bug->task = $relatedTasks[$bug->task];
+ if(isset($relatedCases[$bug->case])) $bug->case = $relatedCases[$bug->case];
+ if(isset($relatedProjects[$bug->project])) $bug->project = $relatedProjects[$bug->project];
+ }
+ return $bugs;
+ }
+}
diff --git a/module/bug/view/activate.html.php b/module/bug/view/activate.html.php
index 7c7b973c09..a09b694da7 100644
--- a/module/bug/view/activate.html.php
+++ b/module/bug/view/activate.html.php
@@ -1,43 +1,43 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
diff --git a/module/bug/view/browse.html.php b/module/bug/view/browse.html.php
index b838312f58..0787e6ab7f 100644
--- a/module/bug/view/browse.html.php
+++ b/module/bug/view/browse.html.php
@@ -1,175 +1,175 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
-
-
-
-
-
" . $lang->bug->moduleBugs . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToMe¶m=0"), $lang->bug->assignToMe) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=openedByMe¶m=0"), $lang->bug->openedByMe) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=resolvedByMe¶m=0"), $lang->bug->resolvedByMe) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToNull¶m=0"), $lang->bug->assignToNull) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unResolved¶m=0"), $lang->bug->unResolved) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unclosed¶m=0"), $lang->bug->unclosed) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=longLifeBugs¶m=0"), $lang->bug->longLifeBugs) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=postponedBugs¶m=0"), $lang->bug->postponedBugs) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->bug->allBugs) . " ";
- echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=needconfirm¶m=0"), $lang->bug->needConfirm) . " ";
- echo "
{$lang->bug->byQuery} ";
- ?>
-
-
- export, '', 'class="export"'); ?>
- bug->customFields, '', "class='iframe'"); ?>
- bug->report->common); ?>
- bug->create); ?>
-
-
-'>
-
-
-
-
-
-
-
-
-
-
- createLink('tree', 'browse', "productID=$productID&view=bug"), $lang->tree->manage);?>
-
-
-
-
-
- recTotal}&recPerPage={$pager->recPerPage}"; ?>
-
-
-
- idAB);?>
- bug->severityAB);?>
- priAB);?>
-
- bug->title);?>
-
- cookie->windowWidth >= $this->config->wideSize):?>
- bug->statusAB);?>
-
-
-
- bug->story);?>
- actions;?>
-
- openedByAB);?>
-
- cookie->windowWidth >= $this->config->wideSize):?>
- bug->openedDateAB);?>
-
-
- assignedToAB);?>
- bug->resolvedByAB);?>
- bug->resolutionAB);?>
-
- cookie->windowWidth >= $this->config->wideSize):?>
- bug->resolvedDateAB);?>
-
-
- actions;?>
-
-
-
-
-
- id");?>
-
- status == 'active' ? 'active' . $bug->severity : $bug->status;?>
- id));?>
- bug->severityList[$bug->severity]?>
- bug->priList[$bug->pri]?>
-
- confirmed;?>
- [{$lang->bug->confirmedList[$bug->confirmed]}] " . html::a($bugLink, $bug->title);?>
-
- cookie->windowWidth >= $this->config->wideSize):?>
- bug->statusList[$bug->status];?>
-
-
-
- createLink('story', 'view', "stoyID=$bug->story"), $bug->storyTitle, '_blank');?>
- id"), $lang->confirm, 'hiddenwin')?>
-
- openedBy];?>
-
- cookie->windowWidth >= $this->config->wideSize):?>
- openedDate, 5, 11)?>
-
-
- assignedTo == $this->app->user->account) echo 'class="red"';?>>assignedTo];?>
- resolvedBy];?>
- bug->resolutionList[$bug->resolution];?>
-
- cookie->windowWidth >= $this->config->wideSize):?>
- resolvedDate, 5, 11)?>
-
-
-
- id";
- if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' ';
- if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' ';
- common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit);
- if($this->cookie->windowWidth >= $this->config->wideSize) common::printLink('bug', 'create', "product=$bug->product&extra=bugID=$bug->id", $lang->bug->buttonCopy);
- ?>
-
-
-
-
-
-
-
- cookie->windowWidth > $this->config->wideSize ? 12 : 9;?>
-
-
- bug->statusList as $status => $label)
- {
- if($status != 'active')
- {
- echo " $label ";
- continue;
- }
- rsort($this->lang->bug->severityList);
- foreach($this->lang->bug->severityList as $severity)
- {
- echo " {$lang->bug->severity}:$severity ";
- }
- }
- ?>
-
- show();?>
-
-
-
-
-
-
-
-
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+
+
+
+
" . $lang->bug->moduleBugs . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToMe¶m=0"), $lang->bug->assignToMe) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=openedByMe¶m=0"), $lang->bug->openedByMe) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=resolvedByMe¶m=0"), $lang->bug->resolvedByMe) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToNull¶m=0"), $lang->bug->assignToNull) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unResolved¶m=0"), $lang->bug->unResolved) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unclosed¶m=0"), $lang->bug->unclosed) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=longLifeBugs¶m=0"), $lang->bug->longLifeBugs) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=postponedBugs¶m=0"), $lang->bug->postponedBugs) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->bug->allBugs) . " ";
+ echo "
" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=needconfirm¶m=0"), $lang->bug->needConfirm) . " ";
+ echo "
{$lang->bug->byQuery} ";
+ ?>
+
+
+ export, '', 'class="export"'); ?>
+ bug->customFields, '', "class='iframe'"); ?>
+ bug->report->common); ?>
+ bug->create); ?>
+
+
+'>
+
+
+
+
+
+
+
+
+
+
+ createLink('tree', 'browse', "productID=$productID&view=bug"), $lang->tree->manage);?>
+
+
+
+
+
+ recTotal}&recPerPage={$pager->recPerPage}"; ?>
+
+
+
+ idAB);?>
+ bug->severityAB);?>
+ priAB);?>
+
+ bug->title);?>
+
+ cookie->windowWidth >= $this->config->wideSize):?>
+ bug->statusAB);?>
+
+
+
+ bug->story);?>
+ actions;?>
+
+ openedByAB);?>
+
+ cookie->windowWidth >= $this->config->wideSize):?>
+ bug->openedDateAB);?>
+
+
+ assignedToAB);?>
+ bug->resolvedByAB);?>
+ bug->resolutionAB);?>
+
+ cookie->windowWidth >= $this->config->wideSize):?>
+ bug->resolvedDateAB);?>
+
+
+ actions;?>
+
+
+
+
+
+ id");?>
+
+ status == 'active' ? 'active' . $bug->severity : $bug->status;?>
+ id));?>
+ bug->severityList[$bug->severity]?>
+ bug->priList[$bug->pri]?>
+
+ confirmed;?>
+ [{$lang->bug->confirmedList[$bug->confirmed]}] " . html::a($bugLink, $bug->title);?>
+
+ cookie->windowWidth >= $this->config->wideSize):?>
+ bug->statusList[$bug->status];?>
+
+
+
+ createLink('story', 'view', "stoyID=$bug->story"), $bug->storyTitle, '_blank');?>
+ id"), $lang->confirm, 'hiddenwin')?>
+
+ openedBy];?>
+
+ cookie->windowWidth >= $this->config->wideSize):?>
+ openedDate, 5, 11)?>
+
+
+ assignedTo == $this->app->user->account) echo 'class="red"';?>>assignedTo];?>
+ resolvedBy];?>
+ bug->resolutionList[$bug->resolution];?>
+
+ cookie->windowWidth >= $this->config->wideSize):?>
+ resolvedDate, 5, 11)?>
+
+
+
+ id";
+ if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' ';
+ if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' ';
+ common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit);
+ if($this->cookie->windowWidth >= $this->config->wideSize) common::printLink('bug', 'create', "product=$bug->product&extra=bugID=$bug->id", $lang->bug->buttonCopy);
+ ?>
+
+
+
+
+
+
+
+ cookie->windowWidth > $this->config->wideSize ? 12 : 9;?>
+
+
+ bug->statusList as $status => $label)
+ {
+ if($status != 'active')
+ {
+ echo " $label ";
+ continue;
+ }
+ rsort($this->lang->bug->severityList);
+ foreach($this->lang->bug->severityList as $severity)
+ {
+ echo " {$lang->bug->severity}:$severity ";
+ }
+ }
+ ?>
+
+ show();?>
+
+
+
+
+
+
+
+
diff --git a/module/bug/view/close.html.php b/module/bug/view/close.html.php
index 932930ef6a..c1ff9253fa 100644
--- a/module/bug/view/close.html.php
+++ b/module/bug/view/close.html.php
@@ -1,31 +1,31 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
diff --git a/module/bug/view/confirmbug.html.php b/module/bug/view/confirmbug.html.php
index bf0dcc65cd..0aa2fc52a1 100755
--- a/module/bug/view/confirmbug.html.php
+++ b/module/bug/view/confirmbug.html.php
@@ -1,31 +1,31 @@
-
- * @package bug
- * @version $Id: resolve.html.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $
- * @link http://www.zentao.net
- */
-?>
-
-
-
+
+ * @package bug
+ * @version $Id: resolve.html.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
diff --git a/module/bug/view/create.html.php b/module/bug/view/create.html.php
index 71642e13bb..54c7466f7c 100644
--- a/module/bug/view/create.html.php
+++ b/module/bug/view/create.html.php
@@ -1,102 +1,102 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
-
-
-
-
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+
+
+
diff --git a/module/bug/view/customfields.html.php b/module/bug/view/customfields.html.php
index 576fa07ffd..cc6f2df478 100644
--- a/module/bug/view/customfields.html.php
+++ b/module/bug/view/customfields.html.php
@@ -1,49 +1,49 @@
-
- * @package product
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
-
+
+ * @package product
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
diff --git a/module/bug/view/edit.html.php b/module/bug/view/edit.html.php
index 3db2107e0e..e15296c932 100644
--- a/module/bug/view/edit.html.php
+++ b/module/bug/view/edit.html.php
@@ -1,206 +1,206 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
-
-
-
-
-
-
-
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+
+
diff --git a/module/bug/view/sendmail.html.php b/module/bug/view/sendmail.html.php
index 818dac4c56..e5cb9603e3 100644
--- a/module/bug/view/sendmail.html.php
+++ b/module/bug/view/sendmail.html.php
@@ -1,22 +1,22 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
diff --git a/module/bug/view/view.html.php b/module/bug/view/view.html.php
index 5e8c83fae6..4705920f2c 100644
--- a/module/bug/view/view.html.php
+++ b/module/bug/view/view.html.php
@@ -1,272 +1,272 @@
-
- * @package bug
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
deleted) echo "class='deleted'";?>>BUG #id . $lang->colon . $bug->title;?>
-
- session->bugList != false ? $app->session->bugList : inlink('browse', "productID=$bug->product");
- $params = "bugID=$bug->id";
- $copyParams = "productID=$productID&extras=bugID=$bug->id";
- $convertParams = "productID=$productID&moduleID=0&from=bug&bugID=$bug->id";
- if(!$bug->deleted)
- {
- if(!($bug->status == 'active' and $bug->confirmed == 0 and common::printLink('bug', 'confirmBug', $params, $lang->bug->buttonConfirm))) echo $lang->bug->buttonConfirm . ' ';
- if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' ';
- common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit);
- if(common::hasPriv('bug', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' ';
- if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' ';
- if(!(($bug->status == 'closed' or $bug->status == 'resolved') and $bug->resolution != 'tostory' and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' ';
- common::printLink('bug', 'create', $copyParams, $lang->bug->buttonCopy);
- if($bug->status == 'active' and common::hasPriv('story', 'create'))
- {
- common::printLink('story', 'create', "product=$bug->product&module=0&story=0&project=0&bugID=$bug->id", $lang->bug->toStory) . ' ';
- }
- else
- {
- echo $lang->bug->toStory . ' ';
- }
- common::printLink('testcase', 'create', $convertParams, $lang->bug->buttonCreateTestcase);
- common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin');
- }
- echo html::a($browseLink, $lang->goback);
- ?>
-
-
-
-
-
-
-
- bug->legendSteps;?>
-
-
- fetch('file', 'printFiles', array('files' => $bug->files, 'fieldset' => 'true'));?>
-
-
- deleted)
- {
- if(!($bug->status == 'active' and $bug->confirmed == 0 and common::printLink('bug', 'confirmBug', $params, $lang->bug->buttonConfirm))) echo $lang->bug->buttonConfirm . ' ';
- if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' ';
- common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit);
- if(common::hasPriv('bug', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' ';
- if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' ';
- if(!(($bug->status == 'closed' or $bug->status == 'resolved') and $bug->resolution != 'tostory' and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' ';
- common::printLink('bug', 'create', $copyParams, $lang->bug->buttonCopy);
- if($bug->status == 'active' and common::hasPriv('bug', 'resolve'))
- {
- common::printLink('story', 'create', "product=$bug->product&module=0&story=0&project=0&bugID=$bug->id", $lang->bug->toStory) . ' ';
- }
- else
- {
- echo $lang->bug->toStory . ' ';
- }
- common::printLink('testcase', 'create', $convertParams, $lang->bug->buttonCreateTestcase);
- common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin');
- }
- echo html::a($browseLink, $lang->goback);
- ?>
-
-
-
-
-
-
- bug->legendBasicInfo;?>
-
-
- bug->product;?>
- product", $productName)) echo $productName;?>
-
-
- bug->module;?>
-
- $module)
- {
- if(!common::printLink('bug', 'browse', "productID=$bug->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name;
- if(isset($modulePath[$key + 1])) echo $lang->arrow;
- }
- ?>
-
-
-
- bug->type;?>
- bug->typeList[$bug->type])) echo $lang->bug->typeList[$bug->type]; else echo $bug->type;?>
-
-
- bug->severity;?>
- bug->severityList[$bug->severity];?>
-
-
- bug->pri;?>
- bug->priList[$bug->pri];?>
-
-
- bug->status;?>
- bug->statusList[$bug->status];?>
-
-
- bug->activatedCount;?>
- activatedCount;?>
-
-
- bug->confirmed;?>
- bug->confirmedList[$bug->confirmed];?>
-
-
- bug->lblAssignedTo;?>
- assignedTo) echo $users[$bug->assignedTo] . $lang->at . $bug->assignedDate;?>
-
-
- bug->os;?>
- bug->osList[$bug->os];?>
-
-
- bug->browser;?>
- bug->browserList[$bug->browser];?>
-
-
- bug->keywords;?>
- keywords;?>
-
-
-
-
- bug->legendLife;?>
-
-
- bug->openedBy;?>
- openedBy] . $lang->at . $bug->openedDate;?>
-
-
- bug->openedBuild;?>
-
- openedBuild)
- {
- $openedBuilds = explode(',', $bug->openedBuild);
- foreach($openedBuilds as $openedBuild) isset($builds[$openedBuild]) ? print($builds[$openedBuild] . ' ') : print($openedBuild . ' ');
- }
- else
- {
- echo $bug->openedBuild;
- }
- ?>
-
-
-
- bug->lblResolved;?>
- resolvedBy) echo $users[$bug->resolvedBy] . $lang->at . $bug->resolvedDate;?>
-
-
- bug->resolvedBuild;?>
- resolvedBuild])) echo $builds[$bug->resolvedBuild]; else echo $bug->resolvedBuild;?>
-
-
- bug->resolution;?>
-
- bug->resolutionList[$bug->resolution];
- if(isset($bug->duplicateBugTitle)) echo " #$bug->duplicateBug:" . html::a($this->createLink('bug', 'view', "bugID=$bug->duplicateBug"), $bug->duplicateBugTitle);
- ?>
-
-
-
- bug->closedBy;?>
- closedBy) echo $users[$bug->closedBy] . $lang->at . $bug->closedDate;?>
-
-
- bug->lblLastEdited;?>
- lastEditedBy) echo $users[$bug->lastEditedBy] . $lang->at . $bug->lastEditedDate?>
-
-
-
-
-
- bug->legendPrjStoryTask;?>
-
-
- bug->project;?>
- project) echo html::a($this->createLink('project', 'browse', "projectid=$bug->project"), $bug->projectName);?>
-
-
- bug->story;?>
-
- story) echo html::a($this->createLink('story', 'view', "storyID=$bug->story"), $bug->storyTitle);
- if($bug->storyStatus == 'active' and $bug->latestStoryVersion > $bug->storyVersion)
- {
- echo "({$lang->story->changed} ";
- echo html::a($this->createLink('bug', 'confirmStoryChange', "bugID=$bug->id"), $lang->confirm, 'hiddenwin');
- echo ")";
- }
- ?>
-
-
-
- bug->task;?>
- task) echo html::a($this->createLink('task', 'view', "taskID=$bug->task"), $bug->taskName);?>
-
-
-
-
- bug->legendMisc;?>
-
-
- bug->mailto;?>
- mailto)); foreach($mailto as $account) echo ' ' . $users[$account]; ?>
-
-
- bug->linkBug;?>
-
- linkBugTitles))
- {
- foreach($bug->linkBugTitles as $linkBugID => $linkBugTitle)
- {
- echo html::a($this->createLink('bug', 'view', "bugID=$linkBugID"), "#$linkBugID $linkBugTitle", '_blank') . ' ';
- }
- }
- ?>
-
-
-
- bug->case;?>
- caseTitle)) echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case"), "#$bug->case $bug->caseTitle", '_blank');?>
-
-
- bug->toStory;?>
- toStory != 0) echo html::a($this->createLink('story', 'view', "storyID=$bug->toStory"), "#$bug->toStory $bug->toStoryTitle", '_blank');?>
-
-
- bug->toTask;?>
- toTask != 0) echo html::a($this->createLink('bug', 'view', "bugID=$bug->toTask"), "#$bug->toTask $bug->toTaskTitle", '_blank');?>
-
-
-
-
-
-
-
+
+ * @package bug
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
deleted) echo "class='deleted'";?>>BUG #id . $lang->colon . $bug->title;?>
+
+ session->bugList != false ? $app->session->bugList : inlink('browse', "productID=$bug->product");
+ $params = "bugID=$bug->id";
+ $copyParams = "productID=$productID&extras=bugID=$bug->id";
+ $convertParams = "productID=$productID&moduleID=0&from=bug&bugID=$bug->id";
+ if(!$bug->deleted)
+ {
+ if(!($bug->status == 'active' and $bug->confirmed == 0 and common::printLink('bug', 'confirmBug', $params, $lang->bug->buttonConfirm))) echo $lang->bug->buttonConfirm . ' ';
+ if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' ';
+ common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit);
+ if(common::hasPriv('bug', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' ';
+ if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' ';
+ if(!(($bug->status == 'closed' or $bug->status == 'resolved') and $bug->resolution != 'tostory' and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' ';
+ common::printLink('bug', 'create', $copyParams, $lang->bug->buttonCopy);
+ if($bug->status == 'active' and common::hasPriv('story', 'create'))
+ {
+ common::printLink('story', 'create', "product=$bug->product&module=0&story=0&project=0&bugID=$bug->id", $lang->bug->toStory) . ' ';
+ }
+ else
+ {
+ echo $lang->bug->toStory . ' ';
+ }
+ common::printLink('testcase', 'create', $convertParams, $lang->bug->buttonCreateTestcase);
+ common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin');
+ }
+ echo html::a($browseLink, $lang->goback);
+ ?>
+
+
+
+
+
+
+
+ bug->legendSteps;?>
+
+
+ fetch('file', 'printFiles', array('files' => $bug->files, 'fieldset' => 'true'));?>
+
+
+ deleted)
+ {
+ if(!($bug->status == 'active' and $bug->confirmed == 0 and common::printLink('bug', 'confirmBug', $params, $lang->bug->buttonConfirm))) echo $lang->bug->buttonConfirm . ' ';
+ if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' ';
+ common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit);
+ if(common::hasPriv('bug', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' ';
+ if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' ';
+ if(!(($bug->status == 'closed' or $bug->status == 'resolved') and $bug->resolution != 'tostory' and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' ';
+ common::printLink('bug', 'create', $copyParams, $lang->bug->buttonCopy);
+ if($bug->status == 'active' and common::hasPriv('bug', 'resolve'))
+ {
+ common::printLink('story', 'create', "product=$bug->product&module=0&story=0&project=0&bugID=$bug->id", $lang->bug->toStory) . ' ';
+ }
+ else
+ {
+ echo $lang->bug->toStory . ' ';
+ }
+ common::printLink('testcase', 'create', $convertParams, $lang->bug->buttonCreateTestcase);
+ common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin');
+ }
+ echo html::a($browseLink, $lang->goback);
+ ?>
+
+
+
+
+
+
+ bug->legendBasicInfo;?>
+
+
+ bug->product;?>
+ product", $productName)) echo $productName;?>
+
+
+ bug->module;?>
+
+ $module)
+ {
+ if(!common::printLink('bug', 'browse', "productID=$bug->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name;
+ if(isset($modulePath[$key + 1])) echo $lang->arrow;
+ }
+ ?>
+
+
+
+ bug->type;?>
+ bug->typeList[$bug->type])) echo $lang->bug->typeList[$bug->type]; else echo $bug->type;?>
+
+
+ bug->severity;?>
+ bug->severityList[$bug->severity];?>
+
+
+ bug->pri;?>
+ bug->priList[$bug->pri];?>
+
+
+ bug->status;?>
+ bug->statusList[$bug->status];?>
+
+
+ bug->activatedCount;?>
+ activatedCount;?>
+
+
+ bug->confirmed;?>
+ bug->confirmedList[$bug->confirmed];?>
+
+
+ bug->lblAssignedTo;?>
+ assignedTo) echo $users[$bug->assignedTo] . $lang->at . $bug->assignedDate;?>
+
+
+ bug->os;?>
+ bug->osList[$bug->os];?>
+
+
+ bug->browser;?>
+ bug->browserList[$bug->browser];?>
+
+
+ bug->keywords;?>
+ keywords;?>
+
+
+
+
+ bug->legendLife;?>
+
+
+ bug->openedBy;?>
+ openedBy] . $lang->at . $bug->openedDate;?>
+
+
+ bug->openedBuild;?>
+
+ openedBuild)
+ {
+ $openedBuilds = explode(',', $bug->openedBuild);
+ foreach($openedBuilds as $openedBuild) isset($builds[$openedBuild]) ? print($builds[$openedBuild] . ' ') : print($openedBuild . ' ');
+ }
+ else
+ {
+ echo $bug->openedBuild;
+ }
+ ?>
+
+
+
+ bug->lblResolved;?>
+ resolvedBy) echo $users[$bug->resolvedBy] . $lang->at . $bug->resolvedDate;?>
+
+
+ bug->resolvedBuild;?>
+ resolvedBuild])) echo $builds[$bug->resolvedBuild]; else echo $bug->resolvedBuild;?>
+
+
+ bug->resolution;?>
+
+ bug->resolutionList[$bug->resolution];
+ if(isset($bug->duplicateBugTitle)) echo " #$bug->duplicateBug:" . html::a($this->createLink('bug', 'view', "bugID=$bug->duplicateBug"), $bug->duplicateBugTitle);
+ ?>
+
+
+
+ bug->closedBy;?>
+ closedBy) echo $users[$bug->closedBy] . $lang->at . $bug->closedDate;?>
+
+
+ bug->lblLastEdited;?>
+ lastEditedBy) echo $users[$bug->lastEditedBy] . $lang->at . $bug->lastEditedDate?>
+
+
+
+
+
+ bug->legendPrjStoryTask;?>
+
+
+ bug->project;?>
+ project) echo html::a($this->createLink('project', 'browse', "projectid=$bug->project"), $bug->projectName);?>
+
+
+ bug->story;?>
+
+ story) echo html::a($this->createLink('story', 'view', "storyID=$bug->story"), $bug->storyTitle);
+ if($bug->storyStatus == 'active' and $bug->latestStoryVersion > $bug->storyVersion)
+ {
+ echo "({$lang->story->changed} ";
+ echo html::a($this->createLink('bug', 'confirmStoryChange', "bugID=$bug->id"), $lang->confirm, 'hiddenwin');
+ echo ")";
+ }
+ ?>
+
+
+
+ bug->task;?>
+ task) echo html::a($this->createLink('task', 'view', "taskID=$bug->task"), $bug->taskName);?>
+
+
+
+
+ bug->legendMisc;?>
+
+
+ bug->mailto;?>
+ mailto)); foreach($mailto as $account) echo ' ' . $users[$account]; ?>
+
+
+ bug->linkBug;?>
+
+ linkBugTitles))
+ {
+ foreach($bug->linkBugTitles as $linkBugID => $linkBugTitle)
+ {
+ echo html::a($this->createLink('bug', 'view', "bugID=$linkBugID"), "#$linkBugID $linkBugTitle", '_blank') . ' ';
+ }
+ }
+ ?>
+
+
+
+ bug->case;?>
+ caseTitle)) echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case"), "#$bug->case $bug->caseTitle", '_blank');?>
+
+
+ bug->toStory;?>
+ toStory != 0) echo html::a($this->createLink('story', 'view', "storyID=$bug->toStory"), "#$bug->toStory $bug->toStoryTitle", '_blank');?>
+
+
+ bug->toTask;?>
+ toTask != 0) echo html::a($this->createLink('bug', 'view', "bugID=$bug->toTask"), "#$bug->toTask $bug->toTaskTitle", '_blank');?>
+
+
+
+
+
+
+
diff --git a/module/build/control.php b/module/build/control.php
index 8bd52d35d2..0f06d9560a 100644
--- a/module/build/control.php
+++ b/module/build/control.php
@@ -1,186 +1,186 @@
-
- * @package build
- * @version $Id$
- * @link http://www.zentao.net
- */
-class build extends control
-{
- /**
- * Create a buld.
- *
- * @param int $projectID
- * @access public
- * @return void
- */
- public function create($projectID)
- {
- if(!empty($_POST))
- {
- $buildID = $this->build->create($projectID);
- if(dao::isError()) die(js::error(dao::getError()));
- $this->loadModel('action')->create('build', $buildID, 'opened');
- die(js::locate($this->createLink('project', 'build', "project=$projectID"), 'parent'));
- }
-
- /* Load these models. */
- $this->loadModel('story');
- $this->loadModel('bug');
- $this->loadModel('task');
- $this->loadModel('project');
- $this->loadModel('user');
-
- /* Set menu. */
- $this->project->setMenu($this->project->getPairs(), $projectID);
-
- /* Get stories and bugs. */
- $orderBy = 'status_asc, stage_asc, id_desc';
- $stories = $this->story->getProjectStories($projectID, $orderBy);
- $bugs = $this->project->getResolvedBugs($projectID);
-
- /* Assign. */
- $this->view->header->title = $this->lang->build->create;
- $this->view->products = $this->project->getProducts($projectID);
- $this->view->projectID = $projectID;
- $this->view->users = $this->user->getPairs();
- $this->view->stories = $stories;
- $this->view->bugs = $bugs;
- $this->view->orderBy = $orderBy;
- $this->display();
- }
-
- /**
- * Edit a build.
- *
- * @param int $buildID
- * @access public
- * @return void
- */
- public function edit($buildID)
- {
- if(!empty($_POST))
- {
- $changes = $this->build->update($buildID);
- if(dao::isError()) die(js::error(dao::getError()));
- if($changes)
- {
- $actionID = $this->loadModel('action')->create('build', $buildID, 'edited');
- $this->action->logHistory($actionID, $changes);
- }
- die(js::locate(inlink('view', "buildID=$buildID"), 'parent'));
- }
-
- $this->loadModel('story');
- $this->loadModel('bug');
- $this->loadModel('project');
-
- /* Set menu. */
- $build = $this->build->getById((int)$buildID);
- $this->project->setMenu($this->project->getPairs(), $build->project);
-
- /* Get stories and bugs. */
- $orderBy = 'status_asc, stage_asc, id_desc';
- $stories = $this->story->getProjectStories($build->project, $orderBy);
- $bugs = $this->project->getResolvedBugs($build->project);
-
- /* Assign. */
- $this->view->header->title = $this->lang->build->edit;
- $this->view->position[] = $this->lang->build->edit;
- $this->view->products = $this->project->getProducts($build->project);
- $this->view->users = $this->loadModel('user')->getPairs();
- $this->view->build = $build;
- $this->view->stories = $stories;
- $this->view->bugs = $bugs;
- $this->view->orderBy = $orderBy;
- $this->display();
- }
-
- /**
- * View a build.
- *
- * @param int $buildID
- * @access public
- * @return void
- */
- public function view($buildID)
- {
- $this->loadModel('story');
- $this->loadModel('bug');
-
- /* Set menu. */
- $build = $this->build->getById((int)$buildID);
- if(!$build) die(js::error($this->lang->notFound) . js::locate('back'));
- $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($build->stories)->fetchAll();
- $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($build->bugs)->fetchAll();
-
- $this->loadModel('project')->setMenu($this->project->getPairs(), $build->project);
-
- /* Assign. */
- $this->view->header->title = $this->lang->build->view;
- $this->view->position[] = $this->lang->build->view;
- $this->view->products = $this->project->getProducts($build->project);
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
- $this->view->build = $build;
- $this->view->stories = $stories;
- $this->view->bugs = $bugs;
- $this->view->actions = $this->loadModel('action')->getList('build', $buildID);
- $this->display();
- }
-
- /**
- * Delete a build.
- *
- * @param int $buildID
- * @param string $confirm yes|noe
- * @access public
- * @return void
- */
- public function delete($buildID, $confirm = 'no')
- {
- if($confirm == 'no')
- {
- die(js::confirm($this->lang->build->confirmDelete, $this->createLink('build', 'delete', "buildID=$buildID&confirm=yes")));
- }
- else
- {
- $build = $this->build->getById($buildID);
- $this->build->delete(TABLE_BUILD, $buildID);
- die(js::locate($this->createLink('project', 'build', "projectID=$build->project"), 'parent'));
- }
- }
-
- /**
- * AJAX: get builds of a product in html select.
- *
- * @param int $productID
- * @param string $varName the name of the select object to create
- * @param string $build build to selected
- * @access public
- * @return string
- */
- public function ajaxGetProductBuilds($productID, $varName, $build = '')
- {
- if($varName == 'openedBuild') die(html::select($varName . '[]', $this->build->getProductBuildPairs($productID, 'noempty'), $build, 'size=4 class=select-3 multiple'));
- if($varName == 'resolvedBuild') die(html::select($varName, $this->build->getProductBuildPairs($productID, 'noempty'), $build, 'class=select-3'));
- }
-
- /**
- * AJAX: get builds of a project in html select.
- *
- * @param int $projectID
- * @param string $varName the name of the select object to create
- * @param string $build build to selected
- * @access public
- * @return string
- */
- public function ajaxGetProjectBuilds($projectID, $productID, $varName, $build = '')
- {
- if($varName == 'openedBuild') die(html::select($varName . '[]', $this->build->getProjectBuildPairs($projectID, $productID, 'noempty'), $build, 'size=4 class=select-3 multiple'));
- if($varName == 'resolvedBuild') die(html::select($varName, $this->build->getProjectBuildPairs($projectID, $productID, 'noempty'), $build, 'class=select-3'));
- }
-}
+
+ * @package build
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class build extends control
+{
+ /**
+ * Create a buld.
+ *
+ * @param int $projectID
+ * @access public
+ * @return void
+ */
+ public function create($projectID)
+ {
+ if(!empty($_POST))
+ {
+ $buildID = $this->build->create($projectID);
+ if(dao::isError()) die(js::error(dao::getError()));
+ $this->loadModel('action')->create('build', $buildID, 'opened');
+ die(js::locate($this->createLink('project', 'build', "project=$projectID"), 'parent'));
+ }
+
+ /* Load these models. */
+ $this->loadModel('story');
+ $this->loadModel('bug');
+ $this->loadModel('task');
+ $this->loadModel('project');
+ $this->loadModel('user');
+
+ /* Set menu. */
+ $this->project->setMenu($this->project->getPairs(), $projectID);
+
+ /* Get stories and bugs. */
+ $orderBy = 'status_asc, stage_asc, id_desc';
+ $stories = $this->story->getProjectStories($projectID, $orderBy);
+ $bugs = $this->project->getResolvedBugs($projectID);
+
+ /* Assign. */
+ $this->view->header->title = $this->lang->build->create;
+ $this->view->products = $this->project->getProducts($projectID);
+ $this->view->projectID = $projectID;
+ $this->view->users = $this->user->getPairs();
+ $this->view->stories = $stories;
+ $this->view->bugs = $bugs;
+ $this->view->orderBy = $orderBy;
+ $this->display();
+ }
+
+ /**
+ * Edit a build.
+ *
+ * @param int $buildID
+ * @access public
+ * @return void
+ */
+ public function edit($buildID)
+ {
+ if(!empty($_POST))
+ {
+ $changes = $this->build->update($buildID);
+ if(dao::isError()) die(js::error(dao::getError()));
+ if($changes)
+ {
+ $actionID = $this->loadModel('action')->create('build', $buildID, 'edited');
+ $this->action->logHistory($actionID, $changes);
+ }
+ die(js::locate(inlink('view', "buildID=$buildID"), 'parent'));
+ }
+
+ $this->loadModel('story');
+ $this->loadModel('bug');
+ $this->loadModel('project');
+
+ /* Set menu. */
+ $build = $this->build->getById((int)$buildID);
+ $this->project->setMenu($this->project->getPairs(), $build->project);
+
+ /* Get stories and bugs. */
+ $orderBy = 'status_asc, stage_asc, id_desc';
+ $stories = $this->story->getProjectStories($build->project, $orderBy);
+ $bugs = $this->project->getResolvedBugs($build->project);
+
+ /* Assign. */
+ $this->view->header->title = $this->lang->build->edit;
+ $this->view->position[] = $this->lang->build->edit;
+ $this->view->products = $this->project->getProducts($build->project);
+ $this->view->users = $this->loadModel('user')->getPairs();
+ $this->view->build = $build;
+ $this->view->stories = $stories;
+ $this->view->bugs = $bugs;
+ $this->view->orderBy = $orderBy;
+ $this->display();
+ }
+
+ /**
+ * View a build.
+ *
+ * @param int $buildID
+ * @access public
+ * @return void
+ */
+ public function view($buildID)
+ {
+ $this->loadModel('story');
+ $this->loadModel('bug');
+
+ /* Set menu. */
+ $build = $this->build->getById((int)$buildID);
+ if(!$build) die(js::error($this->lang->notFound) . js::locate('back'));
+ $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($build->stories)->fetchAll();
+ $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($build->bugs)->fetchAll();
+
+ $this->loadModel('project')->setMenu($this->project->getPairs(), $build->project);
+
+ /* Assign. */
+ $this->view->header->title = $this->lang->build->view;
+ $this->view->position[] = $this->lang->build->view;
+ $this->view->products = $this->project->getProducts($build->project);
+ $this->view->users = $this->loadModel('user')->getPairs('noletter');
+ $this->view->build = $build;
+ $this->view->stories = $stories;
+ $this->view->bugs = $bugs;
+ $this->view->actions = $this->loadModel('action')->getList('build', $buildID);
+ $this->display();
+ }
+
+ /**
+ * Delete a build.
+ *
+ * @param int $buildID
+ * @param string $confirm yes|noe
+ * @access public
+ * @return void
+ */
+ public function delete($buildID, $confirm = 'no')
+ {
+ if($confirm == 'no')
+ {
+ die(js::confirm($this->lang->build->confirmDelete, $this->createLink('build', 'delete', "buildID=$buildID&confirm=yes")));
+ }
+ else
+ {
+ $build = $this->build->getById($buildID);
+ $this->build->delete(TABLE_BUILD, $buildID);
+ die(js::locate($this->createLink('project', 'build', "projectID=$build->project"), 'parent'));
+ }
+ }
+
+ /**
+ * AJAX: get builds of a product in html select.
+ *
+ * @param int $productID
+ * @param string $varName the name of the select object to create
+ * @param string $build build to selected
+ * @access public
+ * @return string
+ */
+ public function ajaxGetProductBuilds($productID, $varName, $build = '')
+ {
+ if($varName == 'openedBuild') die(html::select($varName . '[]', $this->build->getProductBuildPairs($productID, 'noempty'), $build, 'size=4 class=select-3 multiple'));
+ if($varName == 'resolvedBuild') die(html::select($varName, $this->build->getProductBuildPairs($productID, 'noempty'), $build, 'class=select-3'));
+ }
+
+ /**
+ * AJAX: get builds of a project in html select.
+ *
+ * @param int $projectID
+ * @param string $varName the name of the select object to create
+ * @param string $build build to selected
+ * @access public
+ * @return string
+ */
+ public function ajaxGetProjectBuilds($projectID, $productID, $varName, $build = '')
+ {
+ if($varName == 'openedBuild') die(html::select($varName . '[]', $this->build->getProjectBuildPairs($projectID, $productID, 'noempty'), $build, 'size=4 class=select-3 multiple'));
+ if($varName == 'resolvedBuild') die(html::select($varName, $this->build->getProjectBuildPairs($projectID, $productID, 'noempty'), $build, 'class=select-3'));
+ }
+}
diff --git a/module/build/lang/en.php b/module/build/lang/en.php
index a2b8b6e998..2ab6393426 100644
--- a/module/build/lang/en.php
+++ b/module/build/lang/en.php
@@ -1,35 +1,35 @@
-
- * @package build
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->build->common = 'Build';
-$lang->build->create = "Create";
-$lang->build->edit = "Edit";
-$lang->build->delete = "Delete";
-$lang->build->view = "Info";
-$lang->build->ajaxGetProductBuilds = 'API:Product builds';
-$lang->build->ajaxGetProjectBuilds = 'API:Project builds';
-
-$lang->build->confirmDelete = "Are sure to delete this build?";
-
-$lang->build->id = 'ID';
-$lang->build->product = 'Product';
-$lang->build->project = 'Project';
-$lang->build->name = 'Name';
-$lang->build->date = 'Build date';
-$lang->build->builder = 'Builder';
-$lang->build->scmPath = 'Source code path';
-$lang->build->filePath = 'Package file path';
-$lang->build->desc = 'Desc';
-$lang->build->linkStoriesAndBugs = 'stories and bugs';
-$lang->build->linkStories = 'Stories';
-$lang->build->linkBugs = 'Bugs';
-$lang->build->stories = 'Linked stories';
-$lang->build->bugs = 'Linked bugs';
+
+ * @package build
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->build->common = 'Build';
+$lang->build->create = "Create";
+$lang->build->edit = "Edit";
+$lang->build->delete = "Delete";
+$lang->build->view = "Info";
+$lang->build->ajaxGetProductBuilds = 'API:Product builds';
+$lang->build->ajaxGetProjectBuilds = 'API:Project builds';
+
+$lang->build->confirmDelete = "Are sure to delete this build?";
+
+$lang->build->id = 'ID';
+$lang->build->product = 'Product';
+$lang->build->project = 'Project';
+$lang->build->name = 'Name';
+$lang->build->date = 'Build date';
+$lang->build->builder = 'Builder';
+$lang->build->scmPath = 'Source code path';
+$lang->build->filePath = 'Package file path';
+$lang->build->desc = 'Desc';
+$lang->build->linkStoriesAndBugs = 'stories and bugs';
+$lang->build->linkStories = 'Stories';
+$lang->build->linkBugs = 'Bugs';
+$lang->build->stories = 'Linked stories';
+$lang->build->bugs = 'Linked bugs';
diff --git a/module/build/lang/zh-cn.php b/module/build/lang/zh-cn.php
index 94923144f5..91e7c9483a 100644
--- a/module/build/lang/zh-cn.php
+++ b/module/build/lang/zh-cn.php
@@ -1,35 +1,35 @@
-
- * @package build
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->build->common = 'Build';
-$lang->build->create = "创建Build";
-$lang->build->edit = "编辑Build";
-$lang->build->delete = "删除Build";
-$lang->build->view = "Build详情";
-$lang->build->ajaxGetProductBuilds = '接口:产品Build列表';
-$lang->build->ajaxGetProjectBuilds = '接口:项目Build列表';
-
-$lang->build->confirmDelete = "您确认删除该build吗?";
-
-$lang->build->id = 'ID';
-$lang->build->product = '产品';
-$lang->build->project = '项目';
-$lang->build->name = '名称编号';
-$lang->build->date = 'Build日期';
-$lang->build->builder = '构建者';
-$lang->build->scmPath = '源代码地址';
-$lang->build->filePath = '存储地址';
-$lang->build->desc = '描述';
-$lang->build->linkStoriesAndBugs = '关联需求和Bug';
-$lang->build->linkStories = '相关需求';
-$lang->build->linkBugs = '相关Bug';
-$lang->build->stories = '已关联需求';
-$lang->build->bugs = '已关联Bug';
+
+ * @package build
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->build->common = 'Build';
+$lang->build->create = "创建Build";
+$lang->build->edit = "编辑Build";
+$lang->build->delete = "删除Build";
+$lang->build->view = "Build详情";
+$lang->build->ajaxGetProductBuilds = '接口:产品Build列表';
+$lang->build->ajaxGetProjectBuilds = '接口:项目Build列表';
+
+$lang->build->confirmDelete = "您确认删除该build吗?";
+
+$lang->build->id = 'ID';
+$lang->build->product = '产品';
+$lang->build->project = '项目';
+$lang->build->name = '名称编号';
+$lang->build->date = 'Build日期';
+$lang->build->builder = '构建者';
+$lang->build->scmPath = '源代码地址';
+$lang->build->filePath = '存储地址';
+$lang->build->desc = '描述';
+$lang->build->linkStoriesAndBugs = '关联需求和Bug';
+$lang->build->linkStories = '相关需求';
+$lang->build->linkBugs = '相关Bug';
+$lang->build->stories = '已关联需求';
+$lang->build->bugs = '已关联Bug';
diff --git a/module/build/lang/zh-tw.php b/module/build/lang/zh-tw.php
index 05136eaa55..a7830c1a9f 100644
--- a/module/build/lang/zh-tw.php
+++ b/module/build/lang/zh-tw.php
@@ -1,35 +1,35 @@
-
- * @package build
- * @version $Id: zh-tw.php 2527 2012-01-04 00:16:23Z wwccss $
- * @link http://www.zentao.net
- */
-$lang->build->common = 'Build';
-$lang->build->create = "創建Build";
-$lang->build->edit = "編輯Build";
-$lang->build->delete = "刪除Build";
-$lang->build->view = "Build詳情";
-$lang->build->ajaxGetProductBuilds = '介面:產品Build列表';
-$lang->build->ajaxGetProjectBuilds = '介面:項目Build列表';
-
-$lang->build->confirmDelete = "您確認刪除該build嗎?";
-
-$lang->build->id = 'ID';
-$lang->build->product = '產品';
-$lang->build->project = '項目';
-$lang->build->name = '名稱編號';
-$lang->build->date = 'Build日期';
-$lang->build->builder = '構建者';
-$lang->build->scmPath = '原始碼地址';
-$lang->build->filePath = '存儲地址';
-$lang->build->desc = '描述';
-$lang->build->linkStoriesAndBugs = '關聯需求和Bug';
-$lang->build->linkStories = '相關需求';
-$lang->build->linkBugs = '相關Bug';
-$lang->build->stories = '已關聯需求';
-$lang->build->bugs = '已關聯Bug';
+
+ * @package build
+ * @version $Id: zh-tw.php 2527 2012-01-04 00:16:23Z wwccss $
+ * @link http://www.zentao.net
+ */
+$lang->build->common = 'Build';
+$lang->build->create = "創建Build";
+$lang->build->edit = "編輯Build";
+$lang->build->delete = "刪除Build";
+$lang->build->view = "Build詳情";
+$lang->build->ajaxGetProductBuilds = '介面:產品Build列表';
+$lang->build->ajaxGetProjectBuilds = '介面:項目Build列表';
+
+$lang->build->confirmDelete = "您確認刪除該build嗎?";
+
+$lang->build->id = 'ID';
+$lang->build->product = '產品';
+$lang->build->project = '項目';
+$lang->build->name = '名稱編號';
+$lang->build->date = 'Build日期';
+$lang->build->builder = '構建者';
+$lang->build->scmPath = '原始碼地址';
+$lang->build->filePath = '存儲地址';
+$lang->build->desc = '描述';
+$lang->build->linkStoriesAndBugs = '關聯需求和Bug';
+$lang->build->linkStories = '相關需求';
+$lang->build->linkBugs = '相關Bug';
+$lang->build->stories = '已關聯需求';
+$lang->build->bugs = '已關聯Bug';
diff --git a/module/build/model.php b/module/build/model.php
index e0027f909b..7d16a89d8f 100644
--- a/module/build/model.php
+++ b/module/build/model.php
@@ -1,152 +1,152 @@
-
- * @package build
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-dao->select('t1.*, t2.name as projectName, t3.name as productName')
- ->from(TABLE_BUILD)->alias('t1')
- ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
- ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
- ->where('t1.id')->eq((int)$buildID)
- ->orderBy('t1.id DESC')
- ->fetch();
- if(!$build) return false;
- $build->desc = $this->loadModel('file')->setImgSize($build->desc);
- return $build;
- }
-
- /**
- * Get builds of a project.
- *
- * @param int $projectID
- * @access public
- * @return array
- */
- public function getProjectBuilds($projectID)
- {
- return $this->dao->select('t1.*, t2.name as projectName, t3.name as productName')
- ->from(TABLE_BUILD)->alias('t1')
- ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
- ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
- ->where('t1.project')->eq((int)$projectID)
- ->andWhere('t1.deleted')->eq(0)
- ->orderBy('t1.date DESC, t1.id desc')
- ->fetchAll();
- }
-
- /**
- * Get builds of a project in pairs.
- *
- * @param int $projectID
- * @param int $productID
- * @param string $params noempty|notrunk, can be a set of them
- * @access public
- * @return array
- */
- public function getProjectBuildPairs($projectID, $productID, $params = '')
- {
- $sysBuilds = array();
- if(strpos($params, 'noempty') === false) $sysBuilds = array('' => '');
- if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => 'Trunk');
-
- $builds = $this->dao->select('id,name')->from(TABLE_BUILD)
- ->where('project')->eq((int)$projectID)
- ->beginIF($productID)->andWhere('product')->eq((int)$productID)->fi()
- ->andWhere('deleted')->eq(0)
- ->orderBy('date desc, id desc')->fetchPairs();
- if(!$builds) return $sysBuilds;
- $releases = $this->dao->select('build,name')->from(TABLE_RELEASE)
- ->where('build')->in(array_keys($builds))
- ->andWhere('deleted')->eq(0)
- ->fetchPairs();
- foreach($releases as $buildID => $releaseName) $builds[$buildID] = $releaseName;
- return $sysBuilds + $builds;
- }
-
- /**
- * Get builds of a product in pairs.
- *
- * @param int $productID
- * @param string $params noempty|notrunk, can be a set of them
- * @access public
- * @return string
- */
- public function getProductBuildPairs($productID, $params = '')
- {
- $sysBuilds = array();
- if(strpos($params, 'noempty') === false) $sysBuilds = array('' => '');
- if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => 'Trunk');
-
- $builds = $this->dao->select('id,name')->from(TABLE_BUILD)
- ->where('product')->eq((int)$productID)
- ->andWhere('deleted')->eq(0)
- ->orderBy('date desc, id desc')->fetchPairs();
- if(!$builds) return $sysBuilds;
- return $sysBuilds + $builds;
- }
-
- /**
- * Create a build
- *
- * @param int $projectID
- * @access public
- * @return void
- */
- public function create($projectID)
- {
- $build->stories = '';
- $build->bugs = '';
-
- $build = fixer::input('post')->stripTags('name')
- ->join('stories', ',')
- ->join('bugs', ',')
- ->add('project', (int)$projectID)->get();
- $this->dao->insert(TABLE_BUILD)->data($build)->autoCheck()->batchCheck($this->config->build->create->requiredFields, 'notempty')->check('name','unique')->exec();
- if(!dao::isError()) return $this->dao->lastInsertID();
- }
-
- /**
- * Update a build.
- *
- * @param int $buildID
- * @access public
- * @return void
- */
- public function update($buildID)
- {
- $oldBuild = $this->getByID($buildID);
- $build = fixer::input('post')
- ->stripTags('name')
- ->setDefault('stories', '')
- ->setDefault('bugs', '')
- ->join('stories', ',')
- ->join('bugs', ',')
- ->get();
- $this->dao->update(TABLE_BUILD)->data($build)
- ->autoCheck()
- ->batchCheck($this->config->build->edit->requiredFields, 'notempty')
- ->where('id')->eq((int)$buildID)
- ->check('name','unique', "id != $buildID")
- ->exec();
- if(!dao::isError()) return common::createChanges($oldBuild, $build);
- }
-}
+
+ * @package build
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+dao->select('t1.*, t2.name as projectName, t3.name as productName')
+ ->from(TABLE_BUILD)->alias('t1')
+ ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
+ ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
+ ->where('t1.id')->eq((int)$buildID)
+ ->orderBy('t1.id DESC')
+ ->fetch();
+ if(!$build) return false;
+ $build->desc = $this->loadModel('file')->setImgSize($build->desc);
+ return $build;
+ }
+
+ /**
+ * Get builds of a project.
+ *
+ * @param int $projectID
+ * @access public
+ * @return array
+ */
+ public function getProjectBuilds($projectID)
+ {
+ return $this->dao->select('t1.*, t2.name as projectName, t3.name as productName')
+ ->from(TABLE_BUILD)->alias('t1')
+ ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
+ ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
+ ->where('t1.project')->eq((int)$projectID)
+ ->andWhere('t1.deleted')->eq(0)
+ ->orderBy('t1.date DESC, t1.id desc')
+ ->fetchAll();
+ }
+
+ /**
+ * Get builds of a project in pairs.
+ *
+ * @param int $projectID
+ * @param int $productID
+ * @param string $params noempty|notrunk, can be a set of them
+ * @access public
+ * @return array
+ */
+ public function getProjectBuildPairs($projectID, $productID, $params = '')
+ {
+ $sysBuilds = array();
+ if(strpos($params, 'noempty') === false) $sysBuilds = array('' => '');
+ if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => 'Trunk');
+
+ $builds = $this->dao->select('id,name')->from(TABLE_BUILD)
+ ->where('project')->eq((int)$projectID)
+ ->beginIF($productID)->andWhere('product')->eq((int)$productID)->fi()
+ ->andWhere('deleted')->eq(0)
+ ->orderBy('date desc, id desc')->fetchPairs();
+ if(!$builds) return $sysBuilds;
+ $releases = $this->dao->select('build,name')->from(TABLE_RELEASE)
+ ->where('build')->in(array_keys($builds))
+ ->andWhere('deleted')->eq(0)
+ ->fetchPairs();
+ foreach($releases as $buildID => $releaseName) $builds[$buildID] = $releaseName;
+ return $sysBuilds + $builds;
+ }
+
+ /**
+ * Get builds of a product in pairs.
+ *
+ * @param int $productID
+ * @param string $params noempty|notrunk, can be a set of them
+ * @access public
+ * @return string
+ */
+ public function getProductBuildPairs($productID, $params = '')
+ {
+ $sysBuilds = array();
+ if(strpos($params, 'noempty') === false) $sysBuilds = array('' => '');
+ if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => 'Trunk');
+
+ $builds = $this->dao->select('id,name')->from(TABLE_BUILD)
+ ->where('product')->eq((int)$productID)
+ ->andWhere('deleted')->eq(0)
+ ->orderBy('date desc, id desc')->fetchPairs();
+ if(!$builds) return $sysBuilds;
+ return $sysBuilds + $builds;
+ }
+
+ /**
+ * Create a build
+ *
+ * @param int $projectID
+ * @access public
+ * @return void
+ */
+ public function create($projectID)
+ {
+ $build->stories = '';
+ $build->bugs = '';
+
+ $build = fixer::input('post')->stripTags('name')
+ ->join('stories', ',')
+ ->join('bugs', ',')
+ ->add('project', (int)$projectID)->get();
+ $this->dao->insert(TABLE_BUILD)->data($build)->autoCheck()->batchCheck($this->config->build->create->requiredFields, 'notempty')->check('name','unique')->exec();
+ if(!dao::isError()) return $this->dao->lastInsertID();
+ }
+
+ /**
+ * Update a build.
+ *
+ * @param int $buildID
+ * @access public
+ * @return void
+ */
+ public function update($buildID)
+ {
+ $oldBuild = $this->getByID($buildID);
+ $build = fixer::input('post')
+ ->stripTags('name')
+ ->setDefault('stories', '')
+ ->setDefault('bugs', '')
+ ->join('stories', ',')
+ ->join('bugs', ',')
+ ->get();
+ $this->dao->update(TABLE_BUILD)->data($build)
+ ->autoCheck()
+ ->batchCheck($this->config->build->edit->requiredFields, 'notempty')
+ ->where('id')->eq((int)$buildID)
+ ->check('name','unique', "id != $buildID")
+ ->exec();
+ if(!dao::isError()) return common::createChanges($oldBuild, $build);
+ }
+}
diff --git a/module/build/view/create.html.php b/module/build/view/create.html.php
index 41b4bae324..7b07a201a7 100644
--- a/module/build/view/create.html.php
+++ b/module/build/view/create.html.php
@@ -1,97 +1,97 @@
-
- * @package build
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
-
-
- build->create;?>
-
- build->product;?>
-
-
-
- build->name;?>
-
-
-
- build->builder;?>
- user->account, 'class="select-3"');?>
-
-
- build->date;?>
-
-
-
- build->scmPath;?>
-
-
-
- build->filePath;?>
-
-
-
- build->linkStoriesAndBugs;?>
-
-
-
-
-
- build->desc;?>
-
-
-
-
-
-
+
+ * @package build
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+
+ build->create;?>
+
+ build->product;?>
+
+
+
+ build->name;?>
+
+
+
+ build->builder;?>
+ user->account, 'class="select-3"');?>
+
+
+ build->date;?>
+
+
+
+ build->scmPath;?>
+
+
+
+ build->filePath;?>
+
+
+
+ build->linkStoriesAndBugs;?>
+
+
+
+
+
+ build->desc;?>
+
+
+
+
+
+
diff --git a/module/build/view/edit.html.php b/module/build/view/edit.html.php
index 2e10bd353e..07e35e236e 100644
--- a/module/build/view/edit.html.php
+++ b/module/build/view/edit.html.php
@@ -1,97 +1,97 @@
-
- * @package build
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
-
-
- build->edit;?>
-
- build->product;?>
- product, "class='select-3'");?>
-
-
- build->name;?>
- name, "class='text-3'");?>
-
-
- build->builder;?>
- builder, 'class="select-3"');?>
-
-
- build->date;?>
- date, "class='text-3 date'");?>
-
-
- build->scmPath;?>
- scmPath, "class='text-1'");?>
-
-
- build->filePath;?>
- filePath, "class='text-1'");?>
-
-
- build->linkStoriesAndBugs;?>
-
-
-
-
-
- build->desc;?>
- desc), "rows='15' class='area-1'");?>
-
- project);?>
-
-
-
+
+ * @package build
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+
+ build->edit;?>
+
+ build->product;?>
+ product, "class='select-3'");?>
+
+
+ build->name;?>
+ name, "class='text-3'");?>
+
+
+ build->builder;?>
+ builder, 'class="select-3"');?>
+
+
+ build->date;?>
+ date, "class='text-3 date'");?>
+
+
+ build->scmPath;?>
+ scmPath, "class='text-1'");?>
+
+
+ build->filePath;?>
+ filePath, "class='text-1'");?>
+
+
+ build->linkStoriesAndBugs;?>
+
+
+
+
+
+ build->desc;?>
+ desc), "rows='15' class='area-1'");?>
+
+ project);?>
+
+
+
diff --git a/module/build/view/view.html.php b/module/build/view/view.html.php
index c8d94831f1..655d30cfc5 100644
--- a/module/build/view/view.html.php
+++ b/module/build/view/view.html.php
@@ -1,117 +1,117 @@
-
- * @package build
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
- build->view;?>
-
- build->product;?>
- productName;?>
-
-
- build->name;?>
- '>name;?>
-
-
- build->builder;?>
- builder];?>
-
-
- build->date;?>
- date;?>
-
-
- build->scmPath;?>
- scmPath, 'http') === 0 ? printf(html::a($build->scmPath)) : printf($build->scmPath);?>
-
-
- build->filePath;?>
- filePath, 'http') === 0 ? printf(html::a($build->filePath)) : printf($build->filePath);?>
-
-
- build->stories;?>
-
-
-
-
- idAB;?>
- priAB;?>
- story->title;?>
- openedByAB;?>
- story->estimateAB;?>
- statusAB;?>
- story->stageAB;?>
-
- $story):?>
- createLink('story', 'view', "storyID=$story->id");?>
-
- id);?>
- story->priList[$story->pri];?>
- title, '', "class='preview'");?>
- openedBy];?>
- estimate;?>
- story->statusList[$story->status];?>
- story->stageList[$story->stage];?>
-
-
-
-
-
-
-
- build->bugs;?>
-
-
-
-
- idAB;?>
- bug->title;?>
- bug->status;?>
- openedByAB;?>
- bug->openedDateAB;?>
- bug->resolvedByAB;?>
- bug->resolvedDateAB;?>
-
-
- createLink('bug', 'view', "bugID=$bug->id");?>
-
- id);?>
- title, '', "class='preview'");?>
- bug->statusList[$bug->status];?>
- openedBy];?>
- openedDate, 5, 11)?>
- resolvedBy];?>
- resolvedDate, 5, 11)?>
-
-
-
-
-
-
-
- build->desc;?>
- desc;?>
-
-
-
- session->buildList ? $this->session->buildList : $this->createLink('project', 'build', "projectID=$build->project");
- if(!$build->deleted)
- {
- common::printLink('build', 'edit', "buildID=$build->id", $lang->edit);
- common::printLink('build', 'delete', "buildID=$build->id", $lang->delete, 'hiddenwin');
- }
- echo html::a($browseLink, $lang->goback);
- ?>
-
-
-
+
+ * @package build
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+ build->view;?>
+
+ build->product;?>
+ productName;?>
+
+
+ build->name;?>
+ '>name;?>
+
+
+ build->builder;?>
+ builder];?>
+
+
+ build->date;?>
+ date;?>
+
+
+ build->scmPath;?>
+ scmPath, 'http') === 0 ? printf(html::a($build->scmPath)) : printf($build->scmPath);?>
+
+
+ build->filePath;?>
+ filePath, 'http') === 0 ? printf(html::a($build->filePath)) : printf($build->filePath);?>
+
+
+ build->stories;?>
+
+
+
+
+ idAB;?>
+ priAB;?>
+ story->title;?>
+ openedByAB;?>
+ story->estimateAB;?>
+ statusAB;?>
+ story->stageAB;?>
+
+ $story):?>
+ createLink('story', 'view', "storyID=$story->id");?>
+
+ id);?>
+ story->priList[$story->pri];?>
+ title, '', "class='preview'");?>
+ openedBy];?>
+ estimate;?>
+ story->statusList[$story->status];?>
+ story->stageList[$story->stage];?>
+
+
+
+
+
+
+
+ build->bugs;?>
+
+
+
+
+ idAB;?>
+ bug->title;?>
+ bug->status;?>
+ openedByAB;?>
+ bug->openedDateAB;?>
+ bug->resolvedByAB;?>
+ bug->resolvedDateAB;?>
+
+
+ createLink('bug', 'view', "bugID=$bug->id");?>
+
+ id);?>
+ title, '', "class='preview'");?>
+ bug->statusList[$bug->status];?>
+ openedBy];?>
+ openedDate, 5, 11)?>
+ resolvedBy];?>
+ resolvedDate, 5, 11)?>
+
+
+
+
+
+
+
+ build->desc;?>
+ desc;?>
+
+
+
+ session->buildList ? $this->session->buildList : $this->createLink('project', 'build', "projectID=$build->project");
+ if(!$build->deleted)
+ {
+ common::printLink('build', 'edit', "buildID=$build->id", $lang->edit);
+ common::printLink('build', 'delete', "buildID=$build->id", $lang->delete, 'hiddenwin');
+ }
+ echo html::a($browseLink, $lang->goback);
+ ?>
+
+
+
diff --git a/module/common/control.php b/module/common/control.php
index 4ba1032672..be741fbee2 100644
--- a/module/common/control.php
+++ b/module/common/control.php
@@ -1,265 +1,265 @@
-
- * @package common
- * @version $Id$
- * @link http://www.zentao.net
- */
-class common extends control
-{
- /**
- * The construc method, to do some auto things.
- *
- * @access public
- * @return void
- */
- public function __construct()
- {
- parent::__construct();
- $this->common->startSession();
- $this->common->sendHeader();
- $this->common->setCompany();
- $this->common->setUser();
- $this->app->loadLang('company');
- }
-
- /**
- * Check the user has permission to access this method, if not, locate to the login page or deny page.
- *
- * @access public
- * @return void
- */
- public function checkPriv()
- {
- $module = $this->app->getModuleName();
- $method = $this->app->getMethodName();
- if($this->common->isOpenMethod($module, $method)) return true;
- if(!$this->loadModel('user')->isLogon() and $this->server->php_auth_user) $this->user->identifyByPhpAuth();
- if(!$this->loadModel('user')->isLogon() and $this->cookie->za) $this->user->identifyByCookie();
-
- if(isset($this->app->user))
- {
- if(!common::hasPriv($module, $method)) $this->common->deny($module, $method);
- }
- else
- {
- $referer = helper::safe64Encode($this->app->getURI(true));
- $this->locate($this->createLink('user', 'login', "referer=$referer"));
- }
- }
-
- /**
- * Check upgrade's status file is ok or not.
- *
- * @access public
- * @return void
- */
- public function checkUpgradeStatus()
- {
- $statusFile = $this->app->getAppRoot() . 'www' . $this->pathFix . 'ok';
- if(!file_exists($statusFile) or time() - filemtime($statusFile) > 3600)
- {
- $this->app->loadLang('upgrade');
- echo " ";
- echo "";
- printf($this->lang->upgrade->setStatusFile, $statusFile, $statusFile, $statusFile);
- die('
');
- }
- }
-
- /**
- * Check the user has permisson of one method of one module.
- *
- * @param string $module
- * @param string $method
- * @static
- * @access public
- * @return bool
- */
- public static function hasPriv($module, $method)
- {
- global $app;
-
- /* Check is the super admin or not. */
- $account = ',' . $app->user->account . ',';
- if(strpos($app->company->admins, $account) !== false) return true;
-
- /* If not super admin, check the rights. */
- $rights = $app->user->rights;
- if(isset($rights[strtolower($module)][strtolower($method)])) return true;
- return false;
- }
-
- /**
- * Replace the %s of one key of a menu by $params.
- *
- * All the menus are defined in the common's language file. But there're many dynamic params, so in the defination,
- * we used %s as placeholder. These %s should be setted in one module.
- *
- * The items of one module's menu may be an string or array. For example, please see module/common/lang.
- *
- * @param string $object the menus of one module
- * @param string $key the menu item to be replaced
- * @param string $params the params passed to the menu item
- * @access public
- * @return void
- */
- public function setMenuVars($menu, $key, $params)
- {
- if(is_array($params))
- {
- if(is_array($menu->$key))
- {
- $menu->$key = (object)$menu->$key;
- $menu->$key->link = vsprintf($menu->$key->link, $params);
- $menu->$key = (array)$menu->$key;
- }
- else
- {
- $menu->$key = vsprintf($menu->$key, $params);
- }
- }
- else
- {
- if(is_array($menu->$key))
- {
- $menu->$key = (object)$menu->$key;
- $menu->$key->link = sprintf($menu->$key->link, $params);
- $menu->$key = (array)$menu->$key;
- }
- else
- {
- $menu->$key = sprintf($menu->$key, $params);
- }
- }
- }
-
- /**
- * Print the link contains orderBy field.
- *
- * This method will auto set the orderby param according the params. Fox example, if the order by is desc,
- * will be changed to asc.
- *
- * @param string $fieldName the field name to sort by
- * @param string $orderBy the order by string
- * @param string $vars the vars to be passed
- * @param string $label the label of the link
- * @param string $module the module name
- * @param string $method the method name
- * @static
- * @access public
- * @return void
- */
- public static function printOrderLink($fieldName, $orderBy, $vars, $label, $module = '', $method = '')
- {
- global $lang, $app;
- if(empty($module)) $module= $app->getModuleName();
- if(empty($method)) $method= $app->getMethodName();
- $className = 'header';
-
- if(strpos($orderBy, $fieldName) !== false)
- {
- if(stripos($orderBy, 'desc') !== false)
- {
- $orderBy = str_ireplace('desc', 'asc', $orderBy);
- $className = 'headerSortUp';
- }
- elseif(stripos($orderBy, 'asc') !== false)
- {
- $orderBy = str_ireplace('asc', 'desc', $orderBy);
- $className = 'headerSortDown';
- }
- }
- else
- {
- $orderBy = $fieldName . '_' . 'asc';
- $className = 'header';
- }
- $link = helper::createLink($module, $method, sprintf($vars, $orderBy));
- echo "" . html::a($link, $label) . '
';
- }
-
- /**
- * Print link to an modules' methd.
- *
- * Before printing, check the privilege first. If no privilege, return fasle. Else, print the link, return true.
- *
- * @param string $module the module name
- * @param string $method the method
- * @param string $vars vars to be passed
- * @param string $label the label of the link
- * @param string $target the target of the link
- * @param string $misc others
- * @static
- * @access public
- * @return bool
- */
- public static function printLink($module, $method, $vars = '', $label, $target = '', $misc = '')
- {
- if(!common::hasPriv($module, $method)) return false;
- echo html::a(helper::createLink($module, $method, $vars), $label, $target, $misc);
- return true;
- }
-
- /**
- * Create changes of one object.
- *
- * @param mixed $old the old object
- * @param mixed $new the new object
- * @static
- * @access public
- * @return array
- */
- public static function createChanges($old, $new)
- {
- global $config;
- $changes = array();
- $magicQuote = get_magic_quotes_gpc();
- foreach($new as $key => $value)
- {
- if(strtolower($key) == 'lastediteddate') continue;
- if(strtolower($key) == 'lasteditedby') continue;
- if(strtolower($key) == 'assigneddate') continue;
- if(strtolower($key) == 'editedby') continue;
- if(strtolower($key) == 'editeddate') continue;
-
- if($magicQuote) $value = stripslashes($value);
- if($value != $old->$key)
- {
- $diff = '';
- if(substr_count($value, "\n") > 1 or substr_count($old->$key, "\n") > 1 or strpos('name,title,desc,spec,steps,content,digest', strtolower($key)) !== false) $diff = commonModel::diff($old->$key, $value);
- $changes[] = array('field' => $key, 'old' => $old->$key, 'new' => $value, 'diff' => $diff);
- }
- }
- return $changes;
- }
-
- /**
- * Get the full url of the system.
- *
- * @access public
- * @return string
- */
- public function getSysURL()
- {
- $httpType = isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' ? 'https' : 'http';
- $httpHost = $_SERVER['HTTP_HOST'];
- return "$httpType://$httpHost";
- }
-
- /**
- * Print the run info.
- *
- * @param mixed $startTime the start time.
- * @access public
- * @return void
- */
- public function printRunInfo($startTime)
- {
- vprintf($this->lang->runInfo, $this->common->getRunInfo($startTime));
- }
-}
+
+ * @package common
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class common extends control
+{
+ /**
+ * The construc method, to do some auto things.
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->common->startSession();
+ $this->common->sendHeader();
+ $this->common->setCompany();
+ $this->common->setUser();
+ $this->app->loadLang('company');
+ }
+
+ /**
+ * Check the user has permission to access this method, if not, locate to the login page or deny page.
+ *
+ * @access public
+ * @return void
+ */
+ public function checkPriv()
+ {
+ $module = $this->app->getModuleName();
+ $method = $this->app->getMethodName();
+ if($this->common->isOpenMethod($module, $method)) return true;
+ if(!$this->loadModel('user')->isLogon() and $this->server->php_auth_user) $this->user->identifyByPhpAuth();
+ if(!$this->loadModel('user')->isLogon() and $this->cookie->za) $this->user->identifyByCookie();
+
+ if(isset($this->app->user))
+ {
+ if(!common::hasPriv($module, $method)) $this->common->deny($module, $method);
+ }
+ else
+ {
+ $referer = helper::safe64Encode($this->app->getURI(true));
+ $this->locate($this->createLink('user', 'login', "referer=$referer"));
+ }
+ }
+
+ /**
+ * Check upgrade's status file is ok or not.
+ *
+ * @access public
+ * @return void
+ */
+ public function checkUpgradeStatus()
+ {
+ $statusFile = $this->app->getAppRoot() . 'www' . $this->pathFix . 'ok';
+ if(!file_exists($statusFile) or time() - filemtime($statusFile) > 3600)
+ {
+ $this->app->loadLang('upgrade');
+ echo " ";
+ echo "";
+ printf($this->lang->upgrade->setStatusFile, $statusFile, $statusFile, $statusFile);
+ die('
');
+ }
+ }
+
+ /**
+ * Check the user has permisson of one method of one module.
+ *
+ * @param string $module
+ * @param string $method
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function hasPriv($module, $method)
+ {
+ global $app;
+
+ /* Check is the super admin or not. */
+ $account = ',' . $app->user->account . ',';
+ if(strpos($app->company->admins, $account) !== false) return true;
+
+ /* If not super admin, check the rights. */
+ $rights = $app->user->rights;
+ if(isset($rights[strtolower($module)][strtolower($method)])) return true;
+ return false;
+ }
+
+ /**
+ * Replace the %s of one key of a menu by $params.
+ *
+ * All the menus are defined in the common's language file. But there're many dynamic params, so in the defination,
+ * we used %s as placeholder. These %s should be setted in one module.
+ *
+ * The items of one module's menu may be an string or array. For example, please see module/common/lang.
+ *
+ * @param string $object the menus of one module
+ * @param string $key the menu item to be replaced
+ * @param string $params the params passed to the menu item
+ * @access public
+ * @return void
+ */
+ public function setMenuVars($menu, $key, $params)
+ {
+ if(is_array($params))
+ {
+ if(is_array($menu->$key))
+ {
+ $menu->$key = (object)$menu->$key;
+ $menu->$key->link = vsprintf($menu->$key->link, $params);
+ $menu->$key = (array)$menu->$key;
+ }
+ else
+ {
+ $menu->$key = vsprintf($menu->$key, $params);
+ }
+ }
+ else
+ {
+ if(is_array($menu->$key))
+ {
+ $menu->$key = (object)$menu->$key;
+ $menu->$key->link = sprintf($menu->$key->link, $params);
+ $menu->$key = (array)$menu->$key;
+ }
+ else
+ {
+ $menu->$key = sprintf($menu->$key, $params);
+ }
+ }
+ }
+
+ /**
+ * Print the link contains orderBy field.
+ *
+ * This method will auto set the orderby param according the params. Fox example, if the order by is desc,
+ * will be changed to asc.
+ *
+ * @param string $fieldName the field name to sort by
+ * @param string $orderBy the order by string
+ * @param string $vars the vars to be passed
+ * @param string $label the label of the link
+ * @param string $module the module name
+ * @param string $method the method name
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function printOrderLink($fieldName, $orderBy, $vars, $label, $module = '', $method = '')
+ {
+ global $lang, $app;
+ if(empty($module)) $module= $app->getModuleName();
+ if(empty($method)) $method= $app->getMethodName();
+ $className = 'header';
+
+ if(strpos($orderBy, $fieldName) !== false)
+ {
+ if(stripos($orderBy, 'desc') !== false)
+ {
+ $orderBy = str_ireplace('desc', 'asc', $orderBy);
+ $className = 'headerSortUp';
+ }
+ elseif(stripos($orderBy, 'asc') !== false)
+ {
+ $orderBy = str_ireplace('asc', 'desc', $orderBy);
+ $className = 'headerSortDown';
+ }
+ }
+ else
+ {
+ $orderBy = $fieldName . '_' . 'asc';
+ $className = 'header';
+ }
+ $link = helper::createLink($module, $method, sprintf($vars, $orderBy));
+ echo "" . html::a($link, $label) . '
';
+ }
+
+ /**
+ * Print link to an modules' methd.
+ *
+ * Before printing, check the privilege first. If no privilege, return fasle. Else, print the link, return true.
+ *
+ * @param string $module the module name
+ * @param string $method the method
+ * @param string $vars vars to be passed
+ * @param string $label the label of the link
+ * @param string $target the target of the link
+ * @param string $misc others
+ * @static
+ * @access public
+ * @return bool
+ */
+ public static function printLink($module, $method, $vars = '', $label, $target = '', $misc = '')
+ {
+ if(!common::hasPriv($module, $method)) return false;
+ echo html::a(helper::createLink($module, $method, $vars), $label, $target, $misc);
+ return true;
+ }
+
+ /**
+ * Create changes of one object.
+ *
+ * @param mixed $old the old object
+ * @param mixed $new the new object
+ * @static
+ * @access public
+ * @return array
+ */
+ public static function createChanges($old, $new)
+ {
+ global $config;
+ $changes = array();
+ $magicQuote = get_magic_quotes_gpc();
+ foreach($new as $key => $value)
+ {
+ if(strtolower($key) == 'lastediteddate') continue;
+ if(strtolower($key) == 'lasteditedby') continue;
+ if(strtolower($key) == 'assigneddate') continue;
+ if(strtolower($key) == 'editedby') continue;
+ if(strtolower($key) == 'editeddate') continue;
+
+ if($magicQuote) $value = stripslashes($value);
+ if($value != $old->$key)
+ {
+ $diff = '';
+ if(substr_count($value, "\n") > 1 or substr_count($old->$key, "\n") > 1 or strpos('name,title,desc,spec,steps,content,digest', strtolower($key)) !== false) $diff = commonModel::diff($old->$key, $value);
+ $changes[] = array('field' => $key, 'old' => $old->$key, 'new' => $value, 'diff' => $diff);
+ }
+ }
+ return $changes;
+ }
+
+ /**
+ * Get the full url of the system.
+ *
+ * @access public
+ * @return string
+ */
+ public function getSysURL()
+ {
+ $httpType = isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' ? 'https' : 'http';
+ $httpHost = $_SERVER['HTTP_HOST'];
+ return "$httpType://$httpHost";
+ }
+
+ /**
+ * Print the run info.
+ *
+ * @param mixed $startTime the start time.
+ * @access public
+ * @return void
+ */
+ public function printRunInfo($startTime)
+ {
+ vprintf($this->lang->runInfo, $this->common->getRunInfo($startTime));
+ }
+}
diff --git a/module/common/lang/en.php b/module/common/lang/en.php
index d03aba5db1..dbf69f4de9 100644
--- a/module/common/lang/en.php
+++ b/module/common/lang/en.php
@@ -1,296 +1,296 @@
-
- * @package ZenTaoPMS
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->arrow = ' » ';
-$lang->colon = '::';
-$lang->comma = ',';
-$lang->dot = '.';
-$lang->at = ' at ';
-$lang->downArrow = '↓';
-
-$lang->ZenTaoPMS = 'ZenTaoPMS';
-$lang->welcome = "Welcome to『%s』{$lang->colon} {$lang->ZenTaoPMS}";
-$lang->myControl = "Dashboard";
-$lang->currentPos = 'Current';
-$lang->logout = 'Logout';
-$lang->login = 'Login';
-$lang->aboutZenTao = 'About';
-$lang->todayIs = '%s, ';
-$lang->runInfo = "Time: %s ms, Memory: %s KB, Queries: %s.
";
-
-$lang->reset = 'Reset';
-$lang->edit = 'Edit';
-$lang->copy = 'Copy';
-$lang->delete = 'Delete';
-$lang->close = 'Close';
-$lang->link = 'Link';
-$lang->unlink = 'Unlink';
-$lang->import = 'Import';
-$lang->export = 'Export';
-$lang->setFileName = 'Filename:';
-$lang->activate = 'Activate';
-$lang->submitting = 'Saving...';
-$lang->save = 'Save';
-$lang->confirm = 'Confirm';
-$lang->preview = 'View';
-$lang->goback = 'Back';
-$lang->go = 'GO';
-$lang->more = 'More';
-
-$lang->actions = 'Actions';
-$lang->comment = 'Comment';
-$lang->history = 'History';
-$lang->attatch = 'Attatch';
-$lang->reverse = '[Reverse]';
-$lang->switchDisplay= '[Toggle Show]';
-$lang->switchHelp = 'Toggle Help';
-$lang->addFiles = 'Add Files';
-$lang->files = 'Files ';
-$lang->unfold = '+';
-$lang->fold = '-';
-
-$lang->selectAll = 'Select All';
-$lang->notFound = 'Sorry, the object not found.';
-$lang->showAll = '++ Show All ++';
-$lang->hideClosed = '-- Hide Closed--';
-
-$lang->future = 'Future';
-$lang->year = 'Year';
-$lang->workingHour = 'Hour';
-
-$lang->idAB = 'ID';
-$lang->priAB = 'P';
-$lang->statusAB = 'Status';
-$lang->openedByAB = 'Open';
-$lang->assignedToAB = 'To';
-$lang->typeAB = 'Type';
-
-$lang->common->common = 'Common module';
-
-/* The main menu. */
-$lang->menu->my = 'Dashboard|my|index';
-$lang->menu->product = 'Product|product|index';
-$lang->menu->project = 'Project|project|index';
-$lang->menu->qa = 'Test|qa|index';
-$lang->menu->doc = 'Doc|doc|index';
-$lang->menu->company = 'Company|company|index';
-$lang->menu->admin = 'Admin|admin|index';
-
-/* The objects in the search box. */
-$lang->searchObjects['bug'] = 'Bug';
-$lang->searchObjects['story'] = 'Story';
-$lang->searchObjects['task'] = 'Task';
-$lang->searchObjects['testcase'] = 'Test Case';
-$lang->searchObjects['project'] = 'Project';
-$lang->searchObjects['product'] = 'Product';
-$lang->searchObjects['user'] = 'User';
-$lang->searchObjects['build'] = 'Build';
-$lang->searchObjects['release'] = 'Release';
-$lang->searchObjects['productplan'] = 'Plan';
-$lang->searchObjects['testtask'] = 'Test Task';
-$lang->searchObjects['doc'] = 'Doc';
-$lang->searchTips = 'Id here';
-
-/* File type of export. */
-$lang->exportFileTypeList['csv'] = 'csv';
-$lang->exportFileTypeList['xml'] = 'xml';
-$lang->exportFileTypeList['html'] = 'html';
-
-/* Themes. */
-$lang->themes['default'] = 'Default';
-$lang->themes['green'] = 'Green';
-$lang->themes['red'] = 'Red';
-$lang->themes['classblue'] = 'Blue';
-
-/* Index mododule menu. */
-$lang->index->menu->product = 'Products|product|browse';
-$lang->index->menu->project = 'Projects|project|browse';
-
-/* Dashboard menu. */
-$lang->my->menu->account = '%s' . $lang->arrow;
-$lang->my->menu->index = 'Index|my|index';
-$lang->my->menu->todo = array('link' => 'Todo|my|todo|', 'subModule' => 'todo');
-$lang->my->menu->task = 'Task|my|task|';
-$lang->my->menu->bug = 'Bug|my|bug|';
-$lang->my->menu->testtask = 'Test|my|testtask|';
-$lang->my->menu->story = 'Story|my|story|';
-$lang->my->menu->myProject = 'Project|my|project|';
-$lang->my->menu->dynamic = 'Dynamic|my|dynamic|';
-$lang->my->menu->profile = array('link' => 'Profile|my|profile|', 'alias' => 'editprofile');
-$lang->todo->menu = $lang->my->menu;
-
-/* Product menu. */
-$lang->product->menu->list = '%s';
-$lang->product->menu->story = array('link' => 'Story|product|browse|productID=%s', 'subModule' => 'story');
-$lang->product->menu->dynamic = 'Dynamic|product|dynamic|productID=%s';
-$lang->product->menu->plan = array('link' => 'Plan|productplan|browse|productID=%s', 'subModule' => 'productplan');
-$lang->product->menu->release = array('link' => 'Release|release|browse|productID=%s', 'subModule' => 'release');
-$lang->product->menu->roadmap = 'Roadmap|product|roadmap|productID=%s';
-$lang->product->menu->doc = array('link' => 'Doc|product|doc|productID=%s', 'subModule' => 'doc');
-$lang->product->menu->view = 'Info|product|view|productID=%s';
-$lang->product->menu->edit = 'Edit|product|edit|productID=%s';
-$lang->product->menu->delete = array('link' => 'Delete|product|delete|productID=%s', 'target' => 'hiddenwin');
-$lang->product->menu->module = 'Modules|tree|browse|productID=%s&view=story';
-$lang->product->menu->create = array('link' => 'New Product|product|create', 'float' => 'right');
-$lang->product->menu->project = array('link' => 'Project list|product|project|status=all&productID=%s', 'float' => 'right');
-$lang->product->menu->all = array('link' => 'All product|product|index|locate=false', 'float' => 'right');
-$lang->story->menu = $lang->product->menu;
-$lang->productplan->menu = $lang->product->menu;
-$lang->release->menu = $lang->product->menu;
-
-/* Project menu. */
-$lang->project->menu->list = '%s';
-$lang->project->menu->task = array('link' => 'Task|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask');
-$lang->project->menu->story = array('link' => 'Story|project|story|projectID=%s');
-$lang->project->menu->bug = 'Bug|project|bug|projectID=%s';
-$lang->project->menu->dynamic = 'Dynamic|project|dynamic|projectID=%s';
-$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build');
-$lang->project->menu->testtask = 'Testtask|project|testtask|projectID=%s';
-$lang->project->menu->burn = 'Burn|project|burn|projectID=%s';
-$lang->project->menu->team = array('link' => 'Team|project|team|projectID=%s', 'alias' => 'managemembers');
-$lang->project->menu->doc = array('link' => 'Doc|project|doc|porjectID=%s', 'subModule' => 'doc');
-$lang->project->menu->product = 'Link Product|project|manageproducts|projectID=%s';
-$lang->project->menu->linkstory = array('link' => 'Link Story|project|linkstory|projectID=%s');
-$lang->project->menu->view = 'Info|project|view|projectID=%s';
-$lang->project->menu->edit = 'Edit|project|edit|projectID=%s';
-$lang->project->menu->delete = array('link' => 'Delete|project|delete|projectID=%s', 'target' => 'hiddenwin');
-$lang->project->menu->create = array('link' => 'New Project|project|create', 'float' => 'right');
-$lang->project->menu->all = array('link' => 'Project list|project|index|locate=no', 'float' => 'right');
-$lang->task->menu = $lang->project->menu;
-$lang->build->menu = $lang->project->menu;
-
-/* QA menu. */
-$lang->bug->menu->product = '%s';
-$lang->bug->menu->bug = array('link' => 'Bug|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree');
-$lang->bug->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,edit');
-$lang->bug->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s');
-
-$lang->testcase->menu->product = '%s';
-$lang->testcase->menu->bug = array('link' => 'Bug|bug|browse|productID=%s');
-$lang->testcase->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree');
-$lang->testcase->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s');
-
-$lang->testtask->menu->product = '%s';
-$lang->testtask->menu->bug = array('link' => 'Bug|bug|browse|productID=%s');
-$lang->testtask->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s');
-$lang->testtask->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases');
-
-/* Doc menu. */
-$lang->doc->menu->list = '%s';
-$lang->doc->menu->browse = array('link' => 'Doc|doc|browse|libID=%s');
-$lang->doc->menu->edit = 'Edit Library|doc|editLib|libID=%s';
-$lang->doc->menu->module = 'Modules|tree|browse|libID=%s&viewType=doc';
-$lang->doc->menu->delete = array('link' => 'Delete Library|doc|deleteLib|libID=%s', 'target' => 'hiddenwin');
-$lang->doc->menu->create = array('link' => 'New Library|doc|createLib', 'float' => 'right');
-
-/* Company menu. */
-$lang->company->menu->name = '%s' . $lang->arrow;
-$lang->company->menu->browseUser = array('link' => 'Users|company|browse', 'subModule' => 'user');
-$lang->company->menu->dept = array('link' => 'Department|dept|browse', 'subModule' => 'dept');
-$lang->company->menu->browseGroup = array('link' => 'Group|group|browse', 'subModule' => 'group');
-$lang->company->menu->edit = array('link' => 'Company|company|edit');
-$lang->company->menu->dynamic = 'Dynamic|company|dynamic|';
-$lang->company->menu->addGroup = array('link' => 'Add Group|group|create', 'float' => 'right');
-$lang->company->menu->addUser = array('link' => 'Add User|user|create|dept=%s&from=company', 'subModule' => 'user', 'float' => 'right');
-$lang->dept->menu = $lang->company->menu;
-$lang->group->menu = $lang->company->menu;
-
-/* User menu. */
-$lang->user->menu->account = '%s' . $lang->arrow;
-$lang->user->menu->todo = array('link' => 'Todo|user|todo|account=%s', 'subModule' => 'todo');
-$lang->user->menu->task = 'Task|user|task|account=%s';
-$lang->user->menu->bug = 'Bug|user|bug|account=%s';
-$lang->user->menu->dynamic = 'Dynamic|user|dynamic|type=today&account=%s';
-$lang->user->menu->projectList = 'Project|user|project|account=%s';
-$lang->user->menu->profile = array('link' => 'Profile|user|profile|account=%s', 'alias' => 'edit');
-$lang->user->menu->browse = array('link' => 'Manage user|company|browse|', 'float' => 'right');
-
-/* Admin menu. */
-$lang->admin->menu->extension = array('link' => 'Extension|extension|browse', 'subModule' => 'extension');
-$lang->admin->menu->editor = array('link' => 'Extension editor|editor|index', 'subModule' => 'editor');
-$lang->admin->menu->mail = array('link' => 'ConfigEmail|mail|set', 'subModule' => 'mail');
-$lang->admin->menu->convert = array('link' => 'Import|convert|index', 'subModule' => 'convert');
-$lang->admin->menu->trashes = array('link' => 'Trash|action|trash', 'subModule' => 'action');
-$lang->convert->menu = $lang->admin->menu;
-$lang->upgrade->menu = $lang->admin->menu;
-$lang->action->menu = $lang->admin->menu;
-$lang->extension->menu = $lang->admin->menu;
-$lang->editor->menu = $lang->admin->menu;
-$lang->mail->menu = $lang->admin->menu;
-
-/* Groups. */
-$lang->menugroup->release = 'product';
-$lang->menugroup->story = 'product';
-$lang->menugroup->productplan = 'product';
-$lang->menugroup->task = 'project';
-$lang->menugroup->build = 'project';
-$lang->menugroup->convert = 'admin';
-$lang->menugroup->upgrade = 'admin';
-$lang->menugroup->user = 'company';
-$lang->menugroup->group = 'company';
-$lang->menugroup->bug = 'qa';
-$lang->menugroup->testcase = 'qa';
-$lang->menugroup->testtask = 'qa';
-$lang->menugroup->people = 'company';
-$lang->menugroup->dept = 'company';
-$lang->menugroup->todo = 'my';
-$lang->menugroup->action = 'admin';
-$lang->menugroup->extension = 'admin';
-$lang->menugroup->editor = 'admin';
-$lang->menugroup->mail = 'admin';
-
-/* Error info. */
-$lang->error->companyNotFound = "The domain %s does not exist.";
-$lang->error->length = array("『%s』length should be『%s』", "『%s』length should between『%s』and 『%s』.");
-$lang->error->reg = "『%s』should like『%s』";
-$lang->error->unique = "『%s』has『%s』already.";
-$lang->error->gt = "『%s』must great than『%s』.";
-$lang->error->notempty = "『%s』can not be empty.";
-$lang->error->empty = "『%s』 must be empty.";
-$lang->error->equal = "『%s』must be『%s』.";
-$lang->error->int = array("『%s』should be interger", "『%s』should between『%s-%s』.");
-$lang->error->float = "『%s』should be a interger or float.";
-$lang->error->email = "『%s』should be email.";
-$lang->error->date = "『%s』should be date";
-$lang->error->account = "『%s』should be a valid account.";
-$lang->error->passwordsame = "Two passwords must be the same";
-$lang->error->passwordrule = "Password should more than six letters.";
-$lang->error->accessDenied = 'No purview';
-
-/* Pager. */
-$lang->pager->noRecord = "No records yet.";
-$lang->pager->digest = "%s records, %s per page, %s/%s ";
-$lang->pager->first = "First";
-$lang->pager->pre = "Previous";
-$lang->pager->next = "Next";
-$lang->pager->last = "Last";
-$lang->pager->locate = "GO!";
-
-$lang->zentaoSite = "Official Site";
-$lang->chinaScrum = "Scrum community ";
-$lang->agileTraining = "Training ";
-$lang->donate = "Donate ";
-$lang->zentaoKeywords = "Open Source Project Management System";
-$lang->zentaoDESC = "ZenTaoPMS is an open sourced project management system.";
-
-
-
-/* Date times. */
-define('DT_DATETIME1', 'Y-m-d H:i:s');
-define('DT_DATETIME2', 'y-m-d H:i');
-define('DT_MONTHTIME1', 'n/d H:i');
-define('DT_MONTHTIME2', 'F j, H:i');
-define('DT_DATE1', 'Y-m-d');
-define('DT_DATE2', 'Ymd');
-define('DT_DATE3', 'F j, Y ');
-define('DT_DATE4', 'M j');
-define('DT_TIME1', 'H:i:s');
-define('DT_TIME2', 'H:i');
+
+ * @package ZenTaoPMS
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->arrow = ' » ';
+$lang->colon = '::';
+$lang->comma = ',';
+$lang->dot = '.';
+$lang->at = ' at ';
+$lang->downArrow = '↓';
+
+$lang->ZenTaoPMS = 'ZenTaoPMS';
+$lang->welcome = "Welcome to『%s』{$lang->colon} {$lang->ZenTaoPMS}";
+$lang->myControl = "Dashboard";
+$lang->currentPos = 'Current';
+$lang->logout = 'Logout';
+$lang->login = 'Login';
+$lang->aboutZenTao = 'About';
+$lang->todayIs = '%s, ';
+$lang->runInfo = "Time: %s ms, Memory: %s KB, Queries: %s.
";
+
+$lang->reset = 'Reset';
+$lang->edit = 'Edit';
+$lang->copy = 'Copy';
+$lang->delete = 'Delete';
+$lang->close = 'Close';
+$lang->link = 'Link';
+$lang->unlink = 'Unlink';
+$lang->import = 'Import';
+$lang->export = 'Export';
+$lang->setFileName = 'Filename:';
+$lang->activate = 'Activate';
+$lang->submitting = 'Saving...';
+$lang->save = 'Save';
+$lang->confirm = 'Confirm';
+$lang->preview = 'View';
+$lang->goback = 'Back';
+$lang->go = 'GO';
+$lang->more = 'More';
+
+$lang->actions = 'Actions';
+$lang->comment = 'Comment';
+$lang->history = 'History';
+$lang->attatch = 'Attatch';
+$lang->reverse = '[Reverse]';
+$lang->switchDisplay= '[Toggle Show]';
+$lang->switchHelp = 'Toggle Help';
+$lang->addFiles = 'Add Files';
+$lang->files = 'Files ';
+$lang->unfold = '+';
+$lang->fold = '-';
+
+$lang->selectAll = 'Select All';
+$lang->notFound = 'Sorry, the object not found.';
+$lang->showAll = '++ Show All ++';
+$lang->hideClosed = '-- Hide Closed--';
+
+$lang->future = 'Future';
+$lang->year = 'Year';
+$lang->workingHour = 'Hour';
+
+$lang->idAB = 'ID';
+$lang->priAB = 'P';
+$lang->statusAB = 'Status';
+$lang->openedByAB = 'Open';
+$lang->assignedToAB = 'To';
+$lang->typeAB = 'Type';
+
+$lang->common->common = 'Common module';
+
+/* The main menu. */
+$lang->menu->my = 'Dashboard|my|index';
+$lang->menu->product = 'Product|product|index';
+$lang->menu->project = 'Project|project|index';
+$lang->menu->qa = 'Test|qa|index';
+$lang->menu->doc = 'Doc|doc|index';
+$lang->menu->company = 'Company|company|index';
+$lang->menu->admin = 'Admin|admin|index';
+
+/* The objects in the search box. */
+$lang->searchObjects['bug'] = 'Bug';
+$lang->searchObjects['story'] = 'Story';
+$lang->searchObjects['task'] = 'Task';
+$lang->searchObjects['testcase'] = 'Test Case';
+$lang->searchObjects['project'] = 'Project';
+$lang->searchObjects['product'] = 'Product';
+$lang->searchObjects['user'] = 'User';
+$lang->searchObjects['build'] = 'Build';
+$lang->searchObjects['release'] = 'Release';
+$lang->searchObjects['productplan'] = 'Plan';
+$lang->searchObjects['testtask'] = 'Test Task';
+$lang->searchObjects['doc'] = 'Doc';
+$lang->searchTips = 'Id here';
+
+/* File type of export. */
+$lang->exportFileTypeList['csv'] = 'csv';
+$lang->exportFileTypeList['xml'] = 'xml';
+$lang->exportFileTypeList['html'] = 'html';
+
+/* Themes. */
+$lang->themes['default'] = 'Default';
+$lang->themes['green'] = 'Green';
+$lang->themes['red'] = 'Red';
+$lang->themes['classblue'] = 'Blue';
+
+/* Index mododule menu. */
+$lang->index->menu->product = 'Products|product|browse';
+$lang->index->menu->project = 'Projects|project|browse';
+
+/* Dashboard menu. */
+$lang->my->menu->account = '%s' . $lang->arrow;
+$lang->my->menu->index = 'Index|my|index';
+$lang->my->menu->todo = array('link' => 'Todo|my|todo|', 'subModule' => 'todo');
+$lang->my->menu->task = 'Task|my|task|';
+$lang->my->menu->bug = 'Bug|my|bug|';
+$lang->my->menu->testtask = 'Test|my|testtask|';
+$lang->my->menu->story = 'Story|my|story|';
+$lang->my->menu->myProject = 'Project|my|project|';
+$lang->my->menu->dynamic = 'Dynamic|my|dynamic|';
+$lang->my->menu->profile = array('link' => 'Profile|my|profile|', 'alias' => 'editprofile');
+$lang->todo->menu = $lang->my->menu;
+
+/* Product menu. */
+$lang->product->menu->list = '%s';
+$lang->product->menu->story = array('link' => 'Story|product|browse|productID=%s', 'subModule' => 'story');
+$lang->product->menu->dynamic = 'Dynamic|product|dynamic|productID=%s';
+$lang->product->menu->plan = array('link' => 'Plan|productplan|browse|productID=%s', 'subModule' => 'productplan');
+$lang->product->menu->release = array('link' => 'Release|release|browse|productID=%s', 'subModule' => 'release');
+$lang->product->menu->roadmap = 'Roadmap|product|roadmap|productID=%s';
+$lang->product->menu->doc = array('link' => 'Doc|product|doc|productID=%s', 'subModule' => 'doc');
+$lang->product->menu->view = 'Info|product|view|productID=%s';
+$lang->product->menu->edit = 'Edit|product|edit|productID=%s';
+$lang->product->menu->delete = array('link' => 'Delete|product|delete|productID=%s', 'target' => 'hiddenwin');
+$lang->product->menu->module = 'Modules|tree|browse|productID=%s&view=story';
+$lang->product->menu->create = array('link' => 'New Product|product|create', 'float' => 'right');
+$lang->product->menu->project = array('link' => 'Project list|product|project|status=all&productID=%s', 'float' => 'right');
+$lang->product->menu->all = array('link' => 'All product|product|index|locate=false', 'float' => 'right');
+$lang->story->menu = $lang->product->menu;
+$lang->productplan->menu = $lang->product->menu;
+$lang->release->menu = $lang->product->menu;
+
+/* Project menu. */
+$lang->project->menu->list = '%s';
+$lang->project->menu->task = array('link' => 'Task|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask');
+$lang->project->menu->story = array('link' => 'Story|project|story|projectID=%s');
+$lang->project->menu->bug = 'Bug|project|bug|projectID=%s';
+$lang->project->menu->dynamic = 'Dynamic|project|dynamic|projectID=%s';
+$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build');
+$lang->project->menu->testtask = 'Testtask|project|testtask|projectID=%s';
+$lang->project->menu->burn = 'Burn|project|burn|projectID=%s';
+$lang->project->menu->team = array('link' => 'Team|project|team|projectID=%s', 'alias' => 'managemembers');
+$lang->project->menu->doc = array('link' => 'Doc|project|doc|porjectID=%s', 'subModule' => 'doc');
+$lang->project->menu->product = 'Link Product|project|manageproducts|projectID=%s';
+$lang->project->menu->linkstory = array('link' => 'Link Story|project|linkstory|projectID=%s');
+$lang->project->menu->view = 'Info|project|view|projectID=%s';
+$lang->project->menu->edit = 'Edit|project|edit|projectID=%s';
+$lang->project->menu->delete = array('link' => 'Delete|project|delete|projectID=%s', 'target' => 'hiddenwin');
+$lang->project->menu->create = array('link' => 'New Project|project|create', 'float' => 'right');
+$lang->project->menu->all = array('link' => 'Project list|project|index|locate=no', 'float' => 'right');
+$lang->task->menu = $lang->project->menu;
+$lang->build->menu = $lang->project->menu;
+
+/* QA menu. */
+$lang->bug->menu->product = '%s';
+$lang->bug->menu->bug = array('link' => 'Bug|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree');
+$lang->bug->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,edit');
+$lang->bug->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s');
+
+$lang->testcase->menu->product = '%s';
+$lang->testcase->menu->bug = array('link' => 'Bug|bug|browse|productID=%s');
+$lang->testcase->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree');
+$lang->testcase->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s');
+
+$lang->testtask->menu->product = '%s';
+$lang->testtask->menu->bug = array('link' => 'Bug|bug|browse|productID=%s');
+$lang->testtask->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s');
+$lang->testtask->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases');
+
+/* Doc menu. */
+$lang->doc->menu->list = '%s';
+$lang->doc->menu->browse = array('link' => 'Doc|doc|browse|libID=%s');
+$lang->doc->menu->edit = 'Edit Library|doc|editLib|libID=%s';
+$lang->doc->menu->module = 'Modules|tree|browse|libID=%s&viewType=doc';
+$lang->doc->menu->delete = array('link' => 'Delete Library|doc|deleteLib|libID=%s', 'target' => 'hiddenwin');
+$lang->doc->menu->create = array('link' => 'New Library|doc|createLib', 'float' => 'right');
+
+/* Company menu. */
+$lang->company->menu->name = '%s' . $lang->arrow;
+$lang->company->menu->browseUser = array('link' => 'Users|company|browse', 'subModule' => 'user');
+$lang->company->menu->dept = array('link' => 'Department|dept|browse', 'subModule' => 'dept');
+$lang->company->menu->browseGroup = array('link' => 'Group|group|browse', 'subModule' => 'group');
+$lang->company->menu->edit = array('link' => 'Company|company|edit');
+$lang->company->menu->dynamic = 'Dynamic|company|dynamic|';
+$lang->company->menu->addGroup = array('link' => 'Add Group|group|create', 'float' => 'right');
+$lang->company->menu->addUser = array('link' => 'Add User|user|create|dept=%s&from=company', 'subModule' => 'user', 'float' => 'right');
+$lang->dept->menu = $lang->company->menu;
+$lang->group->menu = $lang->company->menu;
+
+/* User menu. */
+$lang->user->menu->account = '%s' . $lang->arrow;
+$lang->user->menu->todo = array('link' => 'Todo|user|todo|account=%s', 'subModule' => 'todo');
+$lang->user->menu->task = 'Task|user|task|account=%s';
+$lang->user->menu->bug = 'Bug|user|bug|account=%s';
+$lang->user->menu->dynamic = 'Dynamic|user|dynamic|type=today&account=%s';
+$lang->user->menu->projectList = 'Project|user|project|account=%s';
+$lang->user->menu->profile = array('link' => 'Profile|user|profile|account=%s', 'alias' => 'edit');
+$lang->user->menu->browse = array('link' => 'Manage user|company|browse|', 'float' => 'right');
+
+/* Admin menu. */
+$lang->admin->menu->extension = array('link' => 'Extension|extension|browse', 'subModule' => 'extension');
+$lang->admin->menu->editor = array('link' => 'Extension editor|editor|index', 'subModule' => 'editor');
+$lang->admin->menu->mail = array('link' => 'ConfigEmail|mail|set', 'subModule' => 'mail');
+$lang->admin->menu->convert = array('link' => 'Import|convert|index', 'subModule' => 'convert');
+$lang->admin->menu->trashes = array('link' => 'Trash|action|trash', 'subModule' => 'action');
+$lang->convert->menu = $lang->admin->menu;
+$lang->upgrade->menu = $lang->admin->menu;
+$lang->action->menu = $lang->admin->menu;
+$lang->extension->menu = $lang->admin->menu;
+$lang->editor->menu = $lang->admin->menu;
+$lang->mail->menu = $lang->admin->menu;
+
+/* Groups. */
+$lang->menugroup->release = 'product';
+$lang->menugroup->story = 'product';
+$lang->menugroup->productplan = 'product';
+$lang->menugroup->task = 'project';
+$lang->menugroup->build = 'project';
+$lang->menugroup->convert = 'admin';
+$lang->menugroup->upgrade = 'admin';
+$lang->menugroup->user = 'company';
+$lang->menugroup->group = 'company';
+$lang->menugroup->bug = 'qa';
+$lang->menugroup->testcase = 'qa';
+$lang->menugroup->testtask = 'qa';
+$lang->menugroup->people = 'company';
+$lang->menugroup->dept = 'company';
+$lang->menugroup->todo = 'my';
+$lang->menugroup->action = 'admin';
+$lang->menugroup->extension = 'admin';
+$lang->menugroup->editor = 'admin';
+$lang->menugroup->mail = 'admin';
+
+/* Error info. */
+$lang->error->companyNotFound = "The domain %s does not exist.";
+$lang->error->length = array("『%s』length should be『%s』", "『%s』length should between『%s』and 『%s』.");
+$lang->error->reg = "『%s』should like『%s』";
+$lang->error->unique = "『%s』has『%s』already.";
+$lang->error->gt = "『%s』must great than『%s』.";
+$lang->error->notempty = "『%s』can not be empty.";
+$lang->error->empty = "『%s』 must be empty.";
+$lang->error->equal = "『%s』must be『%s』.";
+$lang->error->int = array("『%s』should be interger", "『%s』should between『%s-%s』.");
+$lang->error->float = "『%s』should be a interger or float.";
+$lang->error->email = "『%s』should be email.";
+$lang->error->date = "『%s』should be date";
+$lang->error->account = "『%s』should be a valid account.";
+$lang->error->passwordsame = "Two passwords must be the same";
+$lang->error->passwordrule = "Password should more than six letters.";
+$lang->error->accessDenied = 'No purview';
+
+/* Pager. */
+$lang->pager->noRecord = "No records yet.";
+$lang->pager->digest = "%s records, %s per page, %s/%s ";
+$lang->pager->first = "First";
+$lang->pager->pre = "Previous";
+$lang->pager->next = "Next";
+$lang->pager->last = "Last";
+$lang->pager->locate = "GO!";
+
+$lang->zentaoSite = "Official Site";
+$lang->chinaScrum = "Scrum community ";
+$lang->agileTraining = "Training ";
+$lang->donate = "Donate ";
+$lang->zentaoKeywords = "Open Source Project Management System";
+$lang->zentaoDESC = "ZenTaoPMS is an open sourced project management system.";
+
+
+
+/* Date times. */
+define('DT_DATETIME1', 'Y-m-d H:i:s');
+define('DT_DATETIME2', 'y-m-d H:i');
+define('DT_MONTHTIME1', 'n/d H:i');
+define('DT_MONTHTIME2', 'F j, H:i');
+define('DT_DATE1', 'Y-m-d');
+define('DT_DATE2', 'Ymd');
+define('DT_DATE3', 'F j, Y ');
+define('DT_DATE4', 'M j');
+define('DT_TIME1', 'H:i:s');
+define('DT_TIME2', 'H:i');
diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php
index da032065ec..a748bfe424 100644
--- a/module/common/lang/zh-cn.php
+++ b/module/common/lang/zh-cn.php
@@ -1,296 +1,296 @@
-
- * @package ZenTaoPMS
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->arrow = ' » ';
-$lang->colon = '::';
-$lang->comma = ',';
-$lang->dot = '。';
-$lang->at = ' 于 ';
-$lang->downArrow = '↓';
-
-$lang->ZenTaoPMS = '禅道管理';
-$lang->welcome = "欢迎使用『%s』{$lang->colon} {$lang->ZenTaoPMS}";
-$lang->myControl = "我的地盘";
-$lang->currentPos = '当前位置:';
-$lang->logout = '退出';
-$lang->login = '登录';
-$lang->aboutZenTao = '关于';
-$lang->todayIs = '今天是%s,';
-$lang->runInfo = "时间: %s 毫秒, 内存: %s KB, 查询: %s.
";
-
-$lang->reset = '重填';
-$lang->edit = '编辑';
-$lang->copy = '复制';
-$lang->delete = '删除';
-$lang->close = '关闭';
-$lang->link = '关联';
-$lang->unlink = '移除';
-$lang->import = '导入';
-$lang->export = '导出';
-$lang->setFileName = '文件名:';
-$lang->activate = '激活';
-$lang->submitting = '稍候...';
-$lang->save = '保存';
-$lang->confirm = '确认';
-$lang->preview = '查看';
-$lang->goback = '返回';
-$lang->go = 'GO';
-$lang->more = '更多';
-
-$lang->actions = '操作';
-$lang->comment = '备注';
-$lang->history = '历史记录';
-$lang->attatch = '附件';
-$lang->reverse = '[切换顺序]';
-$lang->switchDisplay= '[切换显示]';
-$lang->switchHelp = '切换帮助';
-$lang->addFiles = '上传了附件 ';
-$lang->files = '附件 ';
-$lang->unfold = '+';
-$lang->fold = '-';
-
-$lang->selectAll = '全选';
-$lang->notFound = '抱歉,您访问的对象并不存在!';
-$lang->showAll = '++ 全部显示 ++';
-$lang->hideClosed = '-- 隐藏已结束 --';
-
-$lang->future = '未来';
-$lang->year = '年';
-$lang->workingHour = '工时';
-
-$lang->idAB = 'ID';
-$lang->priAB = 'P';
-$lang->statusAB = '状态';
-$lang->openedByAB = '创建';
-$lang->assignedToAB = '指派';
-$lang->typeAB = '类型';
-
-$lang->common->common = '公有模块';
-
-/* 主导航菜单。*/
-$lang->menu->my = '我的地盘|my|index';
-$lang->menu->product = '产品视图|product|index';
-$lang->menu->project = '项目视图|project|index';
-$lang->menu->qa = '测试视图|qa|index';
-$lang->menu->doc = '文档视图|doc|index';
-$lang->menu->company = '组织视图|company|index';
-$lang->menu->admin = '后台管理|admin|index';
-
-/* 查询条中可以选择的对象列表。*/
-$lang->searchObjects['bug'] = 'B:Bug';
-$lang->searchObjects['story'] = 'S:需求';
-$lang->searchObjects['task'] = 'T:任务';
-$lang->searchObjects['testcase'] = 'C:用例';
-$lang->searchObjects['project'] = 'P:项目';
-$lang->searchObjects['product'] = 'P:产品';
-$lang->searchObjects['user'] = 'U:用户';
-$lang->searchObjects['build'] = 'B:Build';
-$lang->searchObjects['release'] = 'R:发布';
-$lang->searchObjects['productplan'] = 'P:产品计划';
-$lang->searchObjects['testtask'] = 'T:测试任务';
-$lang->searchObjects['doc'] = 'D:文档';
-$lang->searchTips = '输入编号';
-
-/* 导出文件的类型列表。*/
-$lang->exportFileTypeList['csv'] = 'csv';
-$lang->exportFileTypeList['xml'] = 'xml';
-$lang->exportFileTypeList['html'] = 'html';
-
-/* 风格列表。*/
-$lang->themes['default'] = '默认';
-$lang->themes['green'] = '绿色';
-$lang->themes['red'] = '红色';
-$lang->themes['classblue'] = '经典蓝';
-
-/* 首页菜单设置。*/
-$lang->index->menu->product = '浏览产品|product|browse';
-$lang->index->menu->project = '浏览项目|project|browse';
-
-/* 我的地盘菜单设置。*/
-$lang->my->menu->account = '%s' . $lang->arrow;
-$lang->my->menu->index = '首页|my|index';
-$lang->my->menu->todo = array('link' => '我的TODO|my|todo|', 'subModule' => 'todo');
-$lang->my->menu->task = '我的任务|my|task|';
-$lang->my->menu->bug = '我的Bug|my|bug|';
-$lang->my->menu->testtask = '我的测试|my|testtask|';
-$lang->my->menu->story = '我的需求|my|story|';
-$lang->my->menu->myProject = '我的项目|my|project|';
-$lang->my->menu->dynamic = '我的动态|my|dynamic|';
-$lang->my->menu->profile = array('link' => '我的档案|my|profile|', 'alias' => 'editprofile');
-$lang->todo->menu = $lang->my->menu;
-
-/* 产品视图设置。*/
-$lang->product->menu->list = '%s';
-$lang->product->menu->story = array('link' => '需求|product|browse|productID=%s', 'subModule' => 'story');
-$lang->product->menu->dynamic = '动态|product|dynamic|productID=%s';
-$lang->product->menu->plan = array('link' => '计划|productplan|browse|productID=%s', 'subModule' => 'productplan');
-$lang->product->menu->release = array('link' => '发布|release|browse|productID=%s', 'subModule' => 'release');
-$lang->product->menu->roadmap = '路线图|product|roadmap|productID=%s';
-$lang->product->menu->doc = array('link' => '文档|product|doc|productID=%s', 'subModule' => 'doc');
-$lang->product->menu->view = '概况|product|view|productID=%s';
-$lang->product->menu->edit = '编辑|product|edit|productID=%s';
-$lang->product->menu->delete = array('link' => '删除|product|delete|productID=%s', 'target' => 'hiddenwin');
-$lang->product->menu->module = '模块|tree|browse|productID=%s&view=story';
-$lang->product->menu->create = array('link' => '新增产品|product|create', 'float' => 'right');
-$lang->product->menu->project = array('link' => '项目列表|product|project|status=all&productID=%s', 'float' => 'right');
-$lang->product->menu->all = array('link' => '所有产品|product|index|locate=false', 'float' => 'right');
-$lang->story->menu = $lang->product->menu;
-$lang->productplan->menu = $lang->product->menu;
-$lang->release->menu = $lang->product->menu;
-
-/* 项目视图菜单设置。*/
-$lang->project->menu->list = '%s';
-$lang->project->menu->task = array('link' => '任务|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask');
-$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s');
-$lang->project->menu->bug = 'Bug|project|bug|projectID=%s';
-$lang->project->menu->dynamic = '动态|project|dynamic|projectID=%s';
-$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build');
-$lang->project->menu->testtask = '测试任务|project|testtask|projectID=%s';
-$lang->project->menu->burn = '燃尽图|project|burn|projectID=%s';
-$lang->project->menu->team = array('link' => '团队|project|team|projectID=%s', 'alias' => 'managemembers');
-$lang->project->menu->doc = array('link' => '文档|project|doc|porjectID=%s', 'subModule' => 'doc');
-$lang->project->menu->product = '产品|project|manageproducts|projectID=%s';
-$lang->project->menu->linkstory = array('link' => '关联需求|project|linkstory|projectID=%s');
-$lang->project->menu->view = '概况|project|view|projectID=%s';
-$lang->project->menu->edit = '编辑|project|edit|projectID=%s';
-$lang->project->menu->delete = array('link' => '删除|project|delete|projectID=%s', 'target' => 'hiddenwin');
-$lang->project->menu->create = array('link' => '新增项目|project|create', 'float' => 'right');
-$lang->project->menu->all = array('link' => '所有项目|project|index|locate=false', 'float' => 'right');
-$lang->task->menu = $lang->project->menu;
-$lang->build->menu = $lang->project->menu;
-
-/* QA视图菜单设置。*/
-$lang->bug->menu->product = '%s';
-$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree');
-$lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit');
-$lang->bug->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s');
-
-$lang->testcase->menu->product = '%s';
-$lang->testcase->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s');
-$lang->testcase->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree');
-$lang->testcase->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s');
-
-$lang->testtask->menu->product = '%s';
-$lang->testtask->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s');
-$lang->testtask->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s');
-$lang->testtask->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases');
-
-/* 文档视图菜单设置。*/
-$lang->doc->menu->list = '%s';
-$lang->doc->menu->browse = array('link' => '文档列表|doc|browse|libID=%s');
-$lang->doc->menu->edit = '编辑文档库|doc|editLib|libID=%s';
-$lang->doc->menu->module = '维护模块|tree|browse|libID=%s&viewType=doc';
-$lang->doc->menu->delete = array('link' => '删除文档库|doc|deleteLib|libID=%s', 'target' => 'hiddenwin');
-$lang->doc->menu->create = array('link' => '新增文档库|doc|createLib', 'float' => 'right');
-
-/* 组织结构视图菜单设置。*/
-$lang->company->menu->name = '%s' . $lang->arrow;
-$lang->company->menu->browseUser = array('link' => '用户列表|company|browse', 'subModule' => 'user');
-$lang->company->menu->dept = array('link' => '部门维护|dept|browse', 'subModule' => 'dept');
-$lang->company->menu->browseGroup = array('link' => '权限分组|group|browse', 'subModule' => 'group');
-$lang->company->menu->edit = array('link' => '公司管理|company|edit');
-$lang->company->menu->dynamic = '组织动态|company|dynamic|';
-$lang->company->menu->addGroup = array('link' => '添加分组|group|create', 'float' => 'right');
-$lang->company->menu->addUser = array('link' => '添加用户|user|create|dept=%s', 'subModule' => 'user', 'float' => 'right');
-$lang->dept->menu = $lang->company->menu;
-$lang->group->menu = $lang->company->menu;
-
-/* 用户信息菜单设置。*/
-$lang->user->menu->account = '%s' . $lang->arrow;
-$lang->user->menu->todo = array('link' => 'TODO列表|user|todo|account=%s', 'subModule' => 'todo');
-$lang->user->menu->task = '任务列表|user|task|account=%s';
-$lang->user->menu->bug = 'Bug列表|user|bug|account=%s';
-$lang->user->menu->dynamic = '用户动态|user|dynamic|type=today&account=%s';
-$lang->user->menu->projectList = '项目列表|user|project|account=%s';
-$lang->user->menu->profile = array('link' => '用户信息|user|profile|account=%s', 'alias' => 'edit');
-$lang->user->menu->browse = array('link' => '用户管理|company|browse|', 'float' => 'right');
-
-/* 后台管理菜单设置。*/
-$lang->admin->menu->extension = array('link' => '插件管理|extension|browse', 'subModule' => 'extension');
-$lang->admin->menu->editor = array('link' => '扩展编辑器|editor|index', 'subModule' => 'editor');
-$lang->admin->menu->mail = array('link' => 'Email配置|mail|set', 'subModule' => 'mail');
-$lang->admin->menu->convert = array('link' => '从其他系统导入|convert|index', 'subModule' => 'convert');
-$lang->admin->menu->trashes = array('link' => '回收站|action|trash', 'subModule' => 'action');
-$lang->convert->menu = $lang->admin->menu;
-$lang->upgrade->menu = $lang->admin->menu;
-$lang->action->menu = $lang->admin->menu;
-$lang->extension->menu = $lang->admin->menu;
-$lang->editor->menu = $lang->admin->menu;
-$lang->mail->menu = $lang->admin->menu;
-
-/*菜单设置:分组设置。*/
-$lang->menugroup->release = 'product';
-$lang->menugroup->story = 'product';
-$lang->menugroup->productplan = 'product';
-$lang->menugroup->task = 'project';
-$lang->menugroup->build = 'project';
-$lang->menugroup->convert = 'admin';
-$lang->menugroup->upgrade = 'admin';
-$lang->menugroup->user = 'company';
-$lang->menugroup->group = 'company';
-$lang->menugroup->bug = 'qa';
-$lang->menugroup->testcase = 'qa';
-$lang->menugroup->testtask = 'qa';
-$lang->menugroup->people = 'company';
-$lang->menugroup->dept = 'company';
-$lang->menugroup->todo = 'my';
-$lang->menugroup->action = 'admin';
-$lang->menugroup->extension = 'admin';
-$lang->menugroup->editor = 'admin';
-$lang->menugroup->mail = 'admin';
-
-/* 错误提示信息。*/
-$lang->error->companyNotFound = "您访问的域名 %s 没有对应的公司。";
-$lang->error->length = array("『%s』长度错误,应当为『%s』", "『%s』长度应当不超过『%s』,且不小于『%s』。");
-$lang->error->reg = "『%s』不符合格式,应当为:『%s』。";
-$lang->error->unique = "『%s』已经有『%s』这条记录了。";
-$lang->error->gt = "『%s』应当大于『%s』。";
-$lang->error->notempty = "『%s』不能为空。";
-$lang->error->empty = "『%s』必须为空。";
-$lang->error->equal = "『%s』必须为『%s』。";
-$lang->error->int = array("『%s』应当是数字。", "『%s』应当介于『%s-%s』之间。");
-$lang->error->float = "『%s』应当是数字,可以是小数。";
-$lang->error->email = "『%s』应当为合法的EMAIL。";
-$lang->error->date = "『%s』应当为合法的日期。";
-$lang->error->account = "『%s』应当为合法的用户名。";
-$lang->error->passwordsame = "两次密码应当相等。";
-$lang->error->passwordrule = "密码应该符合规则,长度至少为六位。";
-$lang->error->accessDenied = '您没有访问权限';
-
-/* 分页信息。*/
-$lang->pager->noRecord = "暂时没有记录";
-$lang->pager->digest = "共%s 条记录,每页 %s 条,页面:%s/%s ";
-$lang->pager->first = "首页";
-$lang->pager->pre = "上页";
-$lang->pager->next = "下页";
-$lang->pager->last = "末页";
-$lang->pager->locate = "GO!";
-
-$lang->zentaoSite = "官方网站";
-$lang->chinaScrum = "Scrum社区 ";
-$lang->agileTraining = "培训 ";
-$lang->donate = "捐助禅道 ";
-$lang->zentaoKeywords = "开源项目管理软件,项目管理,项目管理软件,pmp,pms,php框架,国产php框架,scrum工具,scrum管理工具,scrum管理软件,敏捷项目管理,禅道";
-$lang->zentaoDESC = "禅道项目管理软件(ZenTaoPMS)是一款国产的,基于LGPL协议,开源免费的项目管理软件(工具、系统),同时也是一款scrum管理工具。
- 它集产品管理、项目管理、测试管理于一体,同时还包含了事务管理、组织管理等诸多功能,是中小型企业项目管理的首选。禅道项目管理软件使用PHP + MySQL开发,
-基于自主的PHP开发框架──ZenTaoPHP而成。第三方开发者或者企业可以非常方便的开发插件或者进行定制。禅道在手,项目无忧!";
-
-/* 时间格式设置。*/
-define('DT_DATETIME1', 'Y-m-d H:i:s');
-define('DT_DATETIME2', 'y-m-d H:i');
-define('DT_MONTHTIME1', 'n/d H:i');
-define('DT_MONTHTIME2', 'n月d日 H:i');
-define('DT_DATE1', 'Y-m-d');
-define('DT_DATE2', 'Ymd');
-define('DT_DATE3', 'Y年m月d日');
-define('DT_DATE4', 'n月j日');
-define('DT_TIME1', 'H:i:s');
-define('DT_TIME2', 'H:i');
+
+ * @package ZenTaoPMS
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->arrow = ' » ';
+$lang->colon = '::';
+$lang->comma = ',';
+$lang->dot = '。';
+$lang->at = ' 于 ';
+$lang->downArrow = '↓';
+
+$lang->ZenTaoPMS = '禅道管理';
+$lang->welcome = "欢迎使用『%s』{$lang->colon} {$lang->ZenTaoPMS}";
+$lang->myControl = "我的地盘";
+$lang->currentPos = '当前位置:';
+$lang->logout = '退出';
+$lang->login = '登录';
+$lang->aboutZenTao = '关于';
+$lang->todayIs = '今天是%s,';
+$lang->runInfo = "时间: %s 毫秒, 内存: %s KB, 查询: %s.
";
+
+$lang->reset = '重填';
+$lang->edit = '编辑';
+$lang->copy = '复制';
+$lang->delete = '删除';
+$lang->close = '关闭';
+$lang->link = '关联';
+$lang->unlink = '移除';
+$lang->import = '导入';
+$lang->export = '导出';
+$lang->setFileName = '文件名:';
+$lang->activate = '激活';
+$lang->submitting = '稍候...';
+$lang->save = '保存';
+$lang->confirm = '确认';
+$lang->preview = '查看';
+$lang->goback = '返回';
+$lang->go = 'GO';
+$lang->more = '更多';
+
+$lang->actions = '操作';
+$lang->comment = '备注';
+$lang->history = '历史记录';
+$lang->attatch = '附件';
+$lang->reverse = '[切换顺序]';
+$lang->switchDisplay= '[切换显示]';
+$lang->switchHelp = '切换帮助';
+$lang->addFiles = '上传了附件 ';
+$lang->files = '附件 ';
+$lang->unfold = '+';
+$lang->fold = '-';
+
+$lang->selectAll = '全选';
+$lang->notFound = '抱歉,您访问的对象并不存在!';
+$lang->showAll = '++ 全部显示 ++';
+$lang->hideClosed = '-- 隐藏已结束 --';
+
+$lang->future = '未来';
+$lang->year = '年';
+$lang->workingHour = '工时';
+
+$lang->idAB = 'ID';
+$lang->priAB = 'P';
+$lang->statusAB = '状态';
+$lang->openedByAB = '创建';
+$lang->assignedToAB = '指派';
+$lang->typeAB = '类型';
+
+$lang->common->common = '公有模块';
+
+/* 主导航菜单。*/
+$lang->menu->my = '我的地盘|my|index';
+$lang->menu->product = '产品视图|product|index';
+$lang->menu->project = '项目视图|project|index';
+$lang->menu->qa = '测试视图|qa|index';
+$lang->menu->doc = '文档视图|doc|index';
+$lang->menu->company = '组织视图|company|index';
+$lang->menu->admin = '后台管理|admin|index';
+
+/* 查询条中可以选择的对象列表。*/
+$lang->searchObjects['bug'] = 'B:Bug';
+$lang->searchObjects['story'] = 'S:需求';
+$lang->searchObjects['task'] = 'T:任务';
+$lang->searchObjects['testcase'] = 'C:用例';
+$lang->searchObjects['project'] = 'P:项目';
+$lang->searchObjects['product'] = 'P:产品';
+$lang->searchObjects['user'] = 'U:用户';
+$lang->searchObjects['build'] = 'B:Build';
+$lang->searchObjects['release'] = 'R:发布';
+$lang->searchObjects['productplan'] = 'P:产品计划';
+$lang->searchObjects['testtask'] = 'T:测试任务';
+$lang->searchObjects['doc'] = 'D:文档';
+$lang->searchTips = '输入编号';
+
+/* 导出文件的类型列表。*/
+$lang->exportFileTypeList['csv'] = 'csv';
+$lang->exportFileTypeList['xml'] = 'xml';
+$lang->exportFileTypeList['html'] = 'html';
+
+/* 风格列表。*/
+$lang->themes['default'] = '默认';
+$lang->themes['green'] = '绿色';
+$lang->themes['red'] = '红色';
+$lang->themes['classblue'] = '经典蓝';
+
+/* 首页菜单设置。*/
+$lang->index->menu->product = '浏览产品|product|browse';
+$lang->index->menu->project = '浏览项目|project|browse';
+
+/* 我的地盘菜单设置。*/
+$lang->my->menu->account = '%s' . $lang->arrow;
+$lang->my->menu->index = '首页|my|index';
+$lang->my->menu->todo = array('link' => '我的TODO|my|todo|', 'subModule' => 'todo');
+$lang->my->menu->task = '我的任务|my|task|';
+$lang->my->menu->bug = '我的Bug|my|bug|';
+$lang->my->menu->testtask = '我的测试|my|testtask|';
+$lang->my->menu->story = '我的需求|my|story|';
+$lang->my->menu->myProject = '我的项目|my|project|';
+$lang->my->menu->dynamic = '我的动态|my|dynamic|';
+$lang->my->menu->profile = array('link' => '我的档案|my|profile|', 'alias' => 'editprofile');
+$lang->todo->menu = $lang->my->menu;
+
+/* 产品视图设置。*/
+$lang->product->menu->list = '%s';
+$lang->product->menu->story = array('link' => '需求|product|browse|productID=%s', 'subModule' => 'story');
+$lang->product->menu->dynamic = '动态|product|dynamic|productID=%s';
+$lang->product->menu->plan = array('link' => '计划|productplan|browse|productID=%s', 'subModule' => 'productplan');
+$lang->product->menu->release = array('link' => '发布|release|browse|productID=%s', 'subModule' => 'release');
+$lang->product->menu->roadmap = '路线图|product|roadmap|productID=%s';
+$lang->product->menu->doc = array('link' => '文档|product|doc|productID=%s', 'subModule' => 'doc');
+$lang->product->menu->view = '概况|product|view|productID=%s';
+$lang->product->menu->edit = '编辑|product|edit|productID=%s';
+$lang->product->menu->delete = array('link' => '删除|product|delete|productID=%s', 'target' => 'hiddenwin');
+$lang->product->menu->module = '模块|tree|browse|productID=%s&view=story';
+$lang->product->menu->create = array('link' => '新增产品|product|create', 'float' => 'right');
+$lang->product->menu->project = array('link' => '项目列表|product|project|status=all&productID=%s', 'float' => 'right');
+$lang->product->menu->all = array('link' => '所有产品|product|index|locate=false', 'float' => 'right');
+$lang->story->menu = $lang->product->menu;
+$lang->productplan->menu = $lang->product->menu;
+$lang->release->menu = $lang->product->menu;
+
+/* 项目视图菜单设置。*/
+$lang->project->menu->list = '%s';
+$lang->project->menu->task = array('link' => '任务|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask');
+$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s');
+$lang->project->menu->bug = 'Bug|project|bug|projectID=%s';
+$lang->project->menu->dynamic = '动态|project|dynamic|projectID=%s';
+$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build');
+$lang->project->menu->testtask = '测试任务|project|testtask|projectID=%s';
+$lang->project->menu->burn = '燃尽图|project|burn|projectID=%s';
+$lang->project->menu->team = array('link' => '团队|project|team|projectID=%s', 'alias' => 'managemembers');
+$lang->project->menu->doc = array('link' => '文档|project|doc|porjectID=%s', 'subModule' => 'doc');
+$lang->project->menu->product = '产品|project|manageproducts|projectID=%s';
+$lang->project->menu->linkstory = array('link' => '关联需求|project|linkstory|projectID=%s');
+$lang->project->menu->view = '概况|project|view|projectID=%s';
+$lang->project->menu->edit = '编辑|project|edit|projectID=%s';
+$lang->project->menu->delete = array('link' => '删除|project|delete|projectID=%s', 'target' => 'hiddenwin');
+$lang->project->menu->create = array('link' => '新增项目|project|create', 'float' => 'right');
+$lang->project->menu->all = array('link' => '所有项目|project|index|locate=false', 'float' => 'right');
+$lang->task->menu = $lang->project->menu;
+$lang->build->menu = $lang->project->menu;
+
+/* QA视图菜单设置。*/
+$lang->bug->menu->product = '%s';
+$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree');
+$lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit');
+$lang->bug->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s');
+
+$lang->testcase->menu->product = '%s';
+$lang->testcase->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s');
+$lang->testcase->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree');
+$lang->testcase->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s');
+
+$lang->testtask->menu->product = '%s';
+$lang->testtask->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s');
+$lang->testtask->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s');
+$lang->testtask->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases');
+
+/* 文档视图菜单设置。*/
+$lang->doc->menu->list = '%s';
+$lang->doc->menu->browse = array('link' => '文档列表|doc|browse|libID=%s');
+$lang->doc->menu->edit = '编辑文档库|doc|editLib|libID=%s';
+$lang->doc->menu->module = '维护模块|tree|browse|libID=%s&viewType=doc';
+$lang->doc->menu->delete = array('link' => '删除文档库|doc|deleteLib|libID=%s', 'target' => 'hiddenwin');
+$lang->doc->menu->create = array('link' => '新增文档库|doc|createLib', 'float' => 'right');
+
+/* 组织结构视图菜单设置。*/
+$lang->company->menu->name = '%s' . $lang->arrow;
+$lang->company->menu->browseUser = array('link' => '用户列表|company|browse', 'subModule' => 'user');
+$lang->company->menu->dept = array('link' => '部门维护|dept|browse', 'subModule' => 'dept');
+$lang->company->menu->browseGroup = array('link' => '权限分组|group|browse', 'subModule' => 'group');
+$lang->company->menu->edit = array('link' => '公司管理|company|edit');
+$lang->company->menu->dynamic = '组织动态|company|dynamic|';
+$lang->company->menu->addGroup = array('link' => '添加分组|group|create', 'float' => 'right');
+$lang->company->menu->addUser = array('link' => '添加用户|user|create|dept=%s', 'subModule' => 'user', 'float' => 'right');
+$lang->dept->menu = $lang->company->menu;
+$lang->group->menu = $lang->company->menu;
+
+/* 用户信息菜单设置。*/
+$lang->user->menu->account = '%s' . $lang->arrow;
+$lang->user->menu->todo = array('link' => 'TODO列表|user|todo|account=%s', 'subModule' => 'todo');
+$lang->user->menu->task = '任务列表|user|task|account=%s';
+$lang->user->menu->bug = 'Bug列表|user|bug|account=%s';
+$lang->user->menu->dynamic = '用户动态|user|dynamic|type=today&account=%s';
+$lang->user->menu->projectList = '项目列表|user|project|account=%s';
+$lang->user->menu->profile = array('link' => '用户信息|user|profile|account=%s', 'alias' => 'edit');
+$lang->user->menu->browse = array('link' => '用户管理|company|browse|', 'float' => 'right');
+
+/* 后台管理菜单设置。*/
+$lang->admin->menu->extension = array('link' => '插件管理|extension|browse', 'subModule' => 'extension');
+$lang->admin->menu->editor = array('link' => '扩展编辑器|editor|index', 'subModule' => 'editor');
+$lang->admin->menu->mail = array('link' => 'Email配置|mail|set', 'subModule' => 'mail');
+$lang->admin->menu->convert = array('link' => '从其他系统导入|convert|index', 'subModule' => 'convert');
+$lang->admin->menu->trashes = array('link' => '回收站|action|trash', 'subModule' => 'action');
+$lang->convert->menu = $lang->admin->menu;
+$lang->upgrade->menu = $lang->admin->menu;
+$lang->action->menu = $lang->admin->menu;
+$lang->extension->menu = $lang->admin->menu;
+$lang->editor->menu = $lang->admin->menu;
+$lang->mail->menu = $lang->admin->menu;
+
+/*菜单设置:分组设置。*/
+$lang->menugroup->release = 'product';
+$lang->menugroup->story = 'product';
+$lang->menugroup->productplan = 'product';
+$lang->menugroup->task = 'project';
+$lang->menugroup->build = 'project';
+$lang->menugroup->convert = 'admin';
+$lang->menugroup->upgrade = 'admin';
+$lang->menugroup->user = 'company';
+$lang->menugroup->group = 'company';
+$lang->menugroup->bug = 'qa';
+$lang->menugroup->testcase = 'qa';
+$lang->menugroup->testtask = 'qa';
+$lang->menugroup->people = 'company';
+$lang->menugroup->dept = 'company';
+$lang->menugroup->todo = 'my';
+$lang->menugroup->action = 'admin';
+$lang->menugroup->extension = 'admin';
+$lang->menugroup->editor = 'admin';
+$lang->menugroup->mail = 'admin';
+
+/* 错误提示信息。*/
+$lang->error->companyNotFound = "您访问的域名 %s 没有对应的公司。";
+$lang->error->length = array("『%s』长度错误,应当为『%s』", "『%s』长度应当不超过『%s』,且不小于『%s』。");
+$lang->error->reg = "『%s』不符合格式,应当为:『%s』。";
+$lang->error->unique = "『%s』已经有『%s』这条记录了。";
+$lang->error->gt = "『%s』应当大于『%s』。";
+$lang->error->notempty = "『%s』不能为空。";
+$lang->error->empty = "『%s』必须为空。";
+$lang->error->equal = "『%s』必须为『%s』。";
+$lang->error->int = array("『%s』应当是数字。", "『%s』应当介于『%s-%s』之间。");
+$lang->error->float = "『%s』应当是数字,可以是小数。";
+$lang->error->email = "『%s』应当为合法的EMAIL。";
+$lang->error->date = "『%s』应当为合法的日期。";
+$lang->error->account = "『%s』应当为合法的用户名。";
+$lang->error->passwordsame = "两次密码应当相等。";
+$lang->error->passwordrule = "密码应该符合规则,长度至少为六位。";
+$lang->error->accessDenied = '您没有访问权限';
+
+/* 分页信息。*/
+$lang->pager->noRecord = "暂时没有记录";
+$lang->pager->digest = "共%s 条记录,每页 %s 条,页面:%s/%s ";
+$lang->pager->first = "首页";
+$lang->pager->pre = "上页";
+$lang->pager->next = "下页";
+$lang->pager->last = "末页";
+$lang->pager->locate = "GO!";
+
+$lang->zentaoSite = "官方网站";
+$lang->chinaScrum = "Scrum社区 ";
+$lang->agileTraining = "培训 ";
+$lang->donate = "捐助禅道 ";
+$lang->zentaoKeywords = "开源项目管理软件,项目管理,项目管理软件,pmp,pms,php框架,国产php框架,scrum工具,scrum管理工具,scrum管理软件,敏捷项目管理,禅道";
+$lang->zentaoDESC = "禅道项目管理软件(ZenTaoPMS)是一款国产的,基于LGPL协议,开源免费的项目管理软件(工具、系统),同时也是一款scrum管理工具。
+ 它集产品管理、项目管理、测试管理于一体,同时还包含了事务管理、组织管理等诸多功能,是中小型企业项目管理的首选。禅道项目管理软件使用PHP + MySQL开发,
+基于自主的PHP开发框架──ZenTaoPHP而成。第三方开发者或者企业可以非常方便的开发插件或者进行定制。禅道在手,项目无忧!";
+
+/* 时间格式设置。*/
+define('DT_DATETIME1', 'Y-m-d H:i:s');
+define('DT_DATETIME2', 'y-m-d H:i');
+define('DT_MONTHTIME1', 'n/d H:i');
+define('DT_MONTHTIME2', 'n月d日 H:i');
+define('DT_DATE1', 'Y-m-d');
+define('DT_DATE2', 'Ymd');
+define('DT_DATE3', 'Y年m月d日');
+define('DT_DATE4', 'n月j日');
+define('DT_TIME1', 'H:i:s');
+define('DT_TIME2', 'H:i');
diff --git a/module/common/lang/zh-tw.php b/module/common/lang/zh-tw.php
index 2466e64183..ea46db0f5a 100644
--- a/module/common/lang/zh-tw.php
+++ b/module/common/lang/zh-tw.php
@@ -1,296 +1,296 @@
-
- * @package ZenTaoPMS
- * @version $Id: zh-tw.php 2538 2012-01-04 07:25:59Z shiyangyangwork@yahoo.cn $
- * @link http://www.zentao.net
- */
-$lang->arrow = ' » ';
-$lang->colon = '::';
-$lang->comma = ',';
-$lang->dot = '。';
-$lang->at = ' 于 ';
-$lang->downArrow = '↓';
-
-$lang->ZenTaoPMS = '禪道管理';
-$lang->welcome = "歡迎使用『%s』{$lang->colon} {$lang->ZenTaoPMS}";
-$lang->myControl = "我的地盤";
-$lang->currentPos = '當前位置:';
-$lang->logout = '退出';
-$lang->login = '登錄';
-$lang->aboutZenTao = '關於';
-$lang->todayIs = '今天是%s,';
-$lang->runInfo = "時間: %s 毫秒, 內存: %s KB, 查詢: %s.
";
-
-$lang->reset = '重填';
-$lang->edit = '編輯';
-$lang->copy = '複製';
-$lang->delete = '刪除';
-$lang->close = '關閉';
-$lang->link = '關聯';
-$lang->unlink = '移除';
-$lang->import = '導入';
-$lang->export = '導出';
-$lang->setFileName = '檔案名:';
-$lang->activate = '激活';
-$lang->submitting = '稍候...';
-$lang->save = '保存';
-$lang->confirm = '確認';
-$lang->preview = '查看';
-$lang->goback = '返回';
-$lang->go = 'GO';
-$lang->more = '更多';
-
-$lang->actions = '操作';
-$lang->comment = '備註';
-$lang->history = '歷史記錄';
-$lang->attatch = '附件';
-$lang->reverse = '[切換順序]';
-$lang->switchDisplay= '[切換顯示]';
-$lang->switchHelp = '切換幫助';
-$lang->addFiles = '上傳了附件 ';
-$lang->files = '附件 ';
-$lang->unfold = '+';
-$lang->fold = '-';
-
-$lang->selectAll = '全選';
-$lang->notFound = '抱歉,您訪問的對象並不存在!';
-$lang->showAll = '++ 全部顯示 ++';
-$lang->hideClosed = '-- 隱藏已結束 --';
-
-$lang->feature = '未來';
-$lang->year = '年';
-$lang->workingHour = '工時';
-
-$lang->idAB = 'ID';
-$lang->priAB = 'P';
-$lang->statusAB = '狀態';
-$lang->openedByAB = '創建';
-$lang->assignedToAB = '指派';
-$lang->typeAB = '類型';
-
-$lang->common->common = '公有模組';
-
-/* 主導航菜單。*/
-$lang->menu->my = '我的地盤|my|index';
-$lang->menu->product = '產品視圖|product|index';
-$lang->menu->project = '項目視圖|project|index';
-$lang->menu->qa = '測試視圖|qa|index';
-$lang->menu->doc = '文檔視圖|doc|index';
-$lang->menu->company = '組織視圖|company|index';
-$lang->menu->admin = '後台管理|admin|index';
-
-/* 查詢條中可以選擇的對象列表。*/
-$lang->searchObjects['bug'] = 'B:Bug';
-$lang->searchObjects['story'] = 'S:需求';
-$lang->searchObjects['task'] = 'T:任務';
-$lang->searchObjects['testcase'] = 'C:用例';
-$lang->searchObjects['project'] = 'P:項目';
-$lang->searchObjects['product'] = 'P:產品';
-$lang->searchObjects['user'] = 'U:用戶';
-$lang->searchObjects['build'] = 'B:Build';
-$lang->searchObjects['release'] = 'R:發佈';
-$lang->searchObjects['productplan'] = 'P:產品計劃';
-$lang->searchObjects['testtask'] = 'T:測試任務';
-$lang->searchObjects['doc'] = 'D:文檔';
-$lang->searchTips = '輸入編號';
-
-/* 導出檔案的類型列表。*/
-$lang->exportFileTypeList['csv'] = 'csv';
-$lang->exportFileTypeList['xml'] = 'xml';
-$lang->exportFileTypeList['html'] = 'html';
-
-/* 風格列表。*/
-$lang->themes['default'] = '預設';
-$lang->themes['green'] = '綠色';
-$lang->themes['red'] = '紅色';
-$lang->themes['classblue'] = '經典藍';
-
-/* 首頁菜單設置。*/
-$lang->index->menu->product = '瀏覽產品|product|browse';
-$lang->index->menu->project = '瀏覽項目|project|browse';
-
-/* 我的地盤菜單設置。*/
-$lang->my->menu->account = '%s' . $lang->arrow;
-$lang->my->menu->index = '首頁|my|index';
-$lang->my->menu->todo = array('link' => '我的TODO|my|todo|', 'subModule' => 'todo');
-$lang->my->menu->task = '我的任務|my|task|';
-$lang->my->menu->bug = '我的Bug|my|bug|';
-$lang->my->menu->testtask = '我的測試|my|testtask|';
-$lang->my->menu->story = '我的需求|my|story|';
-$lang->my->menu->myProject = '我的項目|my|project|';
-$lang->my->menu->dynamic = '我的動態|my|dynamic|';
-$lang->my->menu->profile = array('link' => '我的檔案|my|profile|', 'alias' => 'editprofile');
-$lang->todo->menu = $lang->my->menu;
-
-/* 產品視圖設置。*/
-$lang->product->menu->list = '%s';
-$lang->product->menu->story = array('link' => '需求|product|browse|productID=%s', 'subModule' => 'story');
-$lang->product->menu->dynamic = '動態|product|dynamic|productID=%s';
-$lang->product->menu->plan = array('link' => '計劃|productplan|browse|productID=%s', 'subModule' => 'productplan');
-$lang->product->menu->release = array('link' => '發佈|release|browse|productID=%s', 'subModule' => 'release');
-$lang->product->menu->roadmap = '路線圖|product|roadmap|productID=%s';
-$lang->product->menu->doc = array('link' => '文檔|product|doc|productID=%s', 'subModule' => 'doc');
-$lang->product->menu->view = '概況|product|view|productID=%s';
-$lang->product->menu->edit = '編輯|product|edit|productID=%s';
-$lang->product->menu->delete = array('link' => '刪除|product|delete|productID=%s', 'target' => 'hiddenwin');
-$lang->product->menu->module = '模組|tree|browse|productID=%s&view=story';
-$lang->product->menu->create = array('link' => '新增產品|product|create', 'float' => 'right');
-$lang->product->menu->project = array('link' => '項目列表|product|project|status=all&productID=%s', 'float' => 'right');
-$lang->product->menu->all = array('link' => '所有產品|product|index|locate=false', 'float' => 'right');
-$lang->story->menu = $lang->product->menu;
-$lang->productplan->menu = $lang->product->menu;
-$lang->release->menu = $lang->product->menu;
-
-/* 項目視圖菜單設置。*/
-$lang->project->menu->list = '%s';
-$lang->project->menu->task = array('link' => '任務|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask');
-$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s');
-$lang->project->menu->bug = 'Bug|project|bug|projectID=%s';
-$lang->project->menu->dynamic = '動態|project|dynamic|projectID=%s';
-$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build');
-$lang->project->menu->testtask = '測試任務|project|testtask|projectID=%s';
-$lang->project->menu->burn = '燃盡圖|project|burn|projectID=%s';
-$lang->project->menu->team = array('link' => '團隊|project|team|projectID=%s', 'alias' => 'managemembers');
-$lang->project->menu->doc = array('link' => '文檔|project|doc|porjectID=%s', 'subModule' => 'doc');
-$lang->project->menu->product = '產品|project|manageproducts|projectID=%s';
-$lang->project->menu->linkstory = array('link' => '關聯需求|project|linkstory|projectID=%s');
-$lang->project->menu->view = '概況|project|view|projectID=%s';
-$lang->project->menu->edit = '編輯|project|edit|projectID=%s';
-$lang->project->menu->delete = array('link' => '刪除|project|delete|projectID=%s', 'target' => 'hiddenwin');
-$lang->project->menu->create = array('link' => '新增項目|project|create', 'float' => 'right');
-$lang->project->menu->all = array('link' => '所有項目|project|index|locate=false', 'float' => 'right');
-$lang->task->menu = $lang->project->menu;
-$lang->build->menu = $lang->project->menu;
-
-/* QA視圖菜單設置。*/
-$lang->bug->menu->product = '%s';
-$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree');
-$lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit');
-$lang->bug->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s');
-
-$lang->testcase->menu->product = '%s';
-$lang->testcase->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s');
-$lang->testcase->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree');
-$lang->testcase->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s');
-
-$lang->testtask->menu->product = '%s';
-$lang->testtask->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s');
-$lang->testtask->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s');
-$lang->testtask->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases');
-
-/* 文檔視圖菜單設置。*/
-$lang->doc->menu->list = '%s';
-$lang->doc->menu->browse = array('link' => '文檔列表|doc|browse|libID=%s');
-$lang->doc->menu->edit = '編輯文檔庫|doc|editLib|libID=%s';
-$lang->doc->menu->module = '維護模組|tree|browse|libID=%s&viewType=doc';
-$lang->doc->menu->delete = array('link' => '刪除文檔庫|doc|deleteLib|libID=%s', 'target' => 'hiddenwin');
-$lang->doc->menu->create = array('link' => '新增文檔庫|doc|createLib', 'float' => 'right');
-
-/* 組織結構視圖菜單設置。*/
-$lang->company->menu->name = '%s' . $lang->arrow;
-$lang->company->menu->browseUser = array('link' => '用戶列表|company|browse', 'subModule' => 'user');
-$lang->company->menu->dept = array('link' => '部門維護|dept|browse', 'subModule' => 'dept');
-$lang->company->menu->browseGroup = array('link' => '權限分組|group|browse', 'subModule' => 'group');
-$lang->company->menu->edit = array('link' => '公司管理|company|edit');
-$lang->company->menu->dynamic = '組織動態|company|dynamic|';
-$lang->company->menu->addGroup = array('link' => '添加分組|group|create', 'float' => 'right');
-$lang->company->menu->addUser = array('link' => '添加用戶|user|create|dept=%s', 'subModule' => 'user', 'float' => 'right');
-$lang->dept->menu = $lang->company->menu;
-$lang->group->menu = $lang->company->menu;
-
-/* 用戶信息菜單設置。*/
-$lang->user->menu->account = '%s' . $lang->arrow;
-$lang->user->menu->todo = array('link' => 'TODO列表|user|todo|account=%s', 'subModule' => 'todo');
-$lang->user->menu->task = '任務列表|user|task|account=%s';
-$lang->user->menu->bug = 'Bug列表|user|bug|account=%s';
-$lang->user->menu->dynamic = '用戶動態|user|dynamic|type=today&account=%s';
-$lang->user->menu->projectList = '項目列表|user|project|account=%s';
-$lang->user->menu->profile = array('link' => '用戶信息|user|profile|account=%s', 'alias' => 'edit');
-$lang->user->menu->browse = array('link' => '用戶管理|company|browse|', 'float' => 'right');
-
-/* 後台管理菜單設置。*/
-$lang->admin->menu->extension = array('link' => '插件管理|extension|browse', 'subModule' => 'extension');
-$lang->admin->menu->editor = array('link' => '擴展編輯器|editor|index', 'subModule' => 'editor');
-$lang->admin->menu->mail = array('link' => 'Email配置|mail|set', 'subModule' => 'mail');
-$lang->admin->menu->convert = array('link' => '從其他系統導入|convert|index', 'subModule' => 'convert');
-$lang->admin->menu->trashes = array('link' => '資源回收筒|action|trash', 'subModule' => 'action');
-$lang->convert->menu = $lang->admin->menu;
-$lang->upgrade->menu = $lang->admin->menu;
-$lang->action->menu = $lang->admin->menu;
-$lang->extension->menu = $lang->admin->menu;
-$lang->editor->menu = $lang->admin->menu;
-$lang->mail->menu = $lang->admin->menu;
-
-/*菜單設置:分組設置。*/
-$lang->menugroup->release = 'product';
-$lang->menugroup->story = 'product';
-$lang->menugroup->productplan = 'product';
-$lang->menugroup->task = 'project';
-$lang->menugroup->build = 'project';
-$lang->menugroup->convert = 'admin';
-$lang->menugroup->upgrade = 'admin';
-$lang->menugroup->user = 'company';
-$lang->menugroup->group = 'company';
-$lang->menugroup->bug = 'qa';
-$lang->menugroup->testcase = 'qa';
-$lang->menugroup->testtask = 'qa';
-$lang->menugroup->people = 'company';
-$lang->menugroup->dept = 'company';
-$lang->menugroup->todo = 'my';
-$lang->menugroup->action = 'admin';
-$lang->menugroup->extension = 'admin';
-$lang->menugroup->editor = 'admin';
-$lang->menugroup->mail = 'admin';
-
-/* 錯誤提示信息。*/
-$lang->error->companyNotFound = "您訪問的域名 %s 沒有對應的公司。";
-$lang->error->length = array("『%s』長度錯誤,應當為『%s』", "『%s』長度應當不超過『%s』,且不小於『%s』。");
-$lang->error->reg = "『%s』不符合格式,應當為:『%s』。";
-$lang->error->unique = "『%s』已經有『%s』這條記錄了。";
-$lang->error->gt = "『%s』應當大於『%s』。";
-$lang->error->notempty = "『%s』不能為空。";
-$lang->error->empty = "『%s』必須為空。";
-$lang->error->equal = "『%s』必須為『%s』。";
-$lang->error->int = array("『%s』應當是數字。", "『%s』應當介於『%s-%s』之間。");
-$lang->error->float = "『%s』應當是數字,可以是小數。";
-$lang->error->email = "『%s』應當為合法的EMAIL。";
-$lang->error->date = "『%s』應當為合法的日期。";
-$lang->error->account = "『%s』應當為合法的用戶名。";
-$lang->error->passwordsame = "兩次密碼應當相等。";
-$lang->error->passwordrule = "密碼應該符合規則,長度至少為六位。";
-$lang->error->accessDenied = '您沒有訪問權限';
-
-/* 分頁信息。*/
-$lang->pager->noRecord = "暫時沒有記錄";
-$lang->pager->digest = "共%s 條記錄,每頁 %s 條,頁面:%s/%s ";
-$lang->pager->first = "首頁";
-$lang->pager->pre = "上頁";
-$lang->pager->next = "下頁";
-$lang->pager->last = "末頁";
-$lang->pager->locate = "GO!";
-
-$lang->zentaoSite = "官方網站";
-$lang->chinaScrum = "Scrum社區 ";
-$lang->agileTraining = "培訓 ";
-$lang->donate = "捐助禪道 ";
-$lang->zentaoKeywords = "開源項目管理軟件,項目管理,項目管理軟件,pmp,pms,php框架,國產php框架,scrum工具,scrum管理工具,scrum管理軟件,敏捷項目管理,禪道";
-$lang->zentaoDESC = "禪道項目管理軟件(ZenTaoPMS)是一款國產的,基于LGPL協議,開源免費的項目管理軟件(工具、系統),同時也是一款scrum管理工具。
- 它集產品管理、項目管理、測試管理於一體,同時還包含了事務管理、組織管理等諸多功能,是中小型企業項目管理的首選。禪道項目管理軟件使用PHP + MySQL開發,
-基于自主的PHP開發框架──ZenTaoPHP而成。第三方開發者或者企業可以非常方便的開發插件或者進行定製。禪道在手,項目無憂!";
-
-/* 時間格式設置。*/
-define('DT_DATETIME1', 'Y-m-d H:i:s');
-define('DT_DATETIME2', 'y-m-d H:i');
-define('DT_MONTHTIME1', 'n/d H:i');
-define('DT_MONTHTIME2', 'n月d日 H:i');
-define('DT_DATE1', 'Y-m-d');
-define('DT_DATE2', 'Ymd');
-define('DT_DATE3', 'Y年m月d日');
-define('DT_DATE4', 'n月j日');
-define('DT_TIME1', 'H:i:s');
-define('DT_TIME2', 'H:i');
+
+ * @package ZenTaoPMS
+ * @version $Id: zh-tw.php 2538 2012-01-04 07:25:59Z shiyangyangwork@yahoo.cn $
+ * @link http://www.zentao.net
+ */
+$lang->arrow = ' » ';
+$lang->colon = '::';
+$lang->comma = ',';
+$lang->dot = '。';
+$lang->at = ' 于 ';
+$lang->downArrow = '↓';
+
+$lang->ZenTaoPMS = '禪道管理';
+$lang->welcome = "歡迎使用『%s』{$lang->colon} {$lang->ZenTaoPMS}";
+$lang->myControl = "我的地盤";
+$lang->currentPos = '當前位置:';
+$lang->logout = '退出';
+$lang->login = '登錄';
+$lang->aboutZenTao = '關於';
+$lang->todayIs = '今天是%s,';
+$lang->runInfo = "時間: %s 毫秒, 內存: %s KB, 查詢: %s.
";
+
+$lang->reset = '重填';
+$lang->edit = '編輯';
+$lang->copy = '複製';
+$lang->delete = '刪除';
+$lang->close = '關閉';
+$lang->link = '關聯';
+$lang->unlink = '移除';
+$lang->import = '導入';
+$lang->export = '導出';
+$lang->setFileName = '檔案名:';
+$lang->activate = '激活';
+$lang->submitting = '稍候...';
+$lang->save = '保存';
+$lang->confirm = '確認';
+$lang->preview = '查看';
+$lang->goback = '返回';
+$lang->go = 'GO';
+$lang->more = '更多';
+
+$lang->actions = '操作';
+$lang->comment = '備註';
+$lang->history = '歷史記錄';
+$lang->attatch = '附件';
+$lang->reverse = '[切換順序]';
+$lang->switchDisplay= '[切換顯示]';
+$lang->switchHelp = '切換幫助';
+$lang->addFiles = '上傳了附件 ';
+$lang->files = '附件 ';
+$lang->unfold = '+';
+$lang->fold = '-';
+
+$lang->selectAll = '全選';
+$lang->notFound = '抱歉,您訪問的對象並不存在!';
+$lang->showAll = '++ 全部顯示 ++';
+$lang->hideClosed = '-- 隱藏已結束 --';
+
+$lang->feature = '未來';
+$lang->year = '年';
+$lang->workingHour = '工時';
+
+$lang->idAB = 'ID';
+$lang->priAB = 'P';
+$lang->statusAB = '狀態';
+$lang->openedByAB = '創建';
+$lang->assignedToAB = '指派';
+$lang->typeAB = '類型';
+
+$lang->common->common = '公有模組';
+
+/* 主導航菜單。*/
+$lang->menu->my = '我的地盤|my|index';
+$lang->menu->product = '產品視圖|product|index';
+$lang->menu->project = '項目視圖|project|index';
+$lang->menu->qa = '測試視圖|qa|index';
+$lang->menu->doc = '文檔視圖|doc|index';
+$lang->menu->company = '組織視圖|company|index';
+$lang->menu->admin = '後台管理|admin|index';
+
+/* 查詢條中可以選擇的對象列表。*/
+$lang->searchObjects['bug'] = 'B:Bug';
+$lang->searchObjects['story'] = 'S:需求';
+$lang->searchObjects['task'] = 'T:任務';
+$lang->searchObjects['testcase'] = 'C:用例';
+$lang->searchObjects['project'] = 'P:項目';
+$lang->searchObjects['product'] = 'P:產品';
+$lang->searchObjects['user'] = 'U:用戶';
+$lang->searchObjects['build'] = 'B:Build';
+$lang->searchObjects['release'] = 'R:發佈';
+$lang->searchObjects['productplan'] = 'P:產品計劃';
+$lang->searchObjects['testtask'] = 'T:測試任務';
+$lang->searchObjects['doc'] = 'D:文檔';
+$lang->searchTips = '輸入編號';
+
+/* 導出檔案的類型列表。*/
+$lang->exportFileTypeList['csv'] = 'csv';
+$lang->exportFileTypeList['xml'] = 'xml';
+$lang->exportFileTypeList['html'] = 'html';
+
+/* 風格列表。*/
+$lang->themes['default'] = '預設';
+$lang->themes['green'] = '綠色';
+$lang->themes['red'] = '紅色';
+$lang->themes['classblue'] = '經典藍';
+
+/* 首頁菜單設置。*/
+$lang->index->menu->product = '瀏覽產品|product|browse';
+$lang->index->menu->project = '瀏覽項目|project|browse';
+
+/* 我的地盤菜單設置。*/
+$lang->my->menu->account = '%s' . $lang->arrow;
+$lang->my->menu->index = '首頁|my|index';
+$lang->my->menu->todo = array('link' => '我的TODO|my|todo|', 'subModule' => 'todo');
+$lang->my->menu->task = '我的任務|my|task|';
+$lang->my->menu->bug = '我的Bug|my|bug|';
+$lang->my->menu->testtask = '我的測試|my|testtask|';
+$lang->my->menu->story = '我的需求|my|story|';
+$lang->my->menu->myProject = '我的項目|my|project|';
+$lang->my->menu->dynamic = '我的動態|my|dynamic|';
+$lang->my->menu->profile = array('link' => '我的檔案|my|profile|', 'alias' => 'editprofile');
+$lang->todo->menu = $lang->my->menu;
+
+/* 產品視圖設置。*/
+$lang->product->menu->list = '%s';
+$lang->product->menu->story = array('link' => '需求|product|browse|productID=%s', 'subModule' => 'story');
+$lang->product->menu->dynamic = '動態|product|dynamic|productID=%s';
+$lang->product->menu->plan = array('link' => '計劃|productplan|browse|productID=%s', 'subModule' => 'productplan');
+$lang->product->menu->release = array('link' => '發佈|release|browse|productID=%s', 'subModule' => 'release');
+$lang->product->menu->roadmap = '路線圖|product|roadmap|productID=%s';
+$lang->product->menu->doc = array('link' => '文檔|product|doc|productID=%s', 'subModule' => 'doc');
+$lang->product->menu->view = '概況|product|view|productID=%s';
+$lang->product->menu->edit = '編輯|product|edit|productID=%s';
+$lang->product->menu->delete = array('link' => '刪除|product|delete|productID=%s', 'target' => 'hiddenwin');
+$lang->product->menu->module = '模組|tree|browse|productID=%s&view=story';
+$lang->product->menu->create = array('link' => '新增產品|product|create', 'float' => 'right');
+$lang->product->menu->project = array('link' => '項目列表|product|project|status=all&productID=%s', 'float' => 'right');
+$lang->product->menu->all = array('link' => '所有產品|product|index|locate=false', 'float' => 'right');
+$lang->story->menu = $lang->product->menu;
+$lang->productplan->menu = $lang->product->menu;
+$lang->release->menu = $lang->product->menu;
+
+/* 項目視圖菜單設置。*/
+$lang->project->menu->list = '%s';
+$lang->project->menu->task = array('link' => '任務|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask');
+$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s');
+$lang->project->menu->bug = 'Bug|project|bug|projectID=%s';
+$lang->project->menu->dynamic = '動態|project|dynamic|projectID=%s';
+$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build');
+$lang->project->menu->testtask = '測試任務|project|testtask|projectID=%s';
+$lang->project->menu->burn = '燃盡圖|project|burn|projectID=%s';
+$lang->project->menu->team = array('link' => '團隊|project|team|projectID=%s', 'alias' => 'managemembers');
+$lang->project->menu->doc = array('link' => '文檔|project|doc|porjectID=%s', 'subModule' => 'doc');
+$lang->project->menu->product = '產品|project|manageproducts|projectID=%s';
+$lang->project->menu->linkstory = array('link' => '關聯需求|project|linkstory|projectID=%s');
+$lang->project->menu->view = '概況|project|view|projectID=%s';
+$lang->project->menu->edit = '編輯|project|edit|projectID=%s';
+$lang->project->menu->delete = array('link' => '刪除|project|delete|projectID=%s', 'target' => 'hiddenwin');
+$lang->project->menu->create = array('link' => '新增項目|project|create', 'float' => 'right');
+$lang->project->menu->all = array('link' => '所有項目|project|index|locate=false', 'float' => 'right');
+$lang->task->menu = $lang->project->menu;
+$lang->build->menu = $lang->project->menu;
+
+/* QA視圖菜單設置。*/
+$lang->bug->menu->product = '%s';
+$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree');
+$lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit');
+$lang->bug->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s');
+
+$lang->testcase->menu->product = '%s';
+$lang->testcase->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s');
+$lang->testcase->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree');
+$lang->testcase->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s');
+
+$lang->testtask->menu->product = '%s';
+$lang->testtask->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s');
+$lang->testtask->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s');
+$lang->testtask->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases');
+
+/* 文檔視圖菜單設置。*/
+$lang->doc->menu->list = '%s';
+$lang->doc->menu->browse = array('link' => '文檔列表|doc|browse|libID=%s');
+$lang->doc->menu->edit = '編輯文檔庫|doc|editLib|libID=%s';
+$lang->doc->menu->module = '維護模組|tree|browse|libID=%s&viewType=doc';
+$lang->doc->menu->delete = array('link' => '刪除文檔庫|doc|deleteLib|libID=%s', 'target' => 'hiddenwin');
+$lang->doc->menu->create = array('link' => '新增文檔庫|doc|createLib', 'float' => 'right');
+
+/* 組織結構視圖菜單設置。*/
+$lang->company->menu->name = '%s' . $lang->arrow;
+$lang->company->menu->browseUser = array('link' => '用戶列表|company|browse', 'subModule' => 'user');
+$lang->company->menu->dept = array('link' => '部門維護|dept|browse', 'subModule' => 'dept');
+$lang->company->menu->browseGroup = array('link' => '權限分組|group|browse', 'subModule' => 'group');
+$lang->company->menu->edit = array('link' => '公司管理|company|edit');
+$lang->company->menu->dynamic = '組織動態|company|dynamic|';
+$lang->company->menu->addGroup = array('link' => '添加分組|group|create', 'float' => 'right');
+$lang->company->menu->addUser = array('link' => '添加用戶|user|create|dept=%s', 'subModule' => 'user', 'float' => 'right');
+$lang->dept->menu = $lang->company->menu;
+$lang->group->menu = $lang->company->menu;
+
+/* 用戶信息菜單設置。*/
+$lang->user->menu->account = '%s' . $lang->arrow;
+$lang->user->menu->todo = array('link' => 'TODO列表|user|todo|account=%s', 'subModule' => 'todo');
+$lang->user->menu->task = '任務列表|user|task|account=%s';
+$lang->user->menu->bug = 'Bug列表|user|bug|account=%s';
+$lang->user->menu->dynamic = '用戶動態|user|dynamic|type=today&account=%s';
+$lang->user->menu->projectList = '項目列表|user|project|account=%s';
+$lang->user->menu->profile = array('link' => '用戶信息|user|profile|account=%s', 'alias' => 'edit');
+$lang->user->menu->browse = array('link' => '用戶管理|company|browse|', 'float' => 'right');
+
+/* 後台管理菜單設置。*/
+$lang->admin->menu->extension = array('link' => '插件管理|extension|browse', 'subModule' => 'extension');
+$lang->admin->menu->editor = array('link' => '擴展編輯器|editor|index', 'subModule' => 'editor');
+$lang->admin->menu->mail = array('link' => 'Email配置|mail|set', 'subModule' => 'mail');
+$lang->admin->menu->convert = array('link' => '從其他系統導入|convert|index', 'subModule' => 'convert');
+$lang->admin->menu->trashes = array('link' => '資源回收筒|action|trash', 'subModule' => 'action');
+$lang->convert->menu = $lang->admin->menu;
+$lang->upgrade->menu = $lang->admin->menu;
+$lang->action->menu = $lang->admin->menu;
+$lang->extension->menu = $lang->admin->menu;
+$lang->editor->menu = $lang->admin->menu;
+$lang->mail->menu = $lang->admin->menu;
+
+/*菜單設置:分組設置。*/
+$lang->menugroup->release = 'product';
+$lang->menugroup->story = 'product';
+$lang->menugroup->productplan = 'product';
+$lang->menugroup->task = 'project';
+$lang->menugroup->build = 'project';
+$lang->menugroup->convert = 'admin';
+$lang->menugroup->upgrade = 'admin';
+$lang->menugroup->user = 'company';
+$lang->menugroup->group = 'company';
+$lang->menugroup->bug = 'qa';
+$lang->menugroup->testcase = 'qa';
+$lang->menugroup->testtask = 'qa';
+$lang->menugroup->people = 'company';
+$lang->menugroup->dept = 'company';
+$lang->menugroup->todo = 'my';
+$lang->menugroup->action = 'admin';
+$lang->menugroup->extension = 'admin';
+$lang->menugroup->editor = 'admin';
+$lang->menugroup->mail = 'admin';
+
+/* 錯誤提示信息。*/
+$lang->error->companyNotFound = "您訪問的域名 %s 沒有對應的公司。";
+$lang->error->length = array("『%s』長度錯誤,應當為『%s』", "『%s』長度應當不超過『%s』,且不小於『%s』。");
+$lang->error->reg = "『%s』不符合格式,應當為:『%s』。";
+$lang->error->unique = "『%s』已經有『%s』這條記錄了。";
+$lang->error->gt = "『%s』應當大於『%s』。";
+$lang->error->notempty = "『%s』不能為空。";
+$lang->error->empty = "『%s』必須為空。";
+$lang->error->equal = "『%s』必須為『%s』。";
+$lang->error->int = array("『%s』應當是數字。", "『%s』應當介於『%s-%s』之間。");
+$lang->error->float = "『%s』應當是數字,可以是小數。";
+$lang->error->email = "『%s』應當為合法的EMAIL。";
+$lang->error->date = "『%s』應當為合法的日期。";
+$lang->error->account = "『%s』應當為合法的用戶名。";
+$lang->error->passwordsame = "兩次密碼應當相等。";
+$lang->error->passwordrule = "密碼應該符合規則,長度至少為六位。";
+$lang->error->accessDenied = '您沒有訪問權限';
+
+/* 分頁信息。*/
+$lang->pager->noRecord = "暫時沒有記錄";
+$lang->pager->digest = "共%s 條記錄,每頁 %s 條,頁面:%s/%s ";
+$lang->pager->first = "首頁";
+$lang->pager->pre = "上頁";
+$lang->pager->next = "下頁";
+$lang->pager->last = "末頁";
+$lang->pager->locate = "GO!";
+
+$lang->zentaoSite = "官方網站";
+$lang->chinaScrum = "Scrum社區 ";
+$lang->agileTraining = "培訓 ";
+$lang->donate = "捐助禪道 ";
+$lang->zentaoKeywords = "開源項目管理軟件,項目管理,項目管理軟件,pmp,pms,php框架,國產php框架,scrum工具,scrum管理工具,scrum管理軟件,敏捷項目管理,禪道";
+$lang->zentaoDESC = "禪道項目管理軟件(ZenTaoPMS)是一款國產的,基于LGPL協議,開源免費的項目管理軟件(工具、系統),同時也是一款scrum管理工具。
+ 它集產品管理、項目管理、測試管理於一體,同時還包含了事務管理、組織管理等諸多功能,是中小型企業項目管理的首選。禪道項目管理軟件使用PHP + MySQL開發,
+基于自主的PHP開發框架──ZenTaoPHP而成。第三方開發者或者企業可以非常方便的開發插件或者進行定製。禪道在手,項目無憂!";
+
+/* 時間格式設置。*/
+define('DT_DATETIME1', 'Y-m-d H:i:s');
+define('DT_DATETIME2', 'y-m-d H:i');
+define('DT_MONTHTIME1', 'n/d H:i');
+define('DT_MONTHTIME2', 'n月d日 H:i');
+define('DT_DATE1', 'Y-m-d');
+define('DT_DATE2', 'Ymd');
+define('DT_DATE3', 'Y年m月d日');
+define('DT_DATE4', 'n月j日');
+define('DT_TIME1', 'H:i:s');
+define('DT_TIME2', 'H:i');
diff --git a/module/common/model.php b/module/common/model.php
index 10140ec0e8..d2a72b5751 100644
--- a/module/common/model.php
+++ b/module/common/model.php
@@ -1,366 +1,366 @@
-
- * @package common
- * @version $Id$
- * @link http://www.zentao.net
- */
-class commonModel extends model
-{
- /**
- * Start the session.
- *
- * @access public
- * @return void
- */
- public function startSession()
- {
- session_name($this->config->sessionVar);
- if(isset($_GET[$this->config->sessionVar])) session_id($_GET[$this->config->sessionVar]);
- session_start();
- }
-
- /**
- * Set the header info.
- *
- * @access public
- * @return void
- */
- public function sendHeader()
- {
- header("Content-Type: text/html; Language={$this->config->encoding}");
- header("Cache-control: private");
- }
-
- /**
- * Set the commpany.
- *
- * First, search company by the http host. If not found, search by the default domain. Last, use the first as the default.
- * After get the company, save it to session.
- * @access public
- * @return void
- */
- public function setCompany()
- {
- $httpHost = $this->server->http_host;
- if(strpos($httpHost, ":"))
- {
- $httpHost = explode(":", $httpHost);
- $httpHost = $httpHost[0];
- }
-
- if($this->session->company and $this->session->company->pms == $httpHost)
- {
- $this->app->company = $this->session->company;
- }
- else
- {
- $company = $this->loadModel('company')->getByDomain();
- if(!$company and isset($this->config->default->domain)) $company = $this->company->getByDomain($this->config->default->domain);
- if(!$company) $company = $this->company->getFirst();
- if(!$company) $this->app->error(sprintf($this->lang->error->companyNotFound, $httpHost), __FILE__, __LINE__, $exit = true);
- $this->session->set('company', $company);
- $this->app->company = $company;
- }
- }
-
- /**
- * Set the user info.
- *
- * @access public
- * @return void
- */
- public function setUser()
- {
- if($this->session->user)
- {
- $this->app->user = $this->session->user;
- }
- elseif($this->app->company->guest)
- {
- $user = new stdClass();
- $user->id = 0;
- $user->account = 'guest';
- $user->realname = 'guest';
- $user->rights = $this->loadModel('user')->authorize('guest');
- $this->session->set('user', $user);
- $this->app->user = $this->session->user;
- }
- }
-
- /**
- * Juage a method of one module is open or not?
- *
- * @param string $module
- * @param string $method
- * @access public
- * @return bool
- */
- public function isOpenMethod($module, $method)
- {
- if($module == 'user' and strpos('login|logout|deny', $method) !== false) return true;
- if($module == 'api' and $method == 'getsessionid') return true;
- if($module == 'misc' and $method == 'about') return true;
- if($module == 'help' and $method == 'field') return true;
- return false;
- }
-
- /**
- * Deny access.
- *
- * @access public
- * @return void
- */
- public function deny($module, $method)
- {
- $vars = "module=$module&method=$method";
- if(isset($this->server->http_referer))
- {
- $referer = helper::safe64Encode($this->server->http_referer);
- $vars .= "&referer=$referer";
- }
- $denyLink = helper::createLink('user', 'deny', $vars);
-
- /* Fix the bug of IE: use js locate, can't get the referer. */
- if(strpos($this->server->http_user_agent, 'MSIE') !== false)
- {
- echo "deny ";
- echo "";
- }
- else
- {
- echo js::locate($denyLink);
- }
- exit;
- }
-
- /**
- * Get the run info.
- *
- * @param mixed $startTime the start time of this execution
- * @access public
- * @return array the run info array.
- */
- public function getRunInfo($startTime)
- {
- $info['timeUsed'] = round(getTime() - $startTime, 4) * 1000;
- $info['memory'] = round(memory_get_peak_usage() / 1024, 1);
- $info['querys'] = count(dao::$querys);
- return $info;
- }
-
- /**
- * Print top bar.
- *
- * @static
- * @access public
- * @return void
- */
- public static function printTopBar()
- {
- global $lang, $app;
-
- printf($lang->todayIs, date(DT_DATE3));
- if(isset($app->user)) echo $app->user->realname . ' ';
- if(isset($app->user) and $app->user->account != 'guest')
- {
- echo html::a(helper::createLink('my', 'index'), $lang->myControl);
- echo html::a(helper::createLink('user', 'logout'), $lang->logout);
- }
- else
- {
- echo html::a(helper::createLink('user', 'login'), $lang->login);
- }
- echo html::a(helper::createLink('misc', 'about'), $lang->aboutZenTao, '', "class='about'");
- echo $lang->agileTraining;
- echo $lang->donate;
- }
-
- /**
- * Print the main menu.
- *
- * @param string $moduleName
- * @static
- * @access public
- * @return void
- */
- public static function printMainmenu($moduleName)
- {
- global $app, $lang;
- echo "\n";
-
- /* Set the main main menu. */
- $mainMenu = $moduleName;
- if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName;
-
- /* Print all main menus. */
- foreach($lang->menu as $menuKey => $menu)
- {
- $active = $menuKey == $mainMenu ? "class='active'" : '';
- list($menuLabel, $module, $method) = explode('|', $menu);
-
- if(common::hasPriv($module, $method))
- {
- $link = helper::createLink($module, $method);
- echo " \n";
- }
- }
-
- }
-
- /**
- * Print the search box.
- *
- * @static
- * @access public
- * @return void
- */
- public static function printSearchBox()
- {
- global $app, $lang;
- $moduleName = $app->getModuleName();
- $methodName = $app->getMethodName();
- $searchObject = $moduleName;
-
- if($moduleName == 'product')
- {
- if($methodName == 'browse') $searchObject = 'story';
- }
- elseif($moduleName == 'project')
- {
- if(strpos('task|story|bug|build', $methodName) !== false) $searchObject = $methodName;
- }
- elseif($moduleName == 'my' or $moduleName == 'user')
- {
- $searchObject = $methodName;
- }
-
- echo "";
- echo html::select('searchType', $lang->searchObjects, $searchObject);
- echo html::input('searchQuery', $lang->searchTips, "onclick=this.value='' onkeydown='if(event.keyCode==13) shortcut()' class='w-60px'");
- echo html::commonButton($lang->go, 'id="objectSwitcher" onclick="shortcut()"');
- echo " ";
- echo " \n";
- }
-
- /**
- * Print the module menu.
- *
- * @param string $moduleName
- * @static
- * @access public
- * @return void
- */
- public static function printModuleMenu($moduleName)
- {
- global $lang, $app;
-
- if(!isset($lang->$moduleName->menu)) {echo ""; return;}
-
- /* Get the sub menus of the module, and get current module and method. */
- $submenus = $lang->$moduleName->menu;
- $currentModule = $app->getModuleName();
- $currentMethod = $app->getMethodName();
-
- /* The beginning of the menu. */
- echo "\n";
-
- /* Cycling to print every sub menus. */
- foreach($submenus as $subMenuKey => $submenu)
- {
- /* Init the these vars. */
- $link = $submenu;
- $subModule = '';
- $alias = '';
- $float = '';
- $active = '';
- $target = '';
-
- if(is_array($submenu)) extract($submenu); // If the sub menu is an array, extract it.
-
- /* Print the menu. */
- if(strpos($link, '|') === false)
- {
- echo "$link \n";
- }
- else
- {
- $link = explode('|', $link);
- list($label, $module, $method) = $link;
- $vars = isset($link[3]) ? $link[3] : '';
- if(common::hasPriv($module, $method))
- {
- /* Is the currentModule active? */
- if($currentModule == $subModule) $active = 'active';
- if($module == $currentModule and ($method == $currentMethod or strpos($alias, $currentMethod) !== false)) $active = 'active';
- echo "" . html::a(helper::createLink($module, $method, $vars), $label, $target, "id=submenu$subMenuKey") . " \n";
- }
- }
- }
- echo " \n";
- }
-
- /**
- * Print the bread menu.
- *
- * @param string $moduleName
- * @param string $position
- * @static
- * @access public
- * @return void
- */
- public static function printBreadMenu($moduleName, $position)
- {
- global $lang;
- $mainMenu = $moduleName;
- if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName;
- echo html::a(helper::createLink('my', 'index'), $lang->ZenTaoPMS) . $lang->arrow;
- if($moduleName != 'index')
- {
- list($menuLabel, $module, $method) = explode('|', $lang->menu->$mainMenu);
- echo html::a(helper::createLink($module, $method), $menuLabel);
- }
- else
- {
- echo $lang->index->common;
- }
- if(empty($position)) return;
- echo $lang->arrow;
- foreach($position as $key => $link)
- {
- echo $link;
- if(isset($position[$key + 1])) echo $lang->arrow;
- }
- }
-
-
- /**
- * Diff two string. (see phpt)
- *
- * @param string $text1
- * @param string $text2
- * @static
- * @access public
- * @return string
- */
- public static function diff($text1, $text2)
- {
- $text1 = str_replace(' ', '', trim($text1));
- $text2 = str_replace(' ', '', trim($text2));
- $w = explode("\n", $text1);
- $o = explode("\n", $text2);
- $w1 = array_diff_assoc($w,$o);
- $o1 = array_diff_assoc($o,$w);
- $w2 = array();
- $o2 = array();
- foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1) . "" . trim($val) . "";
- foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1) . "" . trim($val) . " ";
- $diff = array_merge($w2, $o2);
- ksort($diff);
- return implode("\n", $diff);
- }
-}
+
+ * @package common
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class commonModel extends model
+{
+ /**
+ * Start the session.
+ *
+ * @access public
+ * @return void
+ */
+ public function startSession()
+ {
+ session_name($this->config->sessionVar);
+ if(isset($_GET[$this->config->sessionVar])) session_id($_GET[$this->config->sessionVar]);
+ session_start();
+ }
+
+ /**
+ * Set the header info.
+ *
+ * @access public
+ * @return void
+ */
+ public function sendHeader()
+ {
+ header("Content-Type: text/html; Language={$this->config->encoding}");
+ header("Cache-control: private");
+ }
+
+ /**
+ * Set the commpany.
+ *
+ * First, search company by the http host. If not found, search by the default domain. Last, use the first as the default.
+ * After get the company, save it to session.
+ * @access public
+ * @return void
+ */
+ public function setCompany()
+ {
+ $httpHost = $this->server->http_host;
+ if(strpos($httpHost, ":"))
+ {
+ $httpHost = explode(":", $httpHost);
+ $httpHost = $httpHost[0];
+ }
+
+ if($this->session->company and $this->session->company->pms == $httpHost)
+ {
+ $this->app->company = $this->session->company;
+ }
+ else
+ {
+ $company = $this->loadModel('company')->getByDomain();
+ if(!$company and isset($this->config->default->domain)) $company = $this->company->getByDomain($this->config->default->domain);
+ if(!$company) $company = $this->company->getFirst();
+ if(!$company) $this->app->error(sprintf($this->lang->error->companyNotFound, $httpHost), __FILE__, __LINE__, $exit = true);
+ $this->session->set('company', $company);
+ $this->app->company = $company;
+ }
+ }
+
+ /**
+ * Set the user info.
+ *
+ * @access public
+ * @return void
+ */
+ public function setUser()
+ {
+ if($this->session->user)
+ {
+ $this->app->user = $this->session->user;
+ }
+ elseif($this->app->company->guest)
+ {
+ $user = new stdClass();
+ $user->id = 0;
+ $user->account = 'guest';
+ $user->realname = 'guest';
+ $user->rights = $this->loadModel('user')->authorize('guest');
+ $this->session->set('user', $user);
+ $this->app->user = $this->session->user;
+ }
+ }
+
+ /**
+ * Juage a method of one module is open or not?
+ *
+ * @param string $module
+ * @param string $method
+ * @access public
+ * @return bool
+ */
+ public function isOpenMethod($module, $method)
+ {
+ if($module == 'user' and strpos('login|logout|deny', $method) !== false) return true;
+ if($module == 'api' and $method == 'getsessionid') return true;
+ if($module == 'misc' and $method == 'about') return true;
+ if($module == 'help' and $method == 'field') return true;
+ return false;
+ }
+
+ /**
+ * Deny access.
+ *
+ * @access public
+ * @return void
+ */
+ public function deny($module, $method)
+ {
+ $vars = "module=$module&method=$method";
+ if(isset($this->server->http_referer))
+ {
+ $referer = helper::safe64Encode($this->server->http_referer);
+ $vars .= "&referer=$referer";
+ }
+ $denyLink = helper::createLink('user', 'deny', $vars);
+
+ /* Fix the bug of IE: use js locate, can't get the referer. */
+ if(strpos($this->server->http_user_agent, 'MSIE') !== false)
+ {
+ echo "deny ";
+ echo "";
+ }
+ else
+ {
+ echo js::locate($denyLink);
+ }
+ exit;
+ }
+
+ /**
+ * Get the run info.
+ *
+ * @param mixed $startTime the start time of this execution
+ * @access public
+ * @return array the run info array.
+ */
+ public function getRunInfo($startTime)
+ {
+ $info['timeUsed'] = round(getTime() - $startTime, 4) * 1000;
+ $info['memory'] = round(memory_get_peak_usage() / 1024, 1);
+ $info['querys'] = count(dao::$querys);
+ return $info;
+ }
+
+ /**
+ * Print top bar.
+ *
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function printTopBar()
+ {
+ global $lang, $app;
+
+ printf($lang->todayIs, date(DT_DATE3));
+ if(isset($app->user)) echo $app->user->realname . ' ';
+ if(isset($app->user) and $app->user->account != 'guest')
+ {
+ echo html::a(helper::createLink('my', 'index'), $lang->myControl);
+ echo html::a(helper::createLink('user', 'logout'), $lang->logout);
+ }
+ else
+ {
+ echo html::a(helper::createLink('user', 'login'), $lang->login);
+ }
+ echo html::a(helper::createLink('misc', 'about'), $lang->aboutZenTao, '', "class='about'");
+ echo $lang->agileTraining;
+ echo $lang->donate;
+ }
+
+ /**
+ * Print the main menu.
+ *
+ * @param string $moduleName
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function printMainmenu($moduleName)
+ {
+ global $app, $lang;
+ echo "\n";
+
+ /* Set the main main menu. */
+ $mainMenu = $moduleName;
+ if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName;
+
+ /* Print all main menus. */
+ foreach($lang->menu as $menuKey => $menu)
+ {
+ $active = $menuKey == $mainMenu ? "class='active'" : '';
+ list($menuLabel, $module, $method) = explode('|', $menu);
+
+ if(common::hasPriv($module, $method))
+ {
+ $link = helper::createLink($module, $method);
+ echo " \n";
+ }
+ }
+
+ }
+
+ /**
+ * Print the search box.
+ *
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function printSearchBox()
+ {
+ global $app, $lang;
+ $moduleName = $app->getModuleName();
+ $methodName = $app->getMethodName();
+ $searchObject = $moduleName;
+
+ if($moduleName == 'product')
+ {
+ if($methodName == 'browse') $searchObject = 'story';
+ }
+ elseif($moduleName == 'project')
+ {
+ if(strpos('task|story|bug|build', $methodName) !== false) $searchObject = $methodName;
+ }
+ elseif($moduleName == 'my' or $moduleName == 'user')
+ {
+ $searchObject = $methodName;
+ }
+
+ echo "";
+ echo html::select('searchType', $lang->searchObjects, $searchObject);
+ echo html::input('searchQuery', $lang->searchTips, "onclick=this.value='' onkeydown='if(event.keyCode==13) shortcut()' class='w-60px'");
+ echo html::commonButton($lang->go, 'id="objectSwitcher" onclick="shortcut()"');
+ echo " ";
+ echo " \n";
+ }
+
+ /**
+ * Print the module menu.
+ *
+ * @param string $moduleName
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function printModuleMenu($moduleName)
+ {
+ global $lang, $app;
+
+ if(!isset($lang->$moduleName->menu)) {echo ""; return;}
+
+ /* Get the sub menus of the module, and get current module and method. */
+ $submenus = $lang->$moduleName->menu;
+ $currentModule = $app->getModuleName();
+ $currentMethod = $app->getMethodName();
+
+ /* The beginning of the menu. */
+ echo "\n";
+
+ /* Cycling to print every sub menus. */
+ foreach($submenus as $subMenuKey => $submenu)
+ {
+ /* Init the these vars. */
+ $link = $submenu;
+ $subModule = '';
+ $alias = '';
+ $float = '';
+ $active = '';
+ $target = '';
+
+ if(is_array($submenu)) extract($submenu); // If the sub menu is an array, extract it.
+
+ /* Print the menu. */
+ if(strpos($link, '|') === false)
+ {
+ echo "$link \n";
+ }
+ else
+ {
+ $link = explode('|', $link);
+ list($label, $module, $method) = $link;
+ $vars = isset($link[3]) ? $link[3] : '';
+ if(common::hasPriv($module, $method))
+ {
+ /* Is the currentModule active? */
+ if($currentModule == $subModule) $active = 'active';
+ if($module == $currentModule and ($method == $currentMethod or strpos($alias, $currentMethod) !== false)) $active = 'active';
+ echo "" . html::a(helper::createLink($module, $method, $vars), $label, $target, "id=submenu$subMenuKey") . " \n";
+ }
+ }
+ }
+ echo " \n";
+ }
+
+ /**
+ * Print the bread menu.
+ *
+ * @param string $moduleName
+ * @param string $position
+ * @static
+ * @access public
+ * @return void
+ */
+ public static function printBreadMenu($moduleName, $position)
+ {
+ global $lang;
+ $mainMenu = $moduleName;
+ if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName;
+ echo html::a(helper::createLink('my', 'index'), $lang->ZenTaoPMS) . $lang->arrow;
+ if($moduleName != 'index')
+ {
+ list($menuLabel, $module, $method) = explode('|', $lang->menu->$mainMenu);
+ echo html::a(helper::createLink($module, $method), $menuLabel);
+ }
+ else
+ {
+ echo $lang->index->common;
+ }
+ if(empty($position)) return;
+ echo $lang->arrow;
+ foreach($position as $key => $link)
+ {
+ echo $link;
+ if(isset($position[$key + 1])) echo $lang->arrow;
+ }
+ }
+
+
+ /**
+ * Diff two string. (see phpt)
+ *
+ * @param string $text1
+ * @param string $text2
+ * @static
+ * @access public
+ * @return string
+ */
+ public static function diff($text1, $text2)
+ {
+ $text1 = str_replace(' ', '', trim($text1));
+ $text2 = str_replace(' ', '', trim($text2));
+ $w = explode("\n", $text1);
+ $o = explode("\n", $text2);
+ $w1 = array_diff_assoc($w,$o);
+ $o1 = array_diff_assoc($o,$w);
+ $w2 = array();
+ $o2 = array();
+ foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1) . "" . trim($val) . "";
+ foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1) . "" . trim($val) . " ";
+ $diff = array_merge($w2, $o2);
+ ksort($diff);
+ return implode("\n", $diff);
+ }
+}
diff --git a/module/company/control.php b/module/company/control.php
index b06dbf33f0..95a21cc407 100644
--- a/module/company/control.php
+++ b/module/company/control.php
@@ -1,236 +1,236 @@
-
- * @package company
- * @version $Id$
- * @link http://www.zentao.net
- */
-class company extends control
-{
- /**
- * Construct function, load dept and user models auto.
- *
- * @access public
- * @return void
- */
- public function __construct()
- {
- parent::__construct();
- $this->loadModel('dept');
- $this->app->loadLang('user');
- $this->company->setMenu();
- }
-
- /**
- * Index page, header to browse.
- *
- * @access public
- * @return void
- */
- public function index()
- {
- $this->locate($this->createLink('company', 'browse'));
- }
-
- /**
- * Browse departments and users of a company.
- *
- * @param int $deptID
- * @access public
- * @return void
- */
- public function browse($deptID = 0)
- {
- $this->lang->set('menugroup.company', 'company');
- $childDeptIds = $this->dept->getAllChildID($deptID);
-
- $this->company->setMenu($deptID);
-
- $header['title'] = $this->lang->company->index . $this->lang->colon . $this->lang->dept->common;
- $position[] = $this->lang->dept->common;
-
- $this->view->header = $header;
- $this->view->position = $position;
- $this->view->users = $this->dept->getUsers($childDeptIds);
- $this->view->deptTree = $this->dept->getTreeMenu($rooteDeptID = 0, array('deptModel', 'createMemberLink'));
- $this->view->parentDepts = $this->dept->getParents($deptID);
- $this->view->deptID = $deptID;
-
- $this->display();
- }
-
- /**
- * Create a company.
- *
- * @access public
- * @return void
- */
- public function create()
- {
- if(!empty($_POST))
- {
- $this->company->create();
- if(dao::isError()) die(js::error(dao::getError()));
- die(js::locate($this->createLink('admin', 'browsecompany'), 'parent'));
- }
-
- $this->lang->set('menugroup.company', 'admin');
- $this->lang->company->menu = $this->lang->admin->menu;
-
- $header['title'] = $this->lang->admin->common . $this->lang->colon . $this->lang->company->create;
- $position[] = html::a($this->createLink('admin', 'browsecompany'), $this->lang->admin->company);
- $position[] = $this->lang->company->create;
- $this->view->header = $header;
- $this->view->position = $position;
-
- $this->display();
- }
-
- /**
- * Edit a company.
- *
- * @access public
- * @return void
- */
- public function edit()
- {
- if(!empty($_POST))
- {
- $this->company->update();
- if(dao::isError()) die(js::error(dao::getError()));
- die(js::alert($this->lang->company->successSaved));
- }
-
- $header['title'] = $this->lang->company->common . $this->lang->colon . $this->lang->company->edit;
- $position[] = $this->lang->company->edit;
- $this->view->header = $header;
- $this->view->position = $position;
- $this->view->company = $this->company->getById($this->app->company->id);
-
- $this->display();
- }
-
- /**
- * Delete a company.
- *
- * @param int $companyID
- * @param string $confirm yes|no
- * @access public
- * @return void
- */
- public function delete($companyID, $confirm = 'no')
- {
- if($confirm == 'no')
- {
- echo js::confirm($this->lang->company->confirmDelete, $this->createLink('company', 'delete', "companyID=$companyID&confirm=yes"));
- exit;
- }
- else
- {
- $this->company->delete($companyID);
- echo js::locate($this->createLink('admin', 'browseCompany'), 'parent');
- exit;
- }
- }
-
- /**
- * Company dynamic.
- *
- * @param string $browseType
- * @param string $orderBy
- * @param int $recTotal
- * @param int $recPerPage
- * @param int $pageID
- * @access public
- * @return void
- */
- public function dynamic($browseType = 'today', $param = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
- {
- $this->app->loadLang('user');
- $this->app->loadLang('project');
- $this->loadModel('action');
-
- /* Save session. */
- $uri = $this->app->getURI(true);
- $this->session->set('productList', $uri);
- $this->session->set('productPlanList', $uri);
- $this->session->set('releaseList', $uri);
- $this->session->set('storyList', $uri);
- $this->session->set('projectList', $uri);
- $this->session->set('taskList', $uri);
- $this->session->set('buildList', $uri);
- $this->session->set('bugList', $uri);
- $this->session->set('caseList', $uri);
- $this->session->set('testtaskList', $uri);
-
- /* Set the pager. */
- $this->app->loadClass('pager', $static = true);
- $pager = pager::init($recTotal, $recPerPage, $pageID);
- $this->view->orderBy = $orderBy;
- $this->view->pager = $pager;
-
- /* Set the user and type. */
- $account = $browseType == 'account' ? $param : 'all';
- $product = $browseType == 'product' ? $param : 'all';
- $project = $browseType == 'project' ? $param : 'all';
- $period = ($browseType == 'account' or $browseType == 'product' or $browseType == 'project') ? 'all' : $browseType;
- $queryID = ($browseType == 'bysearch') ? (int)$param : 0;
-
- /* Get products' list.*/
- $products = $this->loadModel('product')->getPairs();
- $products = array($this->lang->product->select) + $products;
- $this->view->products = $products;
-
- /* Get projects' list.*/
- $projects = $this->loadModel('project')->getPairs();
- $projects = array($this->lang->project->select) + $projects;
- $this->view->projects = $projects;
-
- /* Get users.*/
- $users = $this->loadModel('user')->getPairs('nodeleted|noletter|noclosed');
- $users[''] = $this->lang->user->select;
- $this->view->users = $users;
-
- /* The header and position. */
- $this->view->header->title = $this->lang->company->common . $this->lang->colon . $this->lang->company->dynamic;
- $this->view->position[] = $this->lang->company->dynamic;
-
- /* Get actions. */
- if($browseType != 'bysearch')
- {
- $actions = $this->action->getDynamic($account, $period, $orderBy, $pager, $product, $project);
- }
- else
- {
- $actions = $this->action->getDynamicBySearch($products, $projects, $queryID, $orderBy, $pager);
- }
-
- /* Build search form. */
- $projects[0] = '';
- $products[0] = '';
- $users[''] = '';
- ksort($projects);
- ksort($products);
- $projects['all'] = $this->lang->project->allProject;
- $products['all'] = $this->lang->product->allProduct;
- $this->config->company->dynamic->search['actionURL'] = $this->createLink('company', 'dynamic', "browseType=bysearch¶m=myQueryID");
- $this->config->company->dynamic->search['queryID'] = $queryID;
- $this->config->company->dynamic->search['params']['project']['values'] = $projects;
- $this->config->company->dynamic->search['params']['product']['values'] = $products;
- $this->config->company->dynamic->search['params']['actor']['values'] = $users;
- $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->company->dynamic->search);
-
- /* Assign. */
- $this->view->browseType = $browseType;
- $this->view->account = $account;
- $this->view->product = $product;
- $this->view->project = $project;
- $this->view->queryID = $queryID;
- $this->view->actions = $actions;
- $this->display();
- }
-}
+
+ * @package company
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class company extends control
+{
+ /**
+ * Construct function, load dept and user models auto.
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->loadModel('dept');
+ $this->app->loadLang('user');
+ $this->company->setMenu();
+ }
+
+ /**
+ * Index page, header to browse.
+ *
+ * @access public
+ * @return void
+ */
+ public function index()
+ {
+ $this->locate($this->createLink('company', 'browse'));
+ }
+
+ /**
+ * Browse departments and users of a company.
+ *
+ * @param int $deptID
+ * @access public
+ * @return void
+ */
+ public function browse($deptID = 0)
+ {
+ $this->lang->set('menugroup.company', 'company');
+ $childDeptIds = $this->dept->getAllChildID($deptID);
+
+ $this->company->setMenu($deptID);
+
+ $header['title'] = $this->lang->company->index . $this->lang->colon . $this->lang->dept->common;
+ $position[] = $this->lang->dept->common;
+
+ $this->view->header = $header;
+ $this->view->position = $position;
+ $this->view->users = $this->dept->getUsers($childDeptIds);
+ $this->view->deptTree = $this->dept->getTreeMenu($rooteDeptID = 0, array('deptModel', 'createMemberLink'));
+ $this->view->parentDepts = $this->dept->getParents($deptID);
+ $this->view->deptID = $deptID;
+
+ $this->display();
+ }
+
+ /**
+ * Create a company.
+ *
+ * @access public
+ * @return void
+ */
+ public function create()
+ {
+ if(!empty($_POST))
+ {
+ $this->company->create();
+ if(dao::isError()) die(js::error(dao::getError()));
+ die(js::locate($this->createLink('admin', 'browsecompany'), 'parent'));
+ }
+
+ $this->lang->set('menugroup.company', 'admin');
+ $this->lang->company->menu = $this->lang->admin->menu;
+
+ $header['title'] = $this->lang->admin->common . $this->lang->colon . $this->lang->company->create;
+ $position[] = html::a($this->createLink('admin', 'browsecompany'), $this->lang->admin->company);
+ $position[] = $this->lang->company->create;
+ $this->view->header = $header;
+ $this->view->position = $position;
+
+ $this->display();
+ }
+
+ /**
+ * Edit a company.
+ *
+ * @access public
+ * @return void
+ */
+ public function edit()
+ {
+ if(!empty($_POST))
+ {
+ $this->company->update();
+ if(dao::isError()) die(js::error(dao::getError()));
+ die(js::alert($this->lang->company->successSaved));
+ }
+
+ $header['title'] = $this->lang->company->common . $this->lang->colon . $this->lang->company->edit;
+ $position[] = $this->lang->company->edit;
+ $this->view->header = $header;
+ $this->view->position = $position;
+ $this->view->company = $this->company->getById($this->app->company->id);
+
+ $this->display();
+ }
+
+ /**
+ * Delete a company.
+ *
+ * @param int $companyID
+ * @param string $confirm yes|no
+ * @access public
+ * @return void
+ */
+ public function delete($companyID, $confirm = 'no')
+ {
+ if($confirm == 'no')
+ {
+ echo js::confirm($this->lang->company->confirmDelete, $this->createLink('company', 'delete', "companyID=$companyID&confirm=yes"));
+ exit;
+ }
+ else
+ {
+ $this->company->delete($companyID);
+ echo js::locate($this->createLink('admin', 'browseCompany'), 'parent');
+ exit;
+ }
+ }
+
+ /**
+ * Company dynamic.
+ *
+ * @param string $browseType
+ * @param string $orderBy
+ * @param int $recTotal
+ * @param int $recPerPage
+ * @param int $pageID
+ * @access public
+ * @return void
+ */
+ public function dynamic($browseType = 'today', $param = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
+ {
+ $this->app->loadLang('user');
+ $this->app->loadLang('project');
+ $this->loadModel('action');
+
+ /* Save session. */
+ $uri = $this->app->getURI(true);
+ $this->session->set('productList', $uri);
+ $this->session->set('productPlanList', $uri);
+ $this->session->set('releaseList', $uri);
+ $this->session->set('storyList', $uri);
+ $this->session->set('projectList', $uri);
+ $this->session->set('taskList', $uri);
+ $this->session->set('buildList', $uri);
+ $this->session->set('bugList', $uri);
+ $this->session->set('caseList', $uri);
+ $this->session->set('testtaskList', $uri);
+
+ /* Set the pager. */
+ $this->app->loadClass('pager', $static = true);
+ $pager = pager::init($recTotal, $recPerPage, $pageID);
+ $this->view->orderBy = $orderBy;
+ $this->view->pager = $pager;
+
+ /* Set the user and type. */
+ $account = $browseType == 'account' ? $param : 'all';
+ $product = $browseType == 'product' ? $param : 'all';
+ $project = $browseType == 'project' ? $param : 'all';
+ $period = ($browseType == 'account' or $browseType == 'product' or $browseType == 'project') ? 'all' : $browseType;
+ $queryID = ($browseType == 'bysearch') ? (int)$param : 0;
+
+ /* Get products' list.*/
+ $products = $this->loadModel('product')->getPairs();
+ $products = array($this->lang->product->select) + $products;
+ $this->view->products = $products;
+
+ /* Get projects' list.*/
+ $projects = $this->loadModel('project')->getPairs();
+ $projects = array($this->lang->project->select) + $projects;
+ $this->view->projects = $projects;
+
+ /* Get users.*/
+ $users = $this->loadModel('user')->getPairs('nodeleted|noletter|noclosed');
+ $users[''] = $this->lang->user->select;
+ $this->view->users = $users;
+
+ /* The header and position. */
+ $this->view->header->title = $this->lang->company->common . $this->lang->colon . $this->lang->company->dynamic;
+ $this->view->position[] = $this->lang->company->dynamic;
+
+ /* Get actions. */
+ if($browseType != 'bysearch')
+ {
+ $actions = $this->action->getDynamic($account, $period, $orderBy, $pager, $product, $project);
+ }
+ else
+ {
+ $actions = $this->action->getDynamicBySearch($products, $projects, $queryID, $orderBy, $pager);
+ }
+
+ /* Build search form. */
+ $projects[0] = '';
+ $products[0] = '';
+ $users[''] = '';
+ ksort($projects);
+ ksort($products);
+ $projects['all'] = $this->lang->project->allProject;
+ $products['all'] = $this->lang->product->allProduct;
+ $this->config->company->dynamic->search['actionURL'] = $this->createLink('company', 'dynamic', "browseType=bysearch¶m=myQueryID");
+ $this->config->company->dynamic->search['queryID'] = $queryID;
+ $this->config->company->dynamic->search['params']['project']['values'] = $projects;
+ $this->config->company->dynamic->search['params']['product']['values'] = $products;
+ $this->config->company->dynamic->search['params']['actor']['values'] = $users;
+ $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->company->dynamic->search);
+
+ /* Assign. */
+ $this->view->browseType = $browseType;
+ $this->view->account = $account;
+ $this->view->product = $product;
+ $this->view->project = $project;
+ $this->view->queryID = $queryID;
+ $this->view->actions = $actions;
+ $this->display();
+ }
+}
diff --git a/module/company/lang/en.php b/module/company/lang/en.php
index c6c9c03433..8f06fc3b8f 100644
--- a/module/company/lang/en.php
+++ b/module/company/lang/en.php
@@ -1,39 +1,39 @@
-
- * @package company
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->company->common = 'Company';
-$lang->company->index = "Index";
-$lang->company->create = "Create";
-$lang->company->edit = "Edit";
-$lang->company->read = "Info";
-$lang->company->update = "Update";
-$lang->company->delete = "Delete";
-$lang->company->browse = "User";
-$lang->company->dynamic = "Dynamic";
-$lang->company->depts = "Dept";
-$lang->company->orgView = 'Company';
-
-$lang->company->confirmDelete = "Are you sure to delete this company?";
-$lang->company->successSaved = "Success saved";
-
-$lang->company->id = 'ID';
-$lang->company->name = 'Name';
-$lang->company->phone = 'Phone';
-$lang->company->fax = 'Fax';
-$lang->company->address = 'Address';
-$lang->company->zipcode = 'Zipcode';
-$lang->company->website = 'Web site';
-$lang->company->backyard = 'Internal Site';
-$lang->company->pms = 'ZenTaoPMS Site';
-$lang->company->guest = 'Guest visit';
-
-$lang->company->guestList[0] = 'Deny';
-$lang->company->guestList[1] = 'Allow';
+
+ * @package company
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->company->common = 'Company';
+$lang->company->index = "Index";
+$lang->company->create = "Create";
+$lang->company->edit = "Edit";
+$lang->company->read = "Info";
+$lang->company->update = "Update";
+$lang->company->delete = "Delete";
+$lang->company->browse = "User";
+$lang->company->dynamic = "Dynamic";
+$lang->company->depts = "Dept";
+$lang->company->orgView = 'Company';
+
+$lang->company->confirmDelete = "Are you sure to delete this company?";
+$lang->company->successSaved = "Success saved";
+
+$lang->company->id = 'ID';
+$lang->company->name = 'Name';
+$lang->company->phone = 'Phone';
+$lang->company->fax = 'Fax';
+$lang->company->address = 'Address';
+$lang->company->zipcode = 'Zipcode';
+$lang->company->website = 'Web site';
+$lang->company->backyard = 'Internal Site';
+$lang->company->pms = 'ZenTaoPMS Site';
+$lang->company->guest = 'Guest visit';
+
+$lang->company->guestList[0] = 'Deny';
+$lang->company->guestList[1] = 'Allow';
diff --git a/module/company/lang/zh-cn.php b/module/company/lang/zh-cn.php
index ae937f1c60..19e2b7c517 100644
--- a/module/company/lang/zh-cn.php
+++ b/module/company/lang/zh-cn.php
@@ -1,39 +1,39 @@
-
- * @package company
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->company->common = '组织视图';
-$lang->company->index = "组织视图首页";
-$lang->company->create = "新增公司";
-$lang->company->edit = "编辑公司";
-$lang->company->read = "公司信息";
-$lang->company->update = "更新公司";
-$lang->company->delete = "删除公司";
-$lang->company->browse = "用户列表";
-$lang->company->dynamic = "组织动态";
-$lang->company->depts = "部门列表";
-$lang->company->orgView = '组织视图';
-
-$lang->company->confirmDelete = "您确定删除该公司吗?";
-$lang->company->successSaved = "成功保存";
-
-$lang->company->id = '编号';
-$lang->company->name = '公司名称';
-$lang->company->phone = '联系电话';
-$lang->company->fax = '传真';
-$lang->company->address = '通讯地址';
-$lang->company->zipcode = '邮政编码';
-$lang->company->website = '公司网站';
-$lang->company->backyard = '公司内网';
-$lang->company->pms = 'PMS网站';
-$lang->company->guest = '匿名登录';
-
-$lang->company->guestList[0] = '不允许';
-$lang->company->guestList[1] = '允许';
+
+ * @package company
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->company->common = '组织视图';
+$lang->company->index = "组织视图首页";
+$lang->company->create = "新增公司";
+$lang->company->edit = "编辑公司";
+$lang->company->read = "公司信息";
+$lang->company->update = "更新公司";
+$lang->company->delete = "删除公司";
+$lang->company->browse = "用户列表";
+$lang->company->dynamic = "组织动态";
+$lang->company->depts = "部门列表";
+$lang->company->orgView = '组织视图';
+
+$lang->company->confirmDelete = "您确定删除该公司吗?";
+$lang->company->successSaved = "成功保存";
+
+$lang->company->id = '编号';
+$lang->company->name = '公司名称';
+$lang->company->phone = '联系电话';
+$lang->company->fax = '传真';
+$lang->company->address = '通讯地址';
+$lang->company->zipcode = '邮政编码';
+$lang->company->website = '公司网站';
+$lang->company->backyard = '公司内网';
+$lang->company->pms = 'PMS网站';
+$lang->company->guest = '匿名登录';
+
+$lang->company->guestList[0] = '不允许';
+$lang->company->guestList[1] = '允许';
diff --git a/module/company/lang/zh-tw.php b/module/company/lang/zh-tw.php
index 2e378dae39..e9826c8519 100644
--- a/module/company/lang/zh-tw.php
+++ b/module/company/lang/zh-tw.php
@@ -1,39 +1,39 @@
-
- * @package company
- * @version $Id: zh-tw.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $
- * @link http://www.zentao.net
- */
-$lang->company->common = '組織視圖';
-$lang->company->index = "組織視圖首頁";
-$lang->company->create = "新增公司";
-$lang->company->edit = "編輯公司";
-$lang->company->read = "公司信息";
-$lang->company->update = "更新公司";
-$lang->company->delete = "刪除公司";
-$lang->company->browse = "用戶列表";
-$lang->company->dynamic = "組織動態";
-$lang->company->depts = "部門列表";
-$lang->company->orgView = '組織視圖';
-
-$lang->company->confirmDelete = "您確定刪除該公司嗎?";
-$lang->company->successSaved = "成功保存";
-
-$lang->company->id = '編號';
-$lang->company->name = '公司名稱';
-$lang->company->phone = '聯繫電話';
-$lang->company->fax = '傳真';
-$lang->company->address = '通訊地址';
-$lang->company->zipcode = '郵政編碼';
-$lang->company->website = '公司網站';
-$lang->company->backyard = '公司內網';
-$lang->company->pms = 'PMS網站';
-$lang->company->guest = '匿名登錄';
-
-$lang->company->guestList[0] = '不允許';
-$lang->company->guestList[1] = '允許';
+
+ * @package company
+ * @version $Id: zh-tw.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $
+ * @link http://www.zentao.net
+ */
+$lang->company->common = '組織視圖';
+$lang->company->index = "組織視圖首頁";
+$lang->company->create = "新增公司";
+$lang->company->edit = "編輯公司";
+$lang->company->read = "公司信息";
+$lang->company->update = "更新公司";
+$lang->company->delete = "刪除公司";
+$lang->company->browse = "用戶列表";
+$lang->company->dynamic = "組織動態";
+$lang->company->depts = "部門列表";
+$lang->company->orgView = '組織視圖';
+
+$lang->company->confirmDelete = "您確定刪除該公司嗎?";
+$lang->company->successSaved = "成功保存";
+
+$lang->company->id = '編號';
+$lang->company->name = '公司名稱';
+$lang->company->phone = '聯繫電話';
+$lang->company->fax = '傳真';
+$lang->company->address = '通訊地址';
+$lang->company->zipcode = '郵政編碼';
+$lang->company->website = '公司網站';
+$lang->company->backyard = '公司內網';
+$lang->company->pms = 'PMS網站';
+$lang->company->guest = '匿名登錄';
+
+$lang->company->guestList[0] = '不允許';
+$lang->company->guestList[1] = '允許';
diff --git a/module/company/model.php b/module/company/model.php
index 16e668886b..edb774aa87 100644
--- a/module/company/model.php
+++ b/module/company/model.php
@@ -1,123 +1,123 @@
-
- * @package company
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-lang->company->menu, 'name', array($this->app->company->name));
- common::setMenuVars($this->lang->company->menu, 'addUser', array($dept));
- }
-
- /**
- * Get company list.
- *
- * @access public
- * @return void
- */
- public function getList()
- {
- return $this->dao->select('*')->from(TABLE_COMPANY)->fetchAll();
- }
-
- /**
- * Get the first company.
- *
- * @access public
- * @return void
- */
- public function getFirst()
- {
- return $this->dao->select('*')->from(TABLE_COMPANY)->orderBy('id')->limit(1)->fetch();
- }
-
- /**
- * get company by domain.
- *
- * @param string $domain if empty, use current HTTP_HOST.
- * @access public
- * @return object
- */
- public function getByDomain($domain = '')
- {
- if(empty($domain)) $domain = $this->server->http_host;
- return $this->dao->findByPMS($domain)->from(TABLE_COMPANY)->fetch();
- }
-
- /**
- * Get company info by id.
- *
- * @param int $companyID
- * @access public
- * @return object
- */
- public function getByID($companyID = '')
- {
- return $this->dao->findById((int)$companyID)->from(TABLE_COMPANY)->fetch();
- }
-
- /**
- * Create a company.
- *
- * @access public
- * @return void
- */
- public function create()
- {
- $company = fixer::input('post')->get();
- $this->dao->insert(TABLE_COMPANY)
- ->data($company)
- ->autoCheck()
- ->batchCheck($this->config->company->create->requiredFields, 'notempty')
- ->batchCheck('name,pms', 'unique')
- ->exec();
- }
-
- /**
- * Update a company.
- *
- * @access public
- * @return void
- */
- public function update()
- {
- $company = fixer::input('post')->stripTags('name')->get();
- $companyID = $this->app->company->id;
- $this->dao->update(TABLE_COMPANY)
- ->data($company)
- ->autoCheck()
- ->batchCheck($this->config->company->edit->requiredFields, 'notempty')
- ->batchCheck('name,pms', 'unique', "id != '$companyID'")
- ->where('id')->eq($companyID)
- ->exec();
- }
-
- /**
- * Delete a company.
- *
- * @param int $companyID
- * @access public
- * @return void
- */
- public function delete($companyID)
- {
- return $this->dao->delete()->from(TABLE_COMPANY)->where('id')->eq((int)$companyID)->limit(1)->exec();
- }
-}
+
+ * @package company
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+lang->company->menu, 'name', array($this->app->company->name));
+ common::setMenuVars($this->lang->company->menu, 'addUser', array($dept));
+ }
+
+ /**
+ * Get company list.
+ *
+ * @access public
+ * @return void
+ */
+ public function getList()
+ {
+ return $this->dao->select('*')->from(TABLE_COMPANY)->fetchAll();
+ }
+
+ /**
+ * Get the first company.
+ *
+ * @access public
+ * @return void
+ */
+ public function getFirst()
+ {
+ return $this->dao->select('*')->from(TABLE_COMPANY)->orderBy('id')->limit(1)->fetch();
+ }
+
+ /**
+ * get company by domain.
+ *
+ * @param string $domain if empty, use current HTTP_HOST.
+ * @access public
+ * @return object
+ */
+ public function getByDomain($domain = '')
+ {
+ if(empty($domain)) $domain = $this->server->http_host;
+ return $this->dao->findByPMS($domain)->from(TABLE_COMPANY)->fetch();
+ }
+
+ /**
+ * Get company info by id.
+ *
+ * @param int $companyID
+ * @access public
+ * @return object
+ */
+ public function getByID($companyID = '')
+ {
+ return $this->dao->findById((int)$companyID)->from(TABLE_COMPANY)->fetch();
+ }
+
+ /**
+ * Create a company.
+ *
+ * @access public
+ * @return void
+ */
+ public function create()
+ {
+ $company = fixer::input('post')->get();
+ $this->dao->insert(TABLE_COMPANY)
+ ->data($company)
+ ->autoCheck()
+ ->batchCheck($this->config->company->create->requiredFields, 'notempty')
+ ->batchCheck('name,pms', 'unique')
+ ->exec();
+ }
+
+ /**
+ * Update a company.
+ *
+ * @access public
+ * @return void
+ */
+ public function update()
+ {
+ $company = fixer::input('post')->stripTags('name')->get();
+ $companyID = $this->app->company->id;
+ $this->dao->update(TABLE_COMPANY)
+ ->data($company)
+ ->autoCheck()
+ ->batchCheck($this->config->company->edit->requiredFields, 'notempty')
+ ->batchCheck('name,pms', 'unique', "id != '$companyID'")
+ ->where('id')->eq($companyID)
+ ->exec();
+ }
+
+ /**
+ * Delete a company.
+ *
+ * @param int $companyID
+ * @access public
+ * @return void
+ */
+ public function delete($companyID)
+ {
+ return $this->dao->delete()->from(TABLE_COMPANY)->where('id')->eq((int)$companyID)->limit(1)->exec();
+ }
+}
diff --git a/module/company/view/browse.html.php b/module/company/view/browse.html.php
index 6a721cffdd..7598007955 100644
--- a/module/company/view/browse.html.php
+++ b/module/company/view/browse.html.php
@@ -1,78 +1,78 @@
-
- * @package product
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
-
- dept->common;?>
-
-
-
- user->create);echo ' ';
- common::printLink('company', 'browse', '', $lang->user->allUsers); echo ' ';
- common::printLink('dept', 'browse', '', $lang->dept->manage);
- ?>
-
-
-
-
-
-
-
-
- idAB;?>
- user->realname;?>
- user->account;?>
- user->nickname;?>
- user->email;?>
- user->gender;?>
- user->phone;?>
- user->join;?>
- user->last;?>
- user->visits;?>
- actions;?>
-
-
-
-
-
- id;?>
- account", $user->realname)) echo $user->realname;?>
- account;?>
- nickname;?>
- email);?>
- user->genderList->{$user->gender})) echo $lang->user->genderList->{$user->gender};?>
- phone;?>
- join;?>
- last);?>
- visits;?>
-
- id&from=company", $lang->edit);
- common::printLink('user', 'delete', "userID=$user->id", $lang->delete, "hiddenwin");
- ?>
-
-
-
-
-
-
-
-
-
-
+
+ * @package product
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+ dept->common;?>
+
+
+
+ user->create);echo ' ';
+ common::printLink('company', 'browse', '', $lang->user->allUsers); echo ' ';
+ common::printLink('dept', 'browse', '', $lang->dept->manage);
+ ?>
+
+
+
+
+
+
+
+
+ idAB;?>
+ user->realname;?>
+ user->account;?>
+ user->nickname;?>
+ user->email;?>
+ user->gender;?>
+ user->phone;?>
+ user->join;?>
+ user->last;?>
+ user->visits;?>
+ actions;?>
+
+
+
+
+
+ id;?>
+ account", $user->realname)) echo $user->realname;?>
+ account;?>
+ nickname;?>
+ email);?>
+ user->genderList->{$user->gender})) echo $lang->user->genderList->{$user->gender};?>
+ phone;?>
+ join;?>
+ last);?>
+ visits;?>
+
+ id&from=company", $lang->edit);
+ common::printLink('user', 'delete', "userID=$user->id", $lang->delete, "hiddenwin");
+ ?>
+
+
+
+
+
+
+
+
+
+
diff --git a/module/company/view/create.html.php b/module/company/view/create.html.php
index 6ed0a65c04..148be8dbac 100644
--- a/module/company/view/create.html.php
+++ b/module/company/view/create.html.php
@@ -1,56 +1,56 @@
-
- * @package company
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
- company->create;?>
-
- company->name;?>
-
-
-
- company->phone;?>
-
-
-
- company->fax;?>
-
-
-
- company->address;?>
-
-
-
- company->zipcode;?>
-
-
-
- company->website;?>
-
-
-
- company->backyard;?>
-
-
-
- company->pms;?>
-
-
-
- company->guest;?>
- company->guestList);?>
-
-
-
-
-
+
+ * @package company
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+ company->create;?>
+
+ company->name;?>
+
+
+
+ company->phone;?>
+
+
+
+ company->fax;?>
+
+
+
+ company->address;?>
+
+
+
+ company->zipcode;?>
+
+
+
+ company->website;?>
+
+
+
+ company->backyard;?>
+
+
+
+ company->pms;?>
+
+
+
+ company->guest;?>
+ company->guestList);?>
+
+
+
+
+
diff --git a/module/company/view/dynamic.html.php b/module/company/view/dynamic.html.php
index 59fb4f5d94..357b684648 100644
--- a/module/company/view/dynamic.html.php
+++ b/module/company/view/dynamic.html.php
@@ -1,62 +1,62 @@
-dynamic view file of dashboard module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2011 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
- * @license LGPL (http://www.gnu.org/licenses/lgpl.html)
- * @author Chunsheng Wang
- * @package dashboard
- * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $
- * @link http://www.zentao.net
- */
-?>
-
-
-
-
- ' . html::a(inlink('dynamic', "browseType=today"), $lang->action->dynamic->today) . '';
- echo '' . html::a(inlink('dynamic', "browseType=yesterday"), $lang->action->dynamic->yesterday) . ' ';
- echo '' . html::a(inlink('dynamic', "browseType=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ' ';
- echo '' . html::a(inlink('dynamic', "browseType=thisweek"), $lang->action->dynamic->thisWeek) . ' ';
- echo '' . html::a(inlink('dynamic', "browseType=lastweek"), $lang->action->dynamic->lastWeek) . ' ';
- echo '' . html::a(inlink('dynamic', "browseType=thismonth"), $lang->action->dynamic->thisMonth) . ' ';
- echo '' . html::a(inlink('dynamic', "browseType=lastmonth"), $lang->action->dynamic->lastMonth) . ' ';
- echo '' . html::a(inlink('dynamic', "browseType=all"), $lang->action->dynamic->all) . ' ';
- echo "" . html::select('account', $users, $account, 'onchange=changeUser(this.value)') . ' ';
- echo "" . html::select('product', $products, $product, 'onchange=changeProduct(this.value)') . ' ';
- echo "" . html::select('project', $projects, $project, 'onchange=changeProject(this.value)') . ' ';
- echo "" . html::a('#', $lang->action->dynamic->search) . " ";
- ?>
-
-'>
-
-
-
- action->date;?>
- action->actor;?>
- action->action;?>
- action->objectType;?>
- idAB;?>
- action->objectName;?>
-
-
-
-
- objectType == 'case' ? 'testcase' : $action->objectType;?>
-
- date;?>
- actor]) ? print($users[$action->actor]) : print($action->actor);?>
- actionLabel;?>
- action->objectTypes[$action->objectType];?>
- objectID;?>
- objectLink, $action->objectName);?>
-
-
-
- show();?>
-
-
-
+dynamic view file of dashboard module of ZenTaoPMS.
+ *
+ * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
+ * @license LGPL (http://www.gnu.org/licenses/lgpl.html)
+ * @author Chunsheng Wang
+ * @package dashboard
+ * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+ ' . html::a(inlink('dynamic', "browseType=today"), $lang->action->dynamic->today) . '';
+ echo '' . html::a(inlink('dynamic', "browseType=yesterday"), $lang->action->dynamic->yesterday) . ' ';
+ echo '' . html::a(inlink('dynamic', "browseType=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ' ';
+ echo '' . html::a(inlink('dynamic', "browseType=thisweek"), $lang->action->dynamic->thisWeek) . ' ';
+ echo '' . html::a(inlink('dynamic', "browseType=lastweek"), $lang->action->dynamic->lastWeek) . ' ';
+ echo '' . html::a(inlink('dynamic', "browseType=thismonth"), $lang->action->dynamic->thisMonth) . ' ';
+ echo '' . html::a(inlink('dynamic', "browseType=lastmonth"), $lang->action->dynamic->lastMonth) . ' ';
+ echo '' . html::a(inlink('dynamic', "browseType=all"), $lang->action->dynamic->all) . ' ';
+ echo "" . html::select('account', $users, $account, 'onchange=changeUser(this.value)') . ' ';
+ echo "" . html::select('product', $products, $product, 'onchange=changeProduct(this.value)') . ' ';
+ echo "" . html::select('project', $projects, $project, 'onchange=changeProject(this.value)') . ' ';
+ echo "" . html::a('#', $lang->action->dynamic->search) . " ";
+ ?>
+
+'>
+
+
+
+ action->date;?>
+ action->actor;?>
+ action->action;?>
+ action->objectType;?>
+ idAB;?>
+ action->objectName;?>
+
+
+
+
+ objectType == 'case' ? 'testcase' : $action->objectType;?>
+
+ date;?>
+ actor]) ? print($users[$action->actor]) : print($action->actor);?>
+ actionLabel;?>
+ action->objectTypes[$action->objectType];?>
+ objectID;?>
+ objectLink, $action->objectName);?>
+
+
+
+ show();?>
+
+
+
diff --git a/module/company/view/edit.html.php b/module/company/view/edit.html.php
index 882bc29160..34ccc07bd6 100644
--- a/module/company/view/edit.html.php
+++ b/module/company/view/edit.html.php
@@ -1,56 +1,56 @@
-
- * @package company
- * @version $Id$
- * @link http://www.zentao.net
- */
-?>
-
-
-
- company->edit;?>
-
- company->name;?>
- name, "class='text-1'");?>
-
-
- company->phone;?>
- phone, "class='text-1'");?>
-
-
- company->fax;?>
- fax, "class='text-1'");?>
-
-
- company->address;?>
- address, "class='text-1'");?>
-
-
- company->zipcode;?>
- zipcode, "class='text-1'");?>
-
-
- company->website;?>
- website, "class='text-1'");?>
-
-
- company->backyard;?>
- backyard, "class='text-1'");?>
-
-
- company->pms;?>
- pms, "class='text-1'");?>
-
-
- company->guest;?>
- company->guestList, $company->guest);?>
-
-
-
-
-
+
+ * @package company
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+ company->edit;?>
+
+ company->name;?>
+ name, "class='text-1'");?>
+
+
+ company->phone;?>
+ phone, "class='text-1'");?>
+
+
+ company->fax;?>
+ fax, "class='text-1'");?>
+
+
+ company->address;?>
+ address, "class='text-1'");?>
+
+
+ company->zipcode;?>
+ zipcode, "class='text-1'");?>
+
+
+ company->website;?>
+ website, "class='text-1'");?>
+
+
+ company->backyard;?>
+ backyard, "class='text-1'");?>
+
+
+ company->pms;?>
+ pms, "class='text-1'");?>
+
+
+ company->guest;?>
+ company->guestList, $company->guest);?>
+
+
+
+
+
diff --git a/module/convert/control.php b/module/convert/control.php
index f75a298720..af46236284 100644
--- a/module/convert/control.php
+++ b/module/convert/control.php
@@ -1,240 +1,240 @@
-
- * @package convert
- * @version $Id$
- * @link http://www.zentao.net
- */
-class convert extends control
-{
- /**
- * Index page of convert.
- *
- * @access public
- * @return void
- */
- public function index()
- {
- $this->convert->saveState();
- $this->view->header->title = $this->lang->convert->common;
- $this->display();
- }
-
- /**
- * Select the source system.
- *
- * @access public
- * @return void
- */
- public function selectSource()
- {
- $this->view->header->title = $this->lang->convert->common . $this->lang->colon;
- $this->display();
- }
-
- /**
- * Set configs of converter.
- *
- * This is the extrance of every system. It will call the set function of corresponding module.
- *
- * @access public
- * @return void
- */
- public function setConfig()
- {
- if(!$this->post->source)
- {
- echo js::alert($this->lang->convert->mustSelectSource);
- die(js::locate('back'));
- }
- list($sourceName, $version) = explode('_', $this->post->source);
- $setFunc = "set$sourceName";
- $this->view->header->title = $this->lang->convert->setting;
- $this->view->source = $sourceName;
- $this->view->version = $version;
- $this->view->setting = $this->fetch('convert', $setFunc, "version=$version");
- $this->display();
- }
-
- /**
- * The setting page of bugfree.
- *
- * @param string $version
- * @access public
- * @return void
- */
- public function setBugFree($version)
- {
- $this->view->source = 'BugFree';
- $this->view->version = $version;
- $this->view->tablePrefix = $version > 1 ? 'bf_' : '';
- $this->view->dbName = $version > 1 ? 'bugfree2' : 'BugFree';
- $this->view->dbCharset = 'utf8';
- $this->display();
- }
-
- /**
- * The setting page of Redmine.
- *
- * @param string $version
- * @access public
- * @return void
- */
- public function setRedmine($version)
- {
- $this->view->source = 'Redmine';
- $this->view->version = $version;
- $this->view->dbName = 'redmine';
- $this->view->dbCharset = 'utf8';
- $this->display();
- }
-
- /**
- * Check config. Same as setConfig.
- *
- * @access public
- * @return void
- */
- public function checkConfig()
- {
- $checkFunc = 'check' . $this->post->source;
- $this->view->header->title = $this->lang->convert->checkConfig;
- $this->view->source = $this->post->source;
- $this->view->checkResult = $this->fetch('convert', $checkFunc, "version={$this->post->version}");
- $this->display();
- }
-
- /**
- * Check settings of bugfree.
- *
- * @param int $version
- * @access public
- * @return void
- */
- public function checkBugFree($version)
- {
- helper::import('./converter/bugfree.php');
- $converter = new bugfreeConvertModel();
-
- /* Check it. */
- $checkInfo['db'] = $converter->connectDB();
- //if(is_object($checkInfo['db'])) $checkInfo['table'] = $converter->checkTables();
- $checkInfo['path'] = $converter->checkPath();
-
- /* Compute the checking result. */
- $result = 'pass';
- if(!is_object($checkInfo['db']) or !$checkInfo['path']) $result = 'fail';
-
- /* Assign. */
- $this->view->version = $version;
- $this->view->source = 'bugfree';
- $this->view->result = $result;
- $this->view->checkInfo = $checkInfo;
- $this->display();
- }
-
- /**
- * Check settings of Redmine.
- *
- * @param int $version
- * @access public
- * @return void
- */
- public function checkRedmine($version)
- {
- helper::import('./converter/redmine.php');
- $converter = new redmineConvertModel();
-
- /* Check it. */
- $checkInfo['db'] = $converter->connectDB();
- $checkInfo['path'] = $converter->checkPath();
-
- $this->view->trackers = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('trackers')->fetchAll('id', $autoCompany = false);
- $this->view->statuses = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('issue_statuses')->fetchAll('id', $autoCompany = false);
- $this->view->pries = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('enumerations')->where('type')->eq('IssuePriority')->fetchAll('id', $autoCompany = false);
- /* Compute the checking result. */
- $result = 'pass';
- if(!is_object($checkInfo['db']) or !$checkInfo['path']) $result = 'fail';
-
- $this->app->loadLang('bug');
- $this->app->loadLang('story');
- $this->app->loadLang('task');
- $this->view->aimTypeList['bug'] = 'bug';
- $this->view->aimTypeList['task'] = 'task';
- $this->view->aimTypeList['story'] = 'story';
-
- /* Assign. */
- $this->view->version = $version;
- $this->view->source = 'Redmine';
- $this->view->result = $result;
- $this->view->checkInfo = $checkInfo;
- $this->display();
- }
-
- /**
- * Execute the converting.
- *
- * @access public
- * @return void
- */
- public function execute()
- {
- $convertFunc = 'convert' . $this->post->source;
- $this->view->header->title = $this->lang->convert->execute;
- $this->view->source = $this->post->source;
- $this->view->version = $this->post->version;
-
- $this->view->executeResult = $this->fetch('convert', $convertFunc, "version={$this->post->version}");
- $this->display();
- }
-
- /**
- * Convert bugfree.
- *
- * @param int $version
- * @access public
- * @return void
- */
- public function convertBugFree($version)
- {
- helper::import('./converter/bugfree.php');
- helper::import("./converter/bugfree$version.php");
- $className = "bugfree{$version}ConvertModel";
- $converter = new $className();
- $this->view->version = $version;
- $this->view->result = $converter->execute($version);
- $this->view->info = bugfreeConvertModel::$info;
- $this->display();
- }
-
- /**
- * convert redmine
- *
- * @param int $version
- * @access public
- * @return void
- */
- public function convertRedmine($version)
- {
- helper::import('./converter/redmine.php');
- helper::import("./converter/redmine$version.php");
- $className = "redmine11ConvertModel";
- $redmine->aimTypes = $this->post->aimTypes;
- $redmine->statusTypes['bug'] = $this->post->statusTypesOfBug;
- $redmine->statusTypes['story'] = $this->post->statusTypesOfStory;
- $redmine->statusTypes['task'] = $this->post->statusTypesOfTask;
- $redmine->priTypes['bug'] = $this->post->priTypesOfBug;
- $redmine->priTypes['story'] = $this->post->priTypesOfStory;
- $redmine->priTypes['task'] = $this->post->priTypesOfTask;
-
- $converter = new $className($redmine);
- $this->view->version = $version;
- $this->view->result = $converter->execute($version);
- $this->view->info = redmineConvertModel::$info;
- $this->display();
- }
-}
+
+ * @package convert
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class convert extends control
+{
+ /**
+ * Index page of convert.
+ *
+ * @access public
+ * @return void
+ */
+ public function index()
+ {
+ $this->convert->saveState();
+ $this->view->header->title = $this->lang->convert->common;
+ $this->display();
+ }
+
+ /**
+ * Select the source system.
+ *
+ * @access public
+ * @return void
+ */
+ public function selectSource()
+ {
+ $this->view->header->title = $this->lang->convert->common . $this->lang->colon;
+ $this->display();
+ }
+
+ /**
+ * Set configs of converter.
+ *
+ * This is the extrance of every system. It will call the set function of corresponding module.
+ *
+ * @access public
+ * @return void
+ */
+ public function setConfig()
+ {
+ if(!$this->post->source)
+ {
+ echo js::alert($this->lang->convert->mustSelectSource);
+ die(js::locate('back'));
+ }
+ list($sourceName, $version) = explode('_', $this->post->source);
+ $setFunc = "set$sourceName";
+ $this->view->header->title = $this->lang->convert->setting;
+ $this->view->source = $sourceName;
+ $this->view->version = $version;
+ $this->view->setting = $this->fetch('convert', $setFunc, "version=$version");
+ $this->display();
+ }
+
+ /**
+ * The setting page of bugfree.
+ *
+ * @param string $version
+ * @access public
+ * @return void
+ */
+ public function setBugFree($version)
+ {
+ $this->view->source = 'BugFree';
+ $this->view->version = $version;
+ $this->view->tablePrefix = $version > 1 ? 'bf_' : '';
+ $this->view->dbName = $version > 1 ? 'bugfree2' : 'BugFree';
+ $this->view->dbCharset = 'utf8';
+ $this->display();
+ }
+
+ /**
+ * The setting page of Redmine.
+ *
+ * @param string $version
+ * @access public
+ * @return void
+ */
+ public function setRedmine($version)
+ {
+ $this->view->source = 'Redmine';
+ $this->view->version = $version;
+ $this->view->dbName = 'redmine';
+ $this->view->dbCharset = 'utf8';
+ $this->display();
+ }
+
+ /**
+ * Check config. Same as setConfig.
+ *
+ * @access public
+ * @return void
+ */
+ public function checkConfig()
+ {
+ $checkFunc = 'check' . $this->post->source;
+ $this->view->header->title = $this->lang->convert->checkConfig;
+ $this->view->source = $this->post->source;
+ $this->view->checkResult = $this->fetch('convert', $checkFunc, "version={$this->post->version}");
+ $this->display();
+ }
+
+ /**
+ * Check settings of bugfree.
+ *
+ * @param int $version
+ * @access public
+ * @return void
+ */
+ public function checkBugFree($version)
+ {
+ helper::import('./converter/bugfree.php');
+ $converter = new bugfreeConvertModel();
+
+ /* Check it. */
+ $checkInfo['db'] = $converter->connectDB();
+ //if(is_object($checkInfo['db'])) $checkInfo['table'] = $converter->checkTables();
+ $checkInfo['path'] = $converter->checkPath();
+
+ /* Compute the checking result. */
+ $result = 'pass';
+ if(!is_object($checkInfo['db']) or !$checkInfo['path']) $result = 'fail';
+
+ /* Assign. */
+ $this->view->version = $version;
+ $this->view->source = 'bugfree';
+ $this->view->result = $result;
+ $this->view->checkInfo = $checkInfo;
+ $this->display();
+ }
+
+ /**
+ * Check settings of Redmine.
+ *
+ * @param int $version
+ * @access public
+ * @return void
+ */
+ public function checkRedmine($version)
+ {
+ helper::import('./converter/redmine.php');
+ $converter = new redmineConvertModel();
+
+ /* Check it. */
+ $checkInfo['db'] = $converter->connectDB();
+ $checkInfo['path'] = $converter->checkPath();
+
+ $this->view->trackers = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('trackers')->fetchAll('id', $autoCompany = false);
+ $this->view->statuses = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('issue_statuses')->fetchAll('id', $autoCompany = false);
+ $this->view->pries = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('enumerations')->where('type')->eq('IssuePriority')->fetchAll('id', $autoCompany = false);
+ /* Compute the checking result. */
+ $result = 'pass';
+ if(!is_object($checkInfo['db']) or !$checkInfo['path']) $result = 'fail';
+
+ $this->app->loadLang('bug');
+ $this->app->loadLang('story');
+ $this->app->loadLang('task');
+ $this->view->aimTypeList['bug'] = 'bug';
+ $this->view->aimTypeList['task'] = 'task';
+ $this->view->aimTypeList['story'] = 'story';
+
+ /* Assign. */
+ $this->view->version = $version;
+ $this->view->source = 'Redmine';
+ $this->view->result = $result;
+ $this->view->checkInfo = $checkInfo;
+ $this->display();
+ }
+
+ /**
+ * Execute the converting.
+ *
+ * @access public
+ * @return void
+ */
+ public function execute()
+ {
+ $convertFunc = 'convert' . $this->post->source;
+ $this->view->header->title = $this->lang->convert->execute;
+ $this->view->source = $this->post->source;
+ $this->view->version = $this->post->version;
+
+ $this->view->executeResult = $this->fetch('convert', $convertFunc, "version={$this->post->version}");
+ $this->display();
+ }
+
+ /**
+ * Convert bugfree.
+ *
+ * @param int $version
+ * @access public
+ * @return void
+ */
+ public function convertBugFree($version)
+ {
+ helper::import('./converter/bugfree.php');
+ helper::import("./converter/bugfree$version.php");
+ $className = "bugfree{$version}ConvertModel";
+ $converter = new $className();
+ $this->view->version = $version;
+ $this->view->result = $converter->execute($version);
+ $this->view->info = bugfreeConvertModel::$info;
+ $this->display();
+ }
+
+ /**
+ * convert redmine
+ *
+ * @param int $version
+ * @access public
+ * @return void
+ */
+ public function convertRedmine($version)
+ {
+ helper::import('./converter/redmine.php');
+ helper::import("./converter/redmine$version.php");
+ $className = "redmine11ConvertModel";
+ $redmine->aimTypes = $this->post->aimTypes;
+ $redmine->statusTypes['bug'] = $this->post->statusTypesOfBug;
+ $redmine->statusTypes['story'] = $this->post->statusTypesOfStory;
+ $redmine->statusTypes['task'] = $this->post->statusTypesOfTask;
+ $redmine->priTypes['bug'] = $this->post->priTypesOfBug;
+ $redmine->priTypes['story'] = $this->post->priTypesOfStory;
+ $redmine->priTypes['task'] = $this->post->priTypesOfTask;
+
+ $converter = new $className($redmine);
+ $this->view->version = $version;
+ $this->view->result = $converter->execute($version);
+ $this->view->info = redmineConvertModel::$info;
+ $this->display();
+ }
+}
diff --git a/module/convert/converter/bugfree.php b/module/convert/converter/bugfree.php
index 3de191f906..8d520dbc3c 100644
--- a/module/convert/converter/bugfree.php
+++ b/module/convert/converter/bugfree.php
@@ -1,88 +1,88 @@
-
- * @package convert
- * @version $Id$
- * @link http://www.zentao.net
- */
-class bugfreeConvertModel extends convertModel
-{
- public $map = array();
- public $filePath = '';
- static public $info = array();
-
- /**
- * Connect to db auto.
- *
- * @access public
- * @return void
- */
- public function __construct()
- {
- parent::__construct();
- parent::connectDB();
- }
-
- /**
- * Check table.
- *
- * @access public
- * @return bool
- */
- public function checkTables()
- {
- return true;
- }
-
- /**
- * Check the install path.
- *
- * @access public
- * @return bool
- */
- public function checkPath()
- {
- $this->setPath();
- return file_exists($this->filePath);
- }
-
- /**
- * Set the path of attachments.
- *
- * @access public
- * @return bool
- */
- public function setPath()
- {
- $this->filePath = realpath($this->post->installPath) . $this->app->getPathFix() . 'BugFile' . $this->app->getPathFix();
- }
-
- /**
- * Excute the convert.
- *
- * @param int $version
- * @access public
- * @return void
- */
- public function execute($version)
- {
- }
-
- /**
- * Clear rows added in converting.
- *
- * @access public
- * @return void
- */
- public function clear()
- {
- foreach($this->session->state as $table => $maxID)
- {
- $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec();
- }
- }
-}
+
+ * @package convert
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class bugfreeConvertModel extends convertModel
+{
+ public $map = array();
+ public $filePath = '';
+ static public $info = array();
+
+ /**
+ * Connect to db auto.
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ parent::connectDB();
+ }
+
+ /**
+ * Check table.
+ *
+ * @access public
+ * @return bool
+ */
+ public function checkTables()
+ {
+ return true;
+ }
+
+ /**
+ * Check the install path.
+ *
+ * @access public
+ * @return bool
+ */
+ public function checkPath()
+ {
+ $this->setPath();
+ return file_exists($this->filePath);
+ }
+
+ /**
+ * Set the path of attachments.
+ *
+ * @access public
+ * @return bool
+ */
+ public function setPath()
+ {
+ $this->filePath = realpath($this->post->installPath) . $this->app->getPathFix() . 'BugFile' . $this->app->getPathFix();
+ }
+
+ /**
+ * Excute the convert.
+ *
+ * @param int $version
+ * @access public
+ * @return void
+ */
+ public function execute($version)
+ {
+ }
+
+ /**
+ * Clear rows added in converting.
+ *
+ * @access public
+ * @return void
+ */
+ public function clear()
+ {
+ foreach($this->session->state as $table => $maxID)
+ {
+ $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec();
+ }
+ }
+}
diff --git a/module/convert/converter/bugfree1.php b/module/convert/converter/bugfree1.php
index 3aa8a53d4f..33e47d16b1 100644
--- a/module/convert/converter/bugfree1.php
+++ b/module/convert/converter/bugfree1.php
@@ -1,318 +1,318 @@
-
- * @package convert
- * @version $Id$
- * @link http://www.zentao.net
- */
-class bugfree1ConvertModel extends bugfreeConvertModel
-{
- /**
- * Execute the convert.
- *
- * @access public
- * @return array
- */
- public function execute()
- {
- $this->clear();
- $this->convertGroup();
- $result['users'] = $this->convertUser();
- $result['projects'] = $this->convertProject();
- $result['modules'] = $this->convertModule();
- $result['bugs'] = $this->convertBug();
- $result['actions'] = $this->convertAction();
- $result['files'] = $this->convertFile();
- $this->dao->dbh($this->dbh);
- $this->loadModel('tree')->fixModulePath();
- return $result;
- }
-
- /**
- * Convert groups.
- *
- * @access public
- * @return void
- */
- public function convertGroup()
- {
- $groups = $this->dao->dbh($this->sourceDBH)
- ->select("groupID AS id, groupName AS name, groupUser AS users")
- ->from('BugGroup')
- ->fetchAll('id', $autoCompany = false);
- foreach($groups as $groupID => $group)
- {
- /* Explode into array. */
- $groupUsers = explode(',', $group->users);
- unset($group->id);
- unset($group->users);
-
- /* Insert the group. */
- $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)->data($group)->exec();
- $zentaoGroupID = $this->dao->lastInsertId();
-
- /* Insert account. */
- foreach($groupUsers as $account)
- {
- if(empty($account)) continue;
- $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)->set('`group`')->eq($zentaoGroupID)->set('account')->eq($account)->exec();
- }
- }
- }
-
- /**
- * Convert user.
- *
- * @access public
- * @return int converted user count
- */
- public function convertUser()
- {
- /* Get users exist in the system. */
- $activeUsers = $this->dao
- ->dbh($this->sourceDBH)
- ->select("username AS account, userpassword AS password, realname, email")
- ->from('BugUser')
- ->orderBy('userID ASC')
- ->fetchAll('account', $autoCompany = false);
-
- /* Get users in histories. */
- $allUsers = $this->dao->select("distinct(username) AS account")->from('BugHistory')->fetchPairs('', '', $autoCompany = false);
-
- /* Merge them. */
- foreach($allUsers as $key => $account)
- {
- if(isset($activeUsers[$account]))
- {
- $allUsers[$key] = $activeUsers[$account];
- }
- else
- {
- $allUsers[$key] = array('account' => $account, 'realname' => $account, 'deleted' => '1');
- }
- }
- foreach($activeUsers as $account => $user) if(!isset($allUsers[$account])) $allUsers[$account] = $user;
-
- /* Insert into zentao. */
- $convertCount = 0;
- foreach($allUsers as $account => $user)
- {
- if(!$this->dao->dbh($this->dbh)->findByAccount($account)->from(TABLE_USER)->fetch('account'))
- {
- $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec();
- $convertCount ++;
- }
- else
- {
- self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $account);
- }
- }
- return $convertCount;
- }
-
- /**
- * Convert project in bugfree to product in zentao.
- *
- * @access public
- * @return int converted project count
- */
- public function convertProject()
- {
- $projects = $this->dao->dbh($this->sourceDBH)->select("projectID AS id, projectName AS name")->from('BugProject')->fetchAll('id', $autoCompany = false);
- foreach($projects as $projectID => $project)
- {
- unset($project->id);
- $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($project)->exec();
- $this->map['product'][$projectID] = $this->dao->lastInsertID();
- }
- return count($projects);
- }
-
- /**
- * Convert modules.
- *
- * @access public
- * @return int converted modules count
- */
- public function convertModule()
- {
- $this->map['module'][0] = 0;
- $modules = $this->dao
- ->dbh($this->sourceDBH)
- ->select(
- 'moduleID AS id,
- projectID AS root,
- moduleName AS name,
- moduleGrade AS grade,
- parentID AS parent,
- "bug" AS type')
- ->from('BugModule')
- ->orderBy('id ASC')
- ->fetchAll('id', $autoCompany = false);
- foreach($modules as $moduleID => $module)
- {
- $module->root = $this->map['product'][$module->root];
- unset($module->id);
- $this->dao->dbh($this->dbh)->insert(TABLE_MODULE)->data($module)->exec();
- $this->map['module'][$moduleID] = $this->dao->lastInsertID();
- }
-
- /* Update parents. */
- foreach($modules as $oldModuleID => $module)
- {
- $newModuleID = $this->map['module'][$oldModuleID];
- $newParentID = $this->map['module'][$module->parent];
- $this->dao->dbh($this->dbh)->update(TABLE_MODULE)->set('parent')->eq($newParentID)->where('id')->eq($newModuleID)->exec();
- }
- return count($modules);
- }
-
- /**
- * Convert bugs.
- *
- * @access public
- * @return int converted bugs count.
- */
- public function convertBug()
- {
- $bugs = $this->dao
- ->dbh($this->sourceDBH)
- ->select('
- bugID AS id,
- projectID AS product,
- moduleID AS module,
- bugTitle AS title,
- bugSeverity AS severity,
- bugType AS type,
- bugOS AS os,
- bugStatus AS status,
- mailto,
- openedBy, openedDate, openedBuild,
- assignedTo, assignedDate,
- resolvedBy, resolution, resolvedBuild, resolvedDate,
- closedBy, closedDate,
- lastEditedBy, lastEditedDate,
- linkID as duplicateBug
- ')
- ->from('BugInfo')
- ->orderBy('bugID')
- ->fetchAll('id', $autoCompany = false);
- foreach($bugs as $bugID => $bug)
- {
- /* Adjust some fields of bug. */
- $bugID = (int)$bugID;
- unset($bug->id);
- if($bug->assignedTo == 'Closed') $bug->assignedTo = 'closed';
- $bug->type = strtolower($bug->type);
- $bug->os = strtolower($bug->os);
- $bug->browser = 'all';
- $bug->resolution = str_replace(' ','', strtolower($bug->resolution));
- $bug->product = $this->map['product'][$bug->product];
- $bug->module = $this->map['module'][$bug->module];
- $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec();
- $this->map['bug'][$bugID] = $this->dao->lastInsertID();
- }
-
- /* Update duplicated bugs. */
- foreach($this->map['bug'] as $oldBugID => $newBugID)
- {
- $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('duplicateBug')->eq($newBugID)->where('duplicateBug')->eq($oldBugID)->exec();
- }
- return count($bugs);
- }
-
- /**
- * Convert actions.
- *
- * @access public
- * @return int converted actions count.
- */
- public function convertAction()
- {
- $actions = $this->dao
- ->dbh($this->sourceDBH)
- ->select("
- 'bug' AS objectType,
- bugID AS objectID,
- userName AS actor,
- action,
- fullInfo AS comment,
- actionDate AS date")
- ->from('BugHistory')
- ->orderBy('bugID, historyID')
- ->fetchGroup('objectID', '', $autoCompany = false);
- $convertCount = 0;
- foreach($actions as $bugID => $bugActions)
- {
- /* Get the related bugID. */
- $bugID = (int)$bugID;
- $zentaoBugID = $this->map['bug'][$bugID];
-
- /* Process actions. */
- foreach($bugActions as $key => $action)
- {
- $action->objectID = $zentaoBugID;
- if($key == 0)
- {
- $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('steps')->eq(nl2br($action->comment))->where('id')->eq($zentaoBugID)->exec();
- $action->comment = '';
- }
- $this->dao->dbh($this->dbh)->insert(TABLE_ACTION)->data($action)->exec();
- $convertCount ++;
- }
- }
- return $convertCount;
- }
-
- /**
- * Convert files.
- *
- * @access public
- * @return int converted files count.
- */
- public function convertFile()
- {
- $this->setPath();
- $files = $this->dao->dbh($this->sourceDBH)
- ->select("
- fileName AS pathname,
- fileTitle AS title,
- fileType AS extension,
- fileSize AS size,
- 'bug' AS objectType,
- bugID AS objectID,
- addUser AS addedBy,
- addDate AS addedDate
- ")
- ->from('BugFile')
- ->orderBy('fileID')
- ->fetchAll('', $autoCompany = false);
- foreach($files as $file)
- {
- $file->objectID = $this->map['bug'][(int)$file->objectID];
- if(strpos($file->size, 'KB')) $file->size = (int)(str_replace('KB', '', $file->size) * 1024);
- if(strpos($file->size, 'MB')) $file->size = (int)(str_replace('MB', '', $file->size) * 1024 * 1024);
- $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec();
-
- /* Copy files. */
- $soureFile = $this->filePath . $file->pathname;
- if(!file_exists($soureFile))
- {
- self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile);
- continue;
- }
- $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname;
- $targetPath = dirname($targetFile);
- if(!is_dir($targetPath)) mkdir($targetPath, 0777, true);
- if(!copy($soureFile, $targetFile))
- {
- self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile);
- }
- }
- return count($files);
- }
-}
+
+ * @package convert
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class bugfree1ConvertModel extends bugfreeConvertModel
+{
+ /**
+ * Execute the convert.
+ *
+ * @access public
+ * @return array
+ */
+ public function execute()
+ {
+ $this->clear();
+ $this->convertGroup();
+ $result['users'] = $this->convertUser();
+ $result['projects'] = $this->convertProject();
+ $result['modules'] = $this->convertModule();
+ $result['bugs'] = $this->convertBug();
+ $result['actions'] = $this->convertAction();
+ $result['files'] = $this->convertFile();
+ $this->dao->dbh($this->dbh);
+ $this->loadModel('tree')->fixModulePath();
+ return $result;
+ }
+
+ /**
+ * Convert groups.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertGroup()
+ {
+ $groups = $this->dao->dbh($this->sourceDBH)
+ ->select("groupID AS id, groupName AS name, groupUser AS users")
+ ->from('BugGroup')
+ ->fetchAll('id', $autoCompany = false);
+ foreach($groups as $groupID => $group)
+ {
+ /* Explode into array. */
+ $groupUsers = explode(',', $group->users);
+ unset($group->id);
+ unset($group->users);
+
+ /* Insert the group. */
+ $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)->data($group)->exec();
+ $zentaoGroupID = $this->dao->lastInsertId();
+
+ /* Insert account. */
+ foreach($groupUsers as $account)
+ {
+ if(empty($account)) continue;
+ $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)->set('`group`')->eq($zentaoGroupID)->set('account')->eq($account)->exec();
+ }
+ }
+ }
+
+ /**
+ * Convert user.
+ *
+ * @access public
+ * @return int converted user count
+ */
+ public function convertUser()
+ {
+ /* Get users exist in the system. */
+ $activeUsers = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select("username AS account, userpassword AS password, realname, email")
+ ->from('BugUser')
+ ->orderBy('userID ASC')
+ ->fetchAll('account', $autoCompany = false);
+
+ /* Get users in histories. */
+ $allUsers = $this->dao->select("distinct(username) AS account")->from('BugHistory')->fetchPairs('', '', $autoCompany = false);
+
+ /* Merge them. */
+ foreach($allUsers as $key => $account)
+ {
+ if(isset($activeUsers[$account]))
+ {
+ $allUsers[$key] = $activeUsers[$account];
+ }
+ else
+ {
+ $allUsers[$key] = array('account' => $account, 'realname' => $account, 'deleted' => '1');
+ }
+ }
+ foreach($activeUsers as $account => $user) if(!isset($allUsers[$account])) $allUsers[$account] = $user;
+
+ /* Insert into zentao. */
+ $convertCount = 0;
+ foreach($allUsers as $account => $user)
+ {
+ if(!$this->dao->dbh($this->dbh)->findByAccount($account)->from(TABLE_USER)->fetch('account'))
+ {
+ $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec();
+ $convertCount ++;
+ }
+ else
+ {
+ self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $account);
+ }
+ }
+ return $convertCount;
+ }
+
+ /**
+ * Convert project in bugfree to product in zentao.
+ *
+ * @access public
+ * @return int converted project count
+ */
+ public function convertProject()
+ {
+ $projects = $this->dao->dbh($this->sourceDBH)->select("projectID AS id, projectName AS name")->from('BugProject')->fetchAll('id', $autoCompany = false);
+ foreach($projects as $projectID => $project)
+ {
+ unset($project->id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($project)->exec();
+ $this->map['product'][$projectID] = $this->dao->lastInsertID();
+ }
+ return count($projects);
+ }
+
+ /**
+ * Convert modules.
+ *
+ * @access public
+ * @return int converted modules count
+ */
+ public function convertModule()
+ {
+ $this->map['module'][0] = 0;
+ $modules = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select(
+ 'moduleID AS id,
+ projectID AS root,
+ moduleName AS name,
+ moduleGrade AS grade,
+ parentID AS parent,
+ "bug" AS type')
+ ->from('BugModule')
+ ->orderBy('id ASC')
+ ->fetchAll('id', $autoCompany = false);
+ foreach($modules as $moduleID => $module)
+ {
+ $module->root = $this->map['product'][$module->root];
+ unset($module->id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_MODULE)->data($module)->exec();
+ $this->map['module'][$moduleID] = $this->dao->lastInsertID();
+ }
+
+ /* Update parents. */
+ foreach($modules as $oldModuleID => $module)
+ {
+ $newModuleID = $this->map['module'][$oldModuleID];
+ $newParentID = $this->map['module'][$module->parent];
+ $this->dao->dbh($this->dbh)->update(TABLE_MODULE)->set('parent')->eq($newParentID)->where('id')->eq($newModuleID)->exec();
+ }
+ return count($modules);
+ }
+
+ /**
+ * Convert bugs.
+ *
+ * @access public
+ * @return int converted bugs count.
+ */
+ public function convertBug()
+ {
+ $bugs = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select('
+ bugID AS id,
+ projectID AS product,
+ moduleID AS module,
+ bugTitle AS title,
+ bugSeverity AS severity,
+ bugType AS type,
+ bugOS AS os,
+ bugStatus AS status,
+ mailto,
+ openedBy, openedDate, openedBuild,
+ assignedTo, assignedDate,
+ resolvedBy, resolution, resolvedBuild, resolvedDate,
+ closedBy, closedDate,
+ lastEditedBy, lastEditedDate,
+ linkID as duplicateBug
+ ')
+ ->from('BugInfo')
+ ->orderBy('bugID')
+ ->fetchAll('id', $autoCompany = false);
+ foreach($bugs as $bugID => $bug)
+ {
+ /* Adjust some fields of bug. */
+ $bugID = (int)$bugID;
+ unset($bug->id);
+ if($bug->assignedTo == 'Closed') $bug->assignedTo = 'closed';
+ $bug->type = strtolower($bug->type);
+ $bug->os = strtolower($bug->os);
+ $bug->browser = 'all';
+ $bug->resolution = str_replace(' ','', strtolower($bug->resolution));
+ $bug->product = $this->map['product'][$bug->product];
+ $bug->module = $this->map['module'][$bug->module];
+ $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec();
+ $this->map['bug'][$bugID] = $this->dao->lastInsertID();
+ }
+
+ /* Update duplicated bugs. */
+ foreach($this->map['bug'] as $oldBugID => $newBugID)
+ {
+ $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('duplicateBug')->eq($newBugID)->where('duplicateBug')->eq($oldBugID)->exec();
+ }
+ return count($bugs);
+ }
+
+ /**
+ * Convert actions.
+ *
+ * @access public
+ * @return int converted actions count.
+ */
+ public function convertAction()
+ {
+ $actions = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select("
+ 'bug' AS objectType,
+ bugID AS objectID,
+ userName AS actor,
+ action,
+ fullInfo AS comment,
+ actionDate AS date")
+ ->from('BugHistory')
+ ->orderBy('bugID, historyID')
+ ->fetchGroup('objectID', '', $autoCompany = false);
+ $convertCount = 0;
+ foreach($actions as $bugID => $bugActions)
+ {
+ /* Get the related bugID. */
+ $bugID = (int)$bugID;
+ $zentaoBugID = $this->map['bug'][$bugID];
+
+ /* Process actions. */
+ foreach($bugActions as $key => $action)
+ {
+ $action->objectID = $zentaoBugID;
+ if($key == 0)
+ {
+ $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('steps')->eq(nl2br($action->comment))->where('id')->eq($zentaoBugID)->exec();
+ $action->comment = '';
+ }
+ $this->dao->dbh($this->dbh)->insert(TABLE_ACTION)->data($action)->exec();
+ $convertCount ++;
+ }
+ }
+ return $convertCount;
+ }
+
+ /**
+ * Convert files.
+ *
+ * @access public
+ * @return int converted files count.
+ */
+ public function convertFile()
+ {
+ $this->setPath();
+ $files = $this->dao->dbh($this->sourceDBH)
+ ->select("
+ fileName AS pathname,
+ fileTitle AS title,
+ fileType AS extension,
+ fileSize AS size,
+ 'bug' AS objectType,
+ bugID AS objectID,
+ addUser AS addedBy,
+ addDate AS addedDate
+ ")
+ ->from('BugFile')
+ ->orderBy('fileID')
+ ->fetchAll('', $autoCompany = false);
+ foreach($files as $file)
+ {
+ $file->objectID = $this->map['bug'][(int)$file->objectID];
+ if(strpos($file->size, 'KB')) $file->size = (int)(str_replace('KB', '', $file->size) * 1024);
+ if(strpos($file->size, 'MB')) $file->size = (int)(str_replace('MB', '', $file->size) * 1024 * 1024);
+ $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec();
+
+ /* Copy files. */
+ $soureFile = $this->filePath . $file->pathname;
+ if(!file_exists($soureFile))
+ {
+ self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile);
+ continue;
+ }
+ $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname;
+ $targetPath = dirname($targetFile);
+ if(!is_dir($targetPath)) mkdir($targetPath, 0777, true);
+ if(!copy($soureFile, $targetFile))
+ {
+ self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile);
+ }
+ }
+ return count($files);
+ }
+}
diff --git a/module/convert/converter/bugfree2.php b/module/convert/converter/bugfree2.php
index efe2641c75..f436b7a7bc 100644
--- a/module/convert/converter/bugfree2.php
+++ b/module/convert/converter/bugfree2.php
@@ -1,530 +1,530 @@
-
- * @package convert
- * @version $Id$
- * @link http://www.zentao.net
- */
-class bugfree2ConvertModel extends bugfreeConvertModel
-{
- /**
- * Execute the converter.
- *
- * @access public
- * @return array
- */
- public function execute()
- {
- $this->clear();
- $this->setTable();
- $this->convertGroup();
- $result['users'] = $this->convertUser();
- $result['projects'] = $this->convertProject();
- $result['modules'] = $this->convertModule();
- $result['bugs'] = $this->convertBug();
- $result['cases'] = $this->convertCase();
- $result['results'] = $this->convertResult();
- $result['actions'] = $this->convertAction();
- $result['files'] = $this->convertFile();
- $this->dao->dbh($this->dbh);
- $this->loadModel('tree')->fixModulePath();
- return $result;
- }
-
- /**
- * Set table names.
- *
- * @access public
- * @return void
- */
- public function setTable()
- {
- $dbPrefix = $this->post->dbPrefix;
- define('BUGFREE_TABLE_OPTION', $dbPrefix . 'TestOptions');
- define('BUGFREE_TABLE_USER', $dbPrefix . 'TestUser');
- define('BUGFREE_TABLE_PROJECT', $dbPrefix . 'TestProject');
- define('BUGFREE_TABLE_MODULE', $dbPrefix . 'TestModule');
- define('BUGFREE_TABLE_BUGINFO', $dbPrefix . 'BugInfo');
- define('BUGFREE_TABLE_CASEINFO', $dbPrefix . 'CaseInfo');
- define('BUGFREE_TABLE_RESULTINFO', $dbPrefix . 'ResultInfo');
- define('BUGFREE_TABLE_ACTION', $dbPrefix . 'TestAction');
- define('BUGFREE_TABLE_FILE', $dbPrefix . 'TestFile');
- define('BUGFREE_TABLE_HISTORY', $dbPrefix . 'TestHistory');
- define('BUGFREE_TABLE_GROUP', $dbPrefix . 'TestGroup');
- }
-
- /**
- * Get the version of bugfree2.x.
- *
- * @access public
- * @return int
- */
- public function getBugFreeVersion()
- {
- return $this->dao->dbh($this->sourceDBH)
- ->select("optionValue as version")->from(BUGFREE_TABLE_OPTION)
- ->where('OptionName')->eq('dbVersion')
- ->fetch('version', $autoCompany = false);
-
- }
-
- /**
- * Convert user.
- *
- * @access public
- * @return int converted user count
- */
- public function convertUser()
- {
- /* Get all user list. */
- $users = $this->dao
- ->dbh($this->sourceDBH)
- ->select("username AS account, userpassword AS password, realname, email, isDroped AS deleted")
- ->from(BUGFREE_TABLE_USER)
- ->orderBy('userID ASC')
- ->fetchAll('account', $autoCompany = false);
-
- /* Insert into zentao. */
- $convertCount = 0;
- foreach($users as $account => $user)
- {
- if(!$this->dao->dbh($this->dbh)->findByAccount($account)->from(TABLE_USER)->fetch('account'))
- {
- $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec();
- $convertCount ++;
- }
- else
- {
- self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $account);
- }
- }
- return $convertCount;
- }
-
- /**
- * Convert groups.
- *
- * @access public
- * @return void converted group count.
- */
- public function convertGroup()
- {
- if(!$this->tableExists(BUGFREE_TABLE_GROUP)) return false;
- $groups = $this->dao->dbh($this->sourceDBH)
- ->select("groupID AS id, groupName AS name, groupUser AS users")
- ->from(BUGFREE_TABLE_GROUP)
- ->fetchAll('id', $autoCompany = false);
- foreach($groups as $groupID => $group)
- {
- /* Fix the group data. */
- if($group->name == '[All Users]') continue;
- $groupUsers = explode(',', $group->users);
- unset($group->id);
- unset($group->users);
-
- /* Insert into zentao's group table. */
- $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)->data($group)->exec();
- $zentaoGroupID = $this->dao->lastInsertId();
-
- /* Insert into zentao's usergroup table. */
- foreach($groupUsers as $account)
- {
- if(empty($account)) continue;
- $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)
- ->set('`group`')->eq($zentaoGroupID)
- ->set('account')->eq($account)
- ->exec();
- }
- }
- }
-
- /**
- * Convert projects.
- *
- * @access public
- * @return int converted projects count.
- */
- public function convertProject()
- {
- $projects = $this->dao->dbh($this->sourceDBH)
- ->select("projectID AS id, projectName AS name, isDroped AS deleted")
- ->from(BUGFREE_TABLE_PROJECT)
- ->fetchAll('id', $autoComapny = false);
- foreach($projects as $projectID => $project)
- {
- unset($project->id);
- $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($project)->exec();
- $this->map['product'][$projectID] = $this->dao->lastInsertID();
- }
- return count($projects);
- }
-
- /**
- * Convert modules.
- *
- * @access public
- * @return int converted modules count.
- */
- public function convertModule()
- {
- $this->map['module'][0] = 0;
- $modules = $this->dao
- ->dbh($this->sourceDBH)
- ->select(
- 'moduleID AS id,
- moduleType as type,
- projectID AS root,
- moduleName AS name,
- moduleGrade AS grade,
- parentID AS parent,
- displayOrder AS `order`')
- ->from(BUGFREE_TABLE_MODULE)
- ->orderBy('id ASC')
- ->fetchAll('id', $autoCompany = false);
- foreach($modules as $moduleID => $module)
- {
- $module->root = $this->map['product'][$module->root];
- $module->type = strtolower($module->type);
- unset($module->id);
- $this->dao->dbh($this->dbh)->insert(TABLE_MODULE)->data($module)->exec();
- $this->map['module'][$moduleID] = $this->dao->lastInsertID();
- }
-
- /* Update parent. */
- foreach($modules as $oldModuleID => $module)
- {
- $newModuleID = $this->map['module'][$oldModuleID];
- $newParentID = $this->map['module'][$module->parent];
- $this->dao->dbh($this->dbh)->update(TABLE_MODULE)->set('parent')->eq($newParentID)->where('id')->eq($newModuleID)->exec();
- }
- return count($modules);
- }
-
- /**
- * Convert bugs.
- *
- * @access public
- * @return int converted bugs count.
- */
- public function convertBug()
- {
- $bugs = $this->dao
- ->dbh($this->sourceDBH)
- ->select('
- bugID AS id,
- projectID AS product,
- moduleID AS module,
- bugTitle AS title,
- bugSeverity AS severity,
- bugPriority AS pri,
- bugType AS type,
- bugOS AS os,
- bugBrowser AS browser,
- bugMachine AS hardware,
- howFound AS found,
- reproSteps AS steps,
- bugStatus AS status,
- linkID AS linkBug,
- duplicateID AS duplicateBug,
- caseID AS `case`,
- 1 AS caseVersion,
- resultID AS result,
- mailto,
- openedBy, openedDate, openedBuild,
- assignedTo, assignedDate,
- resolvedBy, resolution, resolvedBuild, resolvedDate,
- closedBy, closedDate,
- lastEditedBy, lastEditedDate,
- bugKeyword AS keywords
- ')
- ->from(BUGFREE_TABLE_BUGINFO)
- ->where('isDroped')->eq(0)
- ->orderBy('bugID')
- ->fetchAll('id', $autoCompany = false);
- foreach($bugs as $bugID => $bug)
- {
- /* Fix some fileds of bug. */
- $bugID = (int)$bugID;
- unset($bug->id);
-
- if($bug->assignedTo == 'Closed') $bug->assignedTo = 'closed';
- if($bug->assignedTo == 'Active') $bug->assignedTo = '';
-
- $bug->type = strtolower($bug->type);
- $bug->found = strtolower($bug->found);
- $bug->status = strtolower($bug->status);
- $bug->os = strtolower($bug->os);
- $bug->browser= strtolower($bug->browser);
- $bug->steps = nl2br($bug->steps);
-
- if($bug->os == 'winvista') $bug->os = 'vista';
- if($bug->browser == 'firefox3.0') $bug->browser = 'firefox3';
- if($bug->browser == 'firefox2.0') $bug->browser = 'firefox2';
- if($bug->openedBuild == 'N/A') $bug->openedBuild = '';
- if(!$bug->case) $bug->caseVersion = 0;
-
- $bug->resolution = str_replace(' ', '', strtolower($bug->resolution));
- $bug->product = $this->map['product'][$bug->product];
- $bug->module = $this->map['module'][$bug->module];
- $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec();
- $this->map['bug'][$bugID] = $this->dao->lastInsertID();
- }
-
- /* Update duplicated bugs. */
- foreach($this->map['bug'] as $oldBugID => $newBugID)
- {
- $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('duplicateBug')->eq($newBugID)->where('duplicateBug')->eq($oldBugID)->exec();
- }
- return count($bugs);
- }
-
- /**
- * Convert cases.
- *
- * @access public
- * @return int converted cases count.
- */
- public function convertCase()
- {
- $cases = $this->dao
- ->dbh($this->sourceDBH)
- ->select('
- caseID AS id,
- projectID AS product,
- moduleID AS module,
- caseTitle AS title,
- caseSteps AS step,
- casePriority AS pri,
- caseType AS type,
- caseStatus AS status,
- caseMethod AS howRun,
- casePlan AS stage,
- openedBy, openedDate,
- lastEditedBy, lastEditedDate,
- scriptedBy, scriptedDate, scriptStatus, scriptLocation,
- linkID AS linkCase,
- casekeyword AS keywords,
- 1 AS version,
- bugID
- ')
- ->from(BUGFREE_TABLE_CASEINFO)
- ->where('isDroped')->eq(0)
- ->orderBy('caseID')
- ->fetchAll('id', $autoCompany = false);
- foreach($cases as $caseID => $case)
- {
- /* Fix fields of case. */
- $caseID = (int)$caseID;
- $step = $case->step;
- $bugs = explode(',', $case->bugID);
- unset($case->id);
- unset($case->step);
- unset($case->bugID);
-
- $case->type = strtolower($case->type);
- $case->status = strtolower($case->status);
- $case->howRun = strtolower($case->howRun);
- $case->stage = strtolower($case->stage);
-
- if($case->type == 'configuration') $case->type = 'config';
- if($case->type == 'setup') $case->type = 'install';
- if($case->type == 'functional') $case->type = 'feature';
- if($case->status == 'active') $case->status = 'normal';
-
- /* Change product and module by zentao's product and module. */
- $case->product = $this->map['product'][$case->product];
- $case->module = $this->map['module'][$case->module];
-
- /* Insert into case table. */
- $this->dao->dbh($this->dbh)->insert(TABLE_CASE)->data($case)->exec();
- $zentaoCaseID = $this->dao->lastInsertID();
- $this->map['case'][$caseID] = $zentaoCaseID;
-
- /* Insert into case step table. */
- $caseStep->case = $zentaoCaseID;
- $caseStep->version = 1;
- $caseStep->desc = $step;
- $this->dao->dbh($this->dbh)->insert(TABLE_CASESTEP)->data($caseStep)->exec();
-
- /* Update related bugs. */
- foreach($bugs as $bugID)
- {
- if(!isset($this->map['bug'][$bugID])) continue;
- $zentaoBugID = $this->map['bug'][$bugID];
- $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('`case`')->eq($zentaoCaseID)->where('id')->eq($zentaoBugID)->limit(1)->exec();
- }
- }
- return count($cases);
- }
-
- /**
- * Convert results.
- *
- * @access public
- * @return int converted results count.
- */
- public function convertResult()
- {
- $results = $this->dao->dbh($this->sourceDBH)
- ->select('
- resultID AS id,
- caseID AS `case`,
- resultValue AS caseResult,
- 1 AS version,
- openedDate as date,
- bugID
- ')
- ->from(BUGFREE_TABLE_RESULTINFO)
- ->orderBy('id')
- ->fetchAll('id', $autoCompany = false);
- foreach($results as $resultID => $result)
- {
- unset($result->id);
-
- /* The bug id of zentao. */
- $bugID = (int)$result->bugID;
- $zentaoBugID = $this->map['bug'][$bugID];
- unset($result->bugID);
-
- /* Insert into test result table. */
- $this->dao->dbh($this->dbh)->insert(TABLE_TESTRESULT)->data($result)->exec();
- $zentaoResultID = $this->dao->lastInsertId();
- $this->map['result'][$resultID] = $zentaoResultID;
-
- /* Update result table. */
- $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('result')->eq($zentaoResultID)->where('id')->eq($zentaoBugID)->limit(1)->exec();
- }
- return count($results);
- }
-
- /**
- * Convert actions.
- *
- * @access public
- * @return int converted actions count.
- */
- public function convertAction()
- {
- $actions = $this->dao
- ->dbh($this->sourceDBH)
- ->select("actionID AS id,
- actionTarget AS objectType,
- idValue AS objectID,
- actionUser AS actor,
- actionType AS action,
- actionDate AS date,
- actionNote AS comment
- ")
- ->from(BUGFREE_TABLE_ACTION)
- ->where('actionTarget' != 'Result')
- ->orderBy('actionID')
- ->fetchAll('id', $autoComapny = false);
-
- foreach($actions as $actionID => $action)
- {
- $actionID = (int)$action->id;
- unset($action->id);
- $action->objectType = strtolower($action->objectType);
- $action->action = strtolower($action->action);
- $action->objectID = $this->map[$action->objectType][$action->objectID];
-
- $this->dao->dbh($this->dbh)->insert(TABLE_ACTION)->data($action)->exec();
- $this->map['action'][$actionID] = $this->dao->lastInsertID();
- }
- return count($actions);
- }
-
- /**
- * Convert histories.
- *
- * @access public
- * @return int the converted histories count.
- */
- public function convertHistory()
- {
- $histories = $this->dao->dbh($this->sourceDBH)
- ->select('actioID, actionField AS field, oldValue AS old, newValue AS new')
- ->from(BUGFREE_TABLE_HISTORY)
- ->orderBy('historyID')
- ->fetchAll('', $autoCompany = false);
- foreach($histories as $history)
- {
- $history->actionID = $this->map['action'][$history->actionID];
- $this->dao->dbh($this->dbh)->insert(TABLE_HISTORY)->data($history)->exec();
- }
- }
-
- /**
- * Convert attachments.
- *
- * @access public
- * @return int the converted files count.
- */
- public function convertFile()
- {
- $this->setPath();
- $files = $this->dao->dbh($this->sourceDBH)
- ->select("
- actionID,
- fileName AS pathname,
- fileTitle AS title,
- fileType AS extension,
- fileSize AS size
- ")
- ->from(BUGFREE_TABLE_FILE)
- ->orderBy('fileID')
- ->fetchAll('', $autoCompany = false);
- foreach($files as $file)
- {
- /* Get the actionID in zentao, to get file info. */
- $zentaoActionID = $this->map['action'][$file->actionID];
- $zentaoAction = $this->dao->dbh($this->dbh)->findById($zentaoActionID)->from(TABLE_ACTION)->fetch();
- $file->objectType = $zentaoAction->objectType;
- $file->objectID = $zentaoAction->objectID;
- $file->addedBy = $zentaoAction->actor;
- $file->addedDate = $zentaoAction->date;
- unset($file->actionID);
-
- /* Compute the file size. */
- if(strpos($file->size, 'KB')) $file->size = (int)(str_replace('KB', '', $file->size) * 1024);
- if(strpos($file->size, 'MB')) $file->size = (int)(str_replace('MB', '', $file->size) * 1024 * 1024);
-
- /* Insert into database. */
- $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec();
-
- /* Copy file. */
- $soureFile = $this->filePath . $file->pathname;
- if(!file_exists($soureFile))
- {
- self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile);
- continue;
- }
- $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname;
- $targetPath = dirname($targetFile);
- if(!is_dir($targetPath)) mkdir($targetPath, 0777, true);
- if(!copy($soureFile, $targetFile))
- {
- self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile);
- }
- }
- return count($files);
- }
-
- /**
- * Clear the converted records.
- *
- * @access public
- * @return void
- */
- public function clear()
- {
- foreach($this->session->state as $table => $maxID)
- {
- $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec();
- }
- }
-}
+
+ * @package convert
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class bugfree2ConvertModel extends bugfreeConvertModel
+{
+ /**
+ * Execute the converter.
+ *
+ * @access public
+ * @return array
+ */
+ public function execute()
+ {
+ $this->clear();
+ $this->setTable();
+ $this->convertGroup();
+ $result['users'] = $this->convertUser();
+ $result['projects'] = $this->convertProject();
+ $result['modules'] = $this->convertModule();
+ $result['bugs'] = $this->convertBug();
+ $result['cases'] = $this->convertCase();
+ $result['results'] = $this->convertResult();
+ $result['actions'] = $this->convertAction();
+ $result['files'] = $this->convertFile();
+ $this->dao->dbh($this->dbh);
+ $this->loadModel('tree')->fixModulePath();
+ return $result;
+ }
+
+ /**
+ * Set table names.
+ *
+ * @access public
+ * @return void
+ */
+ public function setTable()
+ {
+ $dbPrefix = $this->post->dbPrefix;
+ define('BUGFREE_TABLE_OPTION', $dbPrefix . 'TestOptions');
+ define('BUGFREE_TABLE_USER', $dbPrefix . 'TestUser');
+ define('BUGFREE_TABLE_PROJECT', $dbPrefix . 'TestProject');
+ define('BUGFREE_TABLE_MODULE', $dbPrefix . 'TestModule');
+ define('BUGFREE_TABLE_BUGINFO', $dbPrefix . 'BugInfo');
+ define('BUGFREE_TABLE_CASEINFO', $dbPrefix . 'CaseInfo');
+ define('BUGFREE_TABLE_RESULTINFO', $dbPrefix . 'ResultInfo');
+ define('BUGFREE_TABLE_ACTION', $dbPrefix . 'TestAction');
+ define('BUGFREE_TABLE_FILE', $dbPrefix . 'TestFile');
+ define('BUGFREE_TABLE_HISTORY', $dbPrefix . 'TestHistory');
+ define('BUGFREE_TABLE_GROUP', $dbPrefix . 'TestGroup');
+ }
+
+ /**
+ * Get the version of bugfree2.x.
+ *
+ * @access public
+ * @return int
+ */
+ public function getBugFreeVersion()
+ {
+ return $this->dao->dbh($this->sourceDBH)
+ ->select("optionValue as version")->from(BUGFREE_TABLE_OPTION)
+ ->where('OptionName')->eq('dbVersion')
+ ->fetch('version', $autoCompany = false);
+
+ }
+
+ /**
+ * Convert user.
+ *
+ * @access public
+ * @return int converted user count
+ */
+ public function convertUser()
+ {
+ /* Get all user list. */
+ $users = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select("username AS account, userpassword AS password, realname, email, isDroped AS deleted")
+ ->from(BUGFREE_TABLE_USER)
+ ->orderBy('userID ASC')
+ ->fetchAll('account', $autoCompany = false);
+
+ /* Insert into zentao. */
+ $convertCount = 0;
+ foreach($users as $account => $user)
+ {
+ if(!$this->dao->dbh($this->dbh)->findByAccount($account)->from(TABLE_USER)->fetch('account'))
+ {
+ $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec();
+ $convertCount ++;
+ }
+ else
+ {
+ self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $account);
+ }
+ }
+ return $convertCount;
+ }
+
+ /**
+ * Convert groups.
+ *
+ * @access public
+ * @return void converted group count.
+ */
+ public function convertGroup()
+ {
+ if(!$this->tableExists(BUGFREE_TABLE_GROUP)) return false;
+ $groups = $this->dao->dbh($this->sourceDBH)
+ ->select("groupID AS id, groupName AS name, groupUser AS users")
+ ->from(BUGFREE_TABLE_GROUP)
+ ->fetchAll('id', $autoCompany = false);
+ foreach($groups as $groupID => $group)
+ {
+ /* Fix the group data. */
+ if($group->name == '[All Users]') continue;
+ $groupUsers = explode(',', $group->users);
+ unset($group->id);
+ unset($group->users);
+
+ /* Insert into zentao's group table. */
+ $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)->data($group)->exec();
+ $zentaoGroupID = $this->dao->lastInsertId();
+
+ /* Insert into zentao's usergroup table. */
+ foreach($groupUsers as $account)
+ {
+ if(empty($account)) continue;
+ $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)
+ ->set('`group`')->eq($zentaoGroupID)
+ ->set('account')->eq($account)
+ ->exec();
+ }
+ }
+ }
+
+ /**
+ * Convert projects.
+ *
+ * @access public
+ * @return int converted projects count.
+ */
+ public function convertProject()
+ {
+ $projects = $this->dao->dbh($this->sourceDBH)
+ ->select("projectID AS id, projectName AS name, isDroped AS deleted")
+ ->from(BUGFREE_TABLE_PROJECT)
+ ->fetchAll('id', $autoComapny = false);
+ foreach($projects as $projectID => $project)
+ {
+ unset($project->id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($project)->exec();
+ $this->map['product'][$projectID] = $this->dao->lastInsertID();
+ }
+ return count($projects);
+ }
+
+ /**
+ * Convert modules.
+ *
+ * @access public
+ * @return int converted modules count.
+ */
+ public function convertModule()
+ {
+ $this->map['module'][0] = 0;
+ $modules = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select(
+ 'moduleID AS id,
+ moduleType as type,
+ projectID AS root,
+ moduleName AS name,
+ moduleGrade AS grade,
+ parentID AS parent,
+ displayOrder AS `order`')
+ ->from(BUGFREE_TABLE_MODULE)
+ ->orderBy('id ASC')
+ ->fetchAll('id', $autoCompany = false);
+ foreach($modules as $moduleID => $module)
+ {
+ $module->root = $this->map['product'][$module->root];
+ $module->type = strtolower($module->type);
+ unset($module->id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_MODULE)->data($module)->exec();
+ $this->map['module'][$moduleID] = $this->dao->lastInsertID();
+ }
+
+ /* Update parent. */
+ foreach($modules as $oldModuleID => $module)
+ {
+ $newModuleID = $this->map['module'][$oldModuleID];
+ $newParentID = $this->map['module'][$module->parent];
+ $this->dao->dbh($this->dbh)->update(TABLE_MODULE)->set('parent')->eq($newParentID)->where('id')->eq($newModuleID)->exec();
+ }
+ return count($modules);
+ }
+
+ /**
+ * Convert bugs.
+ *
+ * @access public
+ * @return int converted bugs count.
+ */
+ public function convertBug()
+ {
+ $bugs = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select('
+ bugID AS id,
+ projectID AS product,
+ moduleID AS module,
+ bugTitle AS title,
+ bugSeverity AS severity,
+ bugPriority AS pri,
+ bugType AS type,
+ bugOS AS os,
+ bugBrowser AS browser,
+ bugMachine AS hardware,
+ howFound AS found,
+ reproSteps AS steps,
+ bugStatus AS status,
+ linkID AS linkBug,
+ duplicateID AS duplicateBug,
+ caseID AS `case`,
+ 1 AS caseVersion,
+ resultID AS result,
+ mailto,
+ openedBy, openedDate, openedBuild,
+ assignedTo, assignedDate,
+ resolvedBy, resolution, resolvedBuild, resolvedDate,
+ closedBy, closedDate,
+ lastEditedBy, lastEditedDate,
+ bugKeyword AS keywords
+ ')
+ ->from(BUGFREE_TABLE_BUGINFO)
+ ->where('isDroped')->eq(0)
+ ->orderBy('bugID')
+ ->fetchAll('id', $autoCompany = false);
+ foreach($bugs as $bugID => $bug)
+ {
+ /* Fix some fileds of bug. */
+ $bugID = (int)$bugID;
+ unset($bug->id);
+
+ if($bug->assignedTo == 'Closed') $bug->assignedTo = 'closed';
+ if($bug->assignedTo == 'Active') $bug->assignedTo = '';
+
+ $bug->type = strtolower($bug->type);
+ $bug->found = strtolower($bug->found);
+ $bug->status = strtolower($bug->status);
+ $bug->os = strtolower($bug->os);
+ $bug->browser= strtolower($bug->browser);
+ $bug->steps = nl2br($bug->steps);
+
+ if($bug->os == 'winvista') $bug->os = 'vista';
+ if($bug->browser == 'firefox3.0') $bug->browser = 'firefox3';
+ if($bug->browser == 'firefox2.0') $bug->browser = 'firefox2';
+ if($bug->openedBuild == 'N/A') $bug->openedBuild = '';
+ if(!$bug->case) $bug->caseVersion = 0;
+
+ $bug->resolution = str_replace(' ', '', strtolower($bug->resolution));
+ $bug->product = $this->map['product'][$bug->product];
+ $bug->module = $this->map['module'][$bug->module];
+ $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec();
+ $this->map['bug'][$bugID] = $this->dao->lastInsertID();
+ }
+
+ /* Update duplicated bugs. */
+ foreach($this->map['bug'] as $oldBugID => $newBugID)
+ {
+ $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('duplicateBug')->eq($newBugID)->where('duplicateBug')->eq($oldBugID)->exec();
+ }
+ return count($bugs);
+ }
+
+ /**
+ * Convert cases.
+ *
+ * @access public
+ * @return int converted cases count.
+ */
+ public function convertCase()
+ {
+ $cases = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select('
+ caseID AS id,
+ projectID AS product,
+ moduleID AS module,
+ caseTitle AS title,
+ caseSteps AS step,
+ casePriority AS pri,
+ caseType AS type,
+ caseStatus AS status,
+ caseMethod AS howRun,
+ casePlan AS stage,
+ openedBy, openedDate,
+ lastEditedBy, lastEditedDate,
+ scriptedBy, scriptedDate, scriptStatus, scriptLocation,
+ linkID AS linkCase,
+ casekeyword AS keywords,
+ 1 AS version,
+ bugID
+ ')
+ ->from(BUGFREE_TABLE_CASEINFO)
+ ->where('isDroped')->eq(0)
+ ->orderBy('caseID')
+ ->fetchAll('id', $autoCompany = false);
+ foreach($cases as $caseID => $case)
+ {
+ /* Fix fields of case. */
+ $caseID = (int)$caseID;
+ $step = $case->step;
+ $bugs = explode(',', $case->bugID);
+ unset($case->id);
+ unset($case->step);
+ unset($case->bugID);
+
+ $case->type = strtolower($case->type);
+ $case->status = strtolower($case->status);
+ $case->howRun = strtolower($case->howRun);
+ $case->stage = strtolower($case->stage);
+
+ if($case->type == 'configuration') $case->type = 'config';
+ if($case->type == 'setup') $case->type = 'install';
+ if($case->type == 'functional') $case->type = 'feature';
+ if($case->status == 'active') $case->status = 'normal';
+
+ /* Change product and module by zentao's product and module. */
+ $case->product = $this->map['product'][$case->product];
+ $case->module = $this->map['module'][$case->module];
+
+ /* Insert into case table. */
+ $this->dao->dbh($this->dbh)->insert(TABLE_CASE)->data($case)->exec();
+ $zentaoCaseID = $this->dao->lastInsertID();
+ $this->map['case'][$caseID] = $zentaoCaseID;
+
+ /* Insert into case step table. */
+ $caseStep->case = $zentaoCaseID;
+ $caseStep->version = 1;
+ $caseStep->desc = $step;
+ $this->dao->dbh($this->dbh)->insert(TABLE_CASESTEP)->data($caseStep)->exec();
+
+ /* Update related bugs. */
+ foreach($bugs as $bugID)
+ {
+ if(!isset($this->map['bug'][$bugID])) continue;
+ $zentaoBugID = $this->map['bug'][$bugID];
+ $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('`case`')->eq($zentaoCaseID)->where('id')->eq($zentaoBugID)->limit(1)->exec();
+ }
+ }
+ return count($cases);
+ }
+
+ /**
+ * Convert results.
+ *
+ * @access public
+ * @return int converted results count.
+ */
+ public function convertResult()
+ {
+ $results = $this->dao->dbh($this->sourceDBH)
+ ->select('
+ resultID AS id,
+ caseID AS `case`,
+ resultValue AS caseResult,
+ 1 AS version,
+ openedDate as date,
+ bugID
+ ')
+ ->from(BUGFREE_TABLE_RESULTINFO)
+ ->orderBy('id')
+ ->fetchAll('id', $autoCompany = false);
+ foreach($results as $resultID => $result)
+ {
+ unset($result->id);
+
+ /* The bug id of zentao. */
+ $bugID = (int)$result->bugID;
+ $zentaoBugID = $this->map['bug'][$bugID];
+ unset($result->bugID);
+
+ /* Insert into test result table. */
+ $this->dao->dbh($this->dbh)->insert(TABLE_TESTRESULT)->data($result)->exec();
+ $zentaoResultID = $this->dao->lastInsertId();
+ $this->map['result'][$resultID] = $zentaoResultID;
+
+ /* Update result table. */
+ $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('result')->eq($zentaoResultID)->where('id')->eq($zentaoBugID)->limit(1)->exec();
+ }
+ return count($results);
+ }
+
+ /**
+ * Convert actions.
+ *
+ * @access public
+ * @return int converted actions count.
+ */
+ public function convertAction()
+ {
+ $actions = $this->dao
+ ->dbh($this->sourceDBH)
+ ->select("actionID AS id,
+ actionTarget AS objectType,
+ idValue AS objectID,
+ actionUser AS actor,
+ actionType AS action,
+ actionDate AS date,
+ actionNote AS comment
+ ")
+ ->from(BUGFREE_TABLE_ACTION)
+ ->where('actionTarget' != 'Result')
+ ->orderBy('actionID')
+ ->fetchAll('id', $autoComapny = false);
+
+ foreach($actions as $actionID => $action)
+ {
+ $actionID = (int)$action->id;
+ unset($action->id);
+ $action->objectType = strtolower($action->objectType);
+ $action->action = strtolower($action->action);
+ $action->objectID = $this->map[$action->objectType][$action->objectID];
+
+ $this->dao->dbh($this->dbh)->insert(TABLE_ACTION)->data($action)->exec();
+ $this->map['action'][$actionID] = $this->dao->lastInsertID();
+ }
+ return count($actions);
+ }
+
+ /**
+ * Convert histories.
+ *
+ * @access public
+ * @return int the converted histories count.
+ */
+ public function convertHistory()
+ {
+ $histories = $this->dao->dbh($this->sourceDBH)
+ ->select('actioID, actionField AS field, oldValue AS old, newValue AS new')
+ ->from(BUGFREE_TABLE_HISTORY)
+ ->orderBy('historyID')
+ ->fetchAll('', $autoCompany = false);
+ foreach($histories as $history)
+ {
+ $history->actionID = $this->map['action'][$history->actionID];
+ $this->dao->dbh($this->dbh)->insert(TABLE_HISTORY)->data($history)->exec();
+ }
+ }
+
+ /**
+ * Convert attachments.
+ *
+ * @access public
+ * @return int the converted files count.
+ */
+ public function convertFile()
+ {
+ $this->setPath();
+ $files = $this->dao->dbh($this->sourceDBH)
+ ->select("
+ actionID,
+ fileName AS pathname,
+ fileTitle AS title,
+ fileType AS extension,
+ fileSize AS size
+ ")
+ ->from(BUGFREE_TABLE_FILE)
+ ->orderBy('fileID')
+ ->fetchAll('', $autoCompany = false);
+ foreach($files as $file)
+ {
+ /* Get the actionID in zentao, to get file info. */
+ $zentaoActionID = $this->map['action'][$file->actionID];
+ $zentaoAction = $this->dao->dbh($this->dbh)->findById($zentaoActionID)->from(TABLE_ACTION)->fetch();
+ $file->objectType = $zentaoAction->objectType;
+ $file->objectID = $zentaoAction->objectID;
+ $file->addedBy = $zentaoAction->actor;
+ $file->addedDate = $zentaoAction->date;
+ unset($file->actionID);
+
+ /* Compute the file size. */
+ if(strpos($file->size, 'KB')) $file->size = (int)(str_replace('KB', '', $file->size) * 1024);
+ if(strpos($file->size, 'MB')) $file->size = (int)(str_replace('MB', '', $file->size) * 1024 * 1024);
+
+ /* Insert into database. */
+ $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec();
+
+ /* Copy file. */
+ $soureFile = $this->filePath . $file->pathname;
+ if(!file_exists($soureFile))
+ {
+ self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile);
+ continue;
+ }
+ $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname;
+ $targetPath = dirname($targetFile);
+ if(!is_dir($targetPath)) mkdir($targetPath, 0777, true);
+ if(!copy($soureFile, $targetFile))
+ {
+ self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile);
+ }
+ }
+ return count($files);
+ }
+
+ /**
+ * Clear the converted records.
+ *
+ * @access public
+ * @return void
+ */
+ public function clear()
+ {
+ foreach($this->session->state as $table => $maxID)
+ {
+ $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec();
+ }
+ }
+}
diff --git a/module/convert/converter/redmine.php b/module/convert/converter/redmine.php
index d5a44ce51a..464b6edfcb 100644
--- a/module/convert/converter/redmine.php
+++ b/module/convert/converter/redmine.php
@@ -1,88 +1,88 @@
-
- * @package convert
- * @version $Id $
- * @link http://www.zentao.net
- */
-class redmineConvertModel extends convertModel
-{
- public $map = array();
- public $filePath = '';
- static public $info = array();
-
- /**
- * Connect to db auto.
- *
- * @access public
- * @return void
- */
- public function __construct()
- {
- parent::__construct();
- parent::connectDB();
- }
-
- /**
- * Check table.
- *
- * @access public
- * @return bool
- */
- public function checkTables()
- {
- return true;
- }
-
- /**
- * Check the install path.
- *
- * @access public
- * @return bool
- */
- public function checkPath()
- {
- $this->setPath();
- return file_exists($this->filePath);
- }
-
- /**
- * Set the path of attachments.
- *
- * @access public
- * @return bool
- */
- public function setPath()
- {
- $this->filePath = realpath($this->post->installPath) . $this->app->getPathFix() . 'files' . $this->app->getPathFix();
- }
-
- /**
- * Excute the convert.
- *
- * @param int $version
- * @access public
- * @return void
- */
- public function execute($version)
- {
- }
-
- /**
- * Clear rows added in converting.
- *
- * @access public
- * @return void
- */
- public function clear()
- {
- foreach($this->session->state as $table => $maxID)
- {
- $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec();
- }
- }
-}
+
+ * @package convert
+ * @version $Id $
+ * @link http://www.zentao.net
+ */
+class redmineConvertModel extends convertModel
+{
+ public $map = array();
+ public $filePath = '';
+ static public $info = array();
+
+ /**
+ * Connect to db auto.
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ parent::connectDB();
+ }
+
+ /**
+ * Check table.
+ *
+ * @access public
+ * @return bool
+ */
+ public function checkTables()
+ {
+ return true;
+ }
+
+ /**
+ * Check the install path.
+ *
+ * @access public
+ * @return bool
+ */
+ public function checkPath()
+ {
+ $this->setPath();
+ return file_exists($this->filePath);
+ }
+
+ /**
+ * Set the path of attachments.
+ *
+ * @access public
+ * @return bool
+ */
+ public function setPath()
+ {
+ $this->filePath = realpath($this->post->installPath) . $this->app->getPathFix() . 'files' . $this->app->getPathFix();
+ }
+
+ /**
+ * Excute the convert.
+ *
+ * @param int $version
+ * @access public
+ * @return void
+ */
+ public function execute($version)
+ {
+ }
+
+ /**
+ * Clear rows added in converting.
+ *
+ * @access public
+ * @return void
+ */
+ public function clear()
+ {
+ foreach($this->session->state as $table => $maxID)
+ {
+ $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec();
+ }
+ }
+}
diff --git a/module/convert/converter/redmine1.1.php b/module/convert/converter/redmine1.1.php
index b018c8d905..8ab99848c8 100644
--- a/module/convert/converter/redmine1.1.php
+++ b/module/convert/converter/redmine1.1.php
@@ -1,822 +1,822 @@
-
- * @package convert
- * @version $Id $
- * @link http://www.zentao.net
- */
-class redmine11ConvertModel extends redmineConvertModel
-{
- static $convertGroupCount = 0;
- static $convertUserCount = 0;
- static $convertProductCount = 0;
- static $convertProjectCount = 0;
- static $convertStoryCount = 0;
- static $convertTaskCount = 0;
- static $convertBugCount = 0;
- static $convertProductPlanCount = 0;
- static $convertTeamCount = 0;
- static $convertReleaseCount = 0;
- static $convertBuildCount = 0;
- static $convertDocLibCount = 0;
- static $convertDocCount = 0;
- static $convertFileCount = 0;
- public $issueType;
-
- public function __construct($issueType)
- {
- parent::__construct();
- $this->issueType = $issueType;
- }
- /**
- * Execute the converter.
- *
- * @access public
- * @return array
- */
- public function execute()
- {
- $this->clear();
- $this->setTable();
- $this->convertGroup();
- $this->convertUser();
- $this->convertUserGroup();
- $this->convertProduct();
- $this->convertProject();
- $this->convertBuildAndRelease();
- $this->convertProductPlan();
- $this->convertProjectProduct();
- $this->convertTeam();
- $this->convertDocLib();
- $this->convertDoc();
- $this->convertNews();
- $this->convertIssue();
- $this->convertFile();
- $this->dao->dbh($this->dbh);
- $this->loadModel('tree')->fixModulePath();
-
- $result['groups'] = self::$convertGroupCount;
- $result['users'] = self::$convertUserCount ;
- $result['products'] = self::$convertProductCount ;
- $result['projects'] = self::$convertProjectCount ;
- $result['stories'] = self::$convertStoryCount;
- $result['tasks'] = self::$convertTaskCount ;
- $result['bugs'] = self::$convertBugCount ;
- $result['productPlans'] = self::$convertProductPlanCount;
- $result['teams'] = self::$convertTeamCount;
- $result['releases'] = self::$convertReleaseCount;
- $result['builds'] = self::$convertBuildCount;
- $result['docLibs'] = self::$convertDocLibCount ;
- $result['docs'] = self::$convertDocCount;
- $result['files'] = self::$convertFileCount;
- return $result;
- }
-
- /**
- * Set table names.
- *
- * @access public
- * @return void
- */
- public function setTable()
- {
- //$dbPrefix = $this->post->dbPrefix;
- $dbPrefix = '';
- define('REDMINE_TABLE_ATTACHMENTS', $dbPrefix . 'attachments');
- define('REDMINE_TABLE_AUTH_SOURCES', $dbPrefix . 'auth_sources');
- define('REDMINE_TABLE_BOARDS', $dbPrefix . 'boards');
- define('REDMINE_TABLE_CHANGES', $dbPrefix . 'changes');
- define('REDMINE_TABLE_CHANGESETS', $dbPrefix . 'changesets');
- define('REDMINE_TABLE_CHANGESETS_ISSUES', $dbPrefix . 'changesets_issues');
- define('REDMINE_TABLE_COMMENTS', $dbPrefix . 'comments');
- define('REDMINE_TABLE_CUSTOM_FIELDS', $dbPrefix . 'custom_fields');
- define('REDMINE_TABLE_CUSTOM_FIELDS_PROJECTS', $dbPrefix . 'custom_fields_projects');
- define('REDMINE_TABLE_CUSTOM_FIELDS_TRACKERS', $dbPrefix . 'custom_fields_trackers');
- define('REDMINE_TABLE_CUSTOM_VALUES', $dbPrefix . 'custom_values');
- define('REDMINE_TABLE_DOCUMENTS', $dbPrefix . 'documents');
- define('REDMINE_TABLE_ENABLED_MODULES', $dbPrefix . 'enabled_modules');
- define('REDMINE_TABLE_ENUMERATIONS', $dbPrefix . 'enumerations');
- define('REDMINE_TABLE_GROUPS_USERS', $dbPrefix . 'groups_users');
- define('REDMINE_TABLE_ISSUES', $dbPrefix . 'issues');
- define('REDMINE_TABLE_ISSUE_CATEGORIES', $dbPrefix . 'issue_categories');
- define('REDMINE_TABLE_ISSUE_RELATIONS', $dbPrefix . 'issue_relations');
- define('REDMINE_TABLE_ISSUE_STATUSES', $dbPrefix . 'issue_statuses');
- define('REDMINE_TABLE_JOURNALS', $dbPrefix . 'journals');
- define('REDMINE_TABLE_JOURNAL_DETAILS', $dbPrefix . 'journal_details');
- define('REDMINE_TABLE_MEMBERS', $dbPrefix . 'members');
- define('REDMINE_TABLE_MEMBER_ROLES', $dbPrefix . 'member_roles');
- define('REDMINE_TABLE_MESSAGES', $dbPrefix . 'messages');
- define('REDMINE_TABLE_NEWS', $dbPrefix . 'news');
- define('REDMINE_TABLE_OPEN_ID_AUTHENTICATION_ASSOCIATIONS', $dbPrefix . 'open_id_authentication_associations');
- define('REDMINE_TABLE_OPEN_ID_AUTHENTICATION_NONCES', $dbPrefix . 'open_id_authentication_nonces');
- define('REDMINE_TABLE_PROJECTS', $dbPrefix . 'projects');
- define('REDMINE_TABLE_PROJECTS_TRACKERS', $dbPrefix . 'projects_trackers');
- define('REDMINE_TABLE_QUERIES', $dbPrefix . 'queries');
- define('REDMINE_TABLE_REPOSITORIES', $dbPrefix . 'repositories');
- define('REDMINE_TABLE_ROLES', $dbPrefix . 'roles');
- define('REDMINE_TABLE_SCHEMA_MIGRATIONS', $dbPrefix . 'schema_migrations');
- define('REDMINE_TABLE_SETTINGS', $dbPrefix . 'settings');
- define('REDMINE_TABLE_TIME_ENTRIES', $dbPrefix . 'time_entries');
- define('REDMINE_TABLE_TOKENS', $dbPrefix . 'tokens');
- define('REDMINE_TABLE_TRACKERS', $dbPrefix . 'trackers');
- define('REDMINE_TABLE_USERS', $dbPrefix . 'users');
- define('REDMINE_TABLE_USER_PREFERENCES', $dbPrefix . 'user_preferences');
- define('REDMINE_TABLE_VERSIONS', $dbPrefix . 'versions');
- define('REDMINE_TABLE_WATCHERS', $dbPrefix . 'watchers');
- define('REDMINE_TABLE_WIKIS', $dbPrefix . 'wikis');
- define('REDMINE_TABLE_WIKI_CONTENTS', $dbPrefix . 'wiki_contents');
- define('REDMINE_TABLE_WIKI_CONTENT_VERSIONS', $dbPrefix . 'wiki_content_versions');
- define('REDMINE_TABLE_WIKI_PAGES', $dbPrefix . 'wiki_pages');
- define('REDMINE_TABLE_WIKI_REDIRECTS', $dbPrefix . 'wiki_redirects');
- define('REDMINE_TABLE_WORKFLOWS', $dbPrefix . 'workflows');
- }
-
- /**
- * Convert groups.
- *
- * @access public
- * @return void
- */
- public function convertGroup()
- {
- /* Get group list */
- $groups = $this->dao->dbh($this->sourceDBH)
- ->select("id, lastName AS name")
- ->from(REDMINE_TABLE_USERS)
- ->where('type')->eq('Group')
- ->fetchAll('id', $autoCompany = false);
-
- $zentaoGroupNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_GROUP)->fetchPairs();
- $zentaoGroupIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_GROUP)->fetchPairs();
-
- /* Insert into zentao */
- $convertCount = 0;
- foreach($groups as $groupID =>$group)
- {
- unset($group->id);
- if(in_array("$group->name", $zentaoGroupNames))
- {
- self::$info['groups'][] = sprintf($this->lang->convert->errorGroupExists, $group->name);
- $this->map['groups'][$groupID] = $zentaoGroupIDs[$group->name];
- }
- else
- {
- $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)
- ->data($group)->exec();
- $this->map['groups'][$groupID] = $this->dao->lastInsertID();
- $convertCount ++;
- }
- }
- self::$convertGroupCount += $convertCount;
- }
-
- /**
- * Convert users.
- *
- * @access public
- * @return void
- */
- public function convertUser()
- {
- /* Get user list. */
- $users = $this->dao->dbh($this->sourceDBH)
- ->select("id, login AS account, firstname, lastname, mail as email")
- ->from(REDMINE_TABLE_USERS)
- ->where('type')->eq('User')
- ->fetchAll('id', $autoCompany = false);
-
- $zentaoUserNames = $this->dao->dbh($this->dbh)->select('id, account')->from(TABLE_USER)->fetchPairs();
- $zentaoUserIDs = $this->dao->dbh($this->dbh)->select('account, id')->from(TABLE_USER)->fetchPairs();
-
- /* Insert into zentao. */
- $convertCount = 0;
- foreach($users as $id => $user)
- {
- if(in_array("$user->account", $zentaoUserNames))
- {
- self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $user->account);
- $this->map['users'][$id] = $zentaoUserIDs[$user->account];
- }
- else
- {
- $user->password = md5('123456');
- $user->realname = $user->lastname . $user->firstname;
- unset($user->id);
- unset($user->lastname);
- unset($user->firstname);
- $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec();
- $this->map['users'][$id] = $this->dao->lastInsertID();
- $convertCount ++;
- }
- }
- self::$convertUserCount += $convertCount;
- }
-
- /**
- * convert relationship between user and group.
- *
- * @access public
- * @return void
- */
- public function convertUserGroup()
- {
- $this->map['groups'][0] = 0;
- /* Get relation between user and group list. */
- $userGroups = $this->dao->dbh($this->sourceDBH)
- ->select("t1.group_id, t2.login as account")
- ->from(REDMINE_TABLE_GROUPS_USERS)->alias('t1')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.user_id = t2.id')
- ->fetchAll('', $autoCompany = false);
-
- $zentaoUserGroups = $this->dao->dbh($this->dbh)->select('*')->from(TABLE_USERGROUP)->fetchAll();
-
- /* Insert into zentao. */
- $userGroupExist = false;
- foreach($userGroups as $userGroup)
- {
- $userGroup->group = $this->map['groups'][$userGroup->group_id];
- unset($userGroup->group_id);
- foreach($zentaoUserGroups as $zentaoUserGroup)
- {
- if($userGroup->group == $zentaoUserGroup->group and $userGroup->account == $zentaoUserGroup->account)
- {
- $userGroupExist = true;
- }
- }
- if($userGroupExist == false)
- {
- $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)->data($userGroup)->exec();
- }
- }
- }
-
- /**
- * convert products.
- *
- * @access public
- * @return void
- */
- public function convertProduct()
- {
- /* Get product list */
- $products = $this->dao->dbh($this->sourceDBH)
- ->select("id, name, description as `desc`, created_on as createdDate")
- ->from(REDMINE_TABLE_PROJECTS)
- ->fetchAll('id', $autoComapny = false);
-
- /* Insert into zentao */
- foreach($products as $productID => $product)
- {
- unset($product->id);
- $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($product)->exec();
- $this->map['products'][$productID] = $this->dao->lastInsertID();
- }
- self::$convertProductCount += count($products);
- }
-
- /**
- * Convert projects.
- *
- * @access public
- * @return void
- */
- public function convertProject()
- {
- /* Get project list */
- $projects = $this->dao->dbh($this->sourceDBH)
- ->select("id, name, project_id, description as `desc`, effective_date AS end")
- ->from(REDMINE_TABLE_VERSIONS)
- ->fetchAll('id', $autoComapny = false);
-
- /* Insert into zentao */
- foreach($projects as $projectID => $project)
- {
- $productID = $project->project_id;
- unset($project->id);
- unset($project->project_id);
- $this->dao->dbh($this->dbh)->insert(TABLE_PROJECT)->data($project)->exec();
- $this->map['projects'][$productID][$projectID] = $this->dao->lastInsertID();
- $this->map['project'][$projectID] = $this->map['projects'][$productID][$projectID];
- }
-
- /* Create a same name project with product */
- foreach($this->map['products'] as $productID)
- {
- $project = $this->dao->dbh($this->dbh)->select('name')->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch();
- $this->dao->dbh($this->dbh)->insert(TABLE_PROJECT)->data($project)->exec();
- $this->map['projectOfProduct'][$productID] = $this->dao->lastinsertID();
- }
- $convertCount = count($projects) + count($this->map['projectOfProduct']);
- self::$convertProjectCount += $convertCount;
- }
-
- /**
- * convert builds and releases
- *
- * @access public
- * @return void
- */
- public function convertBuildAndRelease()
- {
- /* Get build list */
- $buildAndReleases = $this->dao->dbh($this->sourceDBH)
- ->select("id, name, project_id, description as `desc`, effective_date AS date")
- ->from(REDMINE_TABLE_VERSIONS)
- ->fetchAll('id', $autoCompany = false);
-
- /* Insert into zentao */
- $convertBuildsCount = 0;
- $convertReleasesCount = 0;
- $zentaoBuildNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_BUILD)->fetchPairs();
- $zentaoBuildIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_BUILD)->fetchPairs();
- $zentaoReleaseNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_RELEASE)->fetchPairs();
- $zentaoReleaseIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_RELEASE)->fetchPairs();
- foreach($buildAndReleases as $id => $buildAndRelease)
- {
- $buildAndRelease->project = $this->map['project'][$id];
- $buildAndRelease->product = $this->map['products'][$buildAndRelease->project_id];
- unset($buildAndRelease->id);
- unset($buildAndRelease->project_id);
-
- if(in_array($buildAndRelease->name, $zentaoBuildNames))
- {
- self::$info['builds'][] = sprintf($this->lang->convert->errorBuildExists, $buildAndRelease->name);
- $buildAndRelease->build = $zentaoBuildIDs[$buildAndRelease->name];
- }
- else
- {
- $this->dao->dbh($this->dbh)->insert(TABLE_BUILD)->data($buildAndRelease)->exec();
- $buildAndRelease->build = $this->dao->lastInsertID();
- $convertBuildsCount ++;
- }
-
- unset($buildAndRelease->project);
- if(in_array($buildAndRelease->name, $zentaoBuildNames))
- {
- self::$info['releases'][] = sprintf($this->lang->convert->errorReleaseExists, $buildAndRelease->name);
- }
- else
- {
- $this->dao->dbh($this->dbh)->insert(TABLE_RELEASE)->data($buildAndRelease)->exec();
- $convertReleasesCount ++;
- }
- }
- self::$convertBuildCount += $convertBuildsCount;
- self::$convertReleaseCount += $convertReleasesCount;
- }
-
- /**
- * convert productPlans
- *
- * @access public
- * @return void
- */
- public function convertProductPlan()
- {
- /* Get productPlan list */
- $productPlans = $this->dao->dbh($this->sourceDBH)
- ->select("id, name as title, project_id, description as `desc`, effective_date as end, created_on AS begin")
- ->from(REDMINE_TABLE_VERSIONS)
- ->fetchAll('id', $autoCompany = false);
- /* Insert into zentao */
- foreach($productPlans as $id => $productPlan)
- {
- $productPlan->product = $this->map['products'][$productPlan->project_id];
- unset($productPlan->id);
- unset($productPlan->project_id);
- $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec();
- }
-
- /* Create a same plan with product */
- foreach($this->map['products'] as $productID)
- {
- $productPlan = $this->dao->dbh($this->dbh)->select("name as title, createdDate as begin")->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch();
- $productPlan->product = $productID;
- $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec();
- $this->map['planOfProduct'][$productID] = $this->dao->lastinsertID();
- }
- $convertCount = count($this->map['products']) + count($productPlans);
- self::$convertProductPlanCount += $convertCount;
- }
-
- /**
- * convert relationship between project and product.
- *
- * @access public
- * @return void
- */
- public function convertProjectProduct()
- {
- foreach($this->map['projects'] as $productID => $projects)
- {
- foreach($projects as $projectID => $project)
- {
- $this->dao->dbh($this->dbh)->insert(TABLE_PROJECTPRODUCT)
- ->set('project')->eq($project)
- ->set('product')->eq($this->map['products'][$productID])
- ->exec();
- }
- }
- }
-
- /**
- * convert teams.
- *
- * @access public
- * @return void
- */
- public function convertTeam()
- {
- /* Get team list */
- $teams = $this->dao->dbh($this->sourceDBH)
- ->select("t2.login as account, t1.project_id, t1.created_on AS joinDate")
- ->from(REDMINE_TABLE_MEMBERS)->alias('t1')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.user_id = t2.id')
- ->where('t2.type')->eq('User')
- ->fetchAll('', $autoCompany = false);
-
- /* Insert into zentao */
- foreach($teams as $team)
- {
- $productID = $team->project_id;
- unset($team->project_id);
- foreach($this->map['projects'][$productID] as $projectID)
- {
- $team->project = $projectID;
- $this->dao->dbh($this->dbh)->insert(TABLE_TEAM)->data($team)->exec();
- }
- }
- self::$convertTeamCount += count($teams);
- }
-
- /**
- * convert docLibs.
- *
- * @access public
- * @return void
- */
- public function convertDocLib()
- {
- /* Get docLib list */
- $docLibs = $this->dao->dbh($this->sourceDBH)
- ->select("id, name")->from(REDMINE_TABLE_ENUMERATIONS)
- ->where('type')->eq('DocumentCategory')
- ->fetchAll('id', $autoCompany = false);
-
- /* Insert into zentao */
- foreach($docLibs as $docLibID => $docLib)
- {
- unset($docLib->id);
- $this->dao->dbh($this->dbh)->insert(TABLE_DOCLIB)->data($docLib)->exec();
- $this->map['docLibs'][$docLibID] = $this->dao->lastInsertID();
- }
- self::$convertDocLibCount += count($docLibs);
- }
-
- /**
- * convert docs.
- *
- * @access public
- * @return void
- */
- public function convertDoc()
- {
- /* Get all docs */
- $docs = $this->dao->dbh($this->sourceDBH)
- ->select("t1.id, t1.project_id AS product, t2.id AS lib, t1.title, t1.description AS content, t1.created_on AS addedDate")
- ->from(REDMINE_TABLE_DOCUMENTS)->alias('t1')
- ->leftjoin(REDMINE_TABLE_ENUMERATIONS)->alias('t2')->on('t1.category_id = t2.id')
- ->fetchAll('id', $autoCompany = false);
-
- /* Insert into zentao */
- foreach($docs as $docID => $doc)
- {
- unset($doc->id);
- $doc->type = 'text';
- $doc->project = 0;
- $doc->product = $this->map['products'][$doc->product];
- $doc->lib = $this->map['docLibs'][$doc->lib];
- $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($doc)->exec();
- $this->map['docs'][$docID] = $this->dao->lastInsertID();
- }
- self::$convertDocCount += count($docs);
- }
-
- /**
- * convert news.
- *
- * @access public
- * @return void
- */
- public function convertNews()
- {
- /* Get news from redmine */
- $news = $this->dao->dbh($this->sourceDBH)
- ->select("t1.project_id as product, t1.title, t1.summary as digest, t1.description as content, t2.login as addedBy, t1.created_on as addedDate")
- ->from(REDMINE_TABLE_NEWS)->alias('t1')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.author_id = t2.id')
- ->fetchAll('', $autoCompany = false);
-
- /* Create a news docLib */
- $newLib->name = 'news';
- $this->dao->dbh($this->dbh)->insert(TABLE_DOCLIB)->data($newLib)->exec();
- $this->map['news'] = $this->dao->lastInsertID();
- self::$convertDocLibCount += 1;
-
- /* Insert into zentao */
- foreach($news as $new)
- {
- $new->product = $this->map['products'][$new->product];
- $new->project = 0;
- $new->lib = $this->map['news'];
- $new->type = 'text';
-
- $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($new)->exec();
- }
- self::$convertDocCount += count($news);
- }
-
- /**
- * convert issue
- *
- * @param array $aimTypes //aimTypes['issueTypeID'] = aimtype eg. aimTypes[1] = 'bug';
- * @param array $statusTypes //statusTypes['task']['statusTypeID'] = statusType eg. statusTypes['task'][1] = 'wait';
- * //statusTypes['bug']['statusTypeID'] = statusType eg. statusTypes['bug'][1] = 'active';
- * @param array $priTypes //priTypes['task']['priTypeID'] = priType; eg. priTypes['task'][1] = 1;
- * @access public
- * @return void
- */
- public function convertIssue()
- {
- $aimTypes = $this->issueType->aimTypes;
- $statusTypes = $this->issueType->statusTypes;
- $priTypes = $this->issueType->priTypes;
-
- foreach($aimTypes as $issueType => $aimType)
- {
- if('story' == $aimType)
- {
- $this->convertStory($issueType, $statusTypes, $priTypes);
- }
- elseif('task' == $aimType)
- {
- $this->convertTask($issueType, $statusTypes, $priTypes);
- }
- else
- {
- $this->convertBug($issueType, $statusTypes, $priTypes);
- }
- }
- }
-
- /**
- * convert story
- *
- * @param array $issueType
- * @param array $statusTypes
- * @param array $priTypes
- * @access public
- * @return void
- */
- public function convertStory($issueType, $statusTypes, $priTypes)
- {
- /* Get story list*/
- $stories = $this->dao->dbh($this->sourceDBH)
- ->select("t1.id, t1.project_id as product, t1.subject as title, t1.description as spec, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.estimated_hours as estimate, t1.updated_on as lastEditedDate")
- ->from(REDMINE_TABLE_ISSUES)->alias('t1')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id')
- ->where('t1.tracker_id')->eq($issueType)
- ->fetchAll('id', $autoCompany = false);
-
- /* Insert into zentao */
- foreach($stories as $issueID => $story)
- {
- $storySpec->title = $story->title;
- $storySpec->spec = $story->spec;
- unset($story->id);
- unset($story->spec);
-
- /* Insert story into table story */
- $story->product = $this->map['products'][$story->product];
- $story->module = 0;
- $story->plan = $this->map['planOfProduct'][$story->product];
- $story->fromBug = 0;
- $story->pri = $priTypes['story'][$story->pri];
- $story->status = $statusTypes['story'][$story->status];
- $story->toBug = 0;
- $story->duplicateStory = 0;
- $this->dao->dbh($this->dbh)->insert(TABLE_STORY)->data($story)->exec();
- $this->map['issueID'][$issueID] = $this->dao->lastInsertID();
- $this->map['issueType'][$issueID] = 'story';
-
- /* Insert data into table storySpec */
- $storySpec->story = $this->map['issueID'][$issueID];
- $storySpec->version = 1;
- $this->dao->dbh($this->dbh)->insert(TABLE_STORYSPEC)->data($storySpec)->exec();
- }
- self::$convertStoryCount += count($stories);
- }
-
- /**
- * convert task
- *
- * @param array $issueType
- * @param array $statusTypes
- * @param array $priTypes
- * @access public
- * @return void
- */
- public function convertTask($issueType, $statusTypes, $priTypes)
- {
- /* Get task list */
- $tasks = $this->dao->dbh($this->sourceDBH)
- ->select("t1.id, t1.project_id as product, t1.fixed_version_id as project, t1.subject as name, t1.description as `desc`, t1.due_date as deadline, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.estimated_hours as estimate, t1.updated_on as lastEditedDate")
- ->from(REDMINE_TABLE_ISSUES)->alias('t1')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id')
- ->where('t1.tracker_id')->eq($issueType)
- ->fetchAll('id', $autoCompany = false);
-
- /* Insert into zentao */
- foreach($tasks as $issueID => $task)
- {
- $task->story = 0;
- $task->storyVersion = 0;
- $task->type = 'misc';
- $task->pri = $priTypes['task'][$task->pri];
- $task->status = $statusTypes['task'][$task->status];
- if($task->project == 0)
- {
- $task->project = $this->map['projectOfProduct'][$task->product];
- }
- else
- {
- $task->project = $this->map['project'][$task->project];
- }
- unset($task->id);
- unset($task->product);
- $this->dao->dbh($this->dbh)->insert(TABLE_TASK)->data($task)->exec();
- $this->map['issueID'][$issueID] = $this->dao->lastInsertID();
- $this->map['issueType'][$issueID] = 'task';
- }
- self::$convertTaskCount += count($tasks);
- }
-
- /**
- * convert bug
- *
- * @param array $issueType
- * @param array $statusTypes
- * @param array $priTypes
- * @access public
- * @return void
- */
- public function convertBug($issueType, $statusTypes, $priTypes)
- {
- /* Get bug list */
- $bugs = $this->dao->dbh($this->sourceDBH)
- ->select("t1.id, t1.project_id as product, t1.fixed_version_id project, t1.subject as title, t1.description as steps, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.updated_on as lastEditedDate")
- ->from(REDMINE_TABLE_ISSUES)->alias('t1')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id')
- ->where('t1.tracker_id')->eq($issueType)
- ->fetchAll('id', $autoCompany = false);
-
- /* Insert into zentao */
- foreach($bugs as $issueID => $bug)
- {
- $bug->product = $this->map['products'][$bug->product];
- $bug->module = 0;
- $bug->story = 0;
- $bug->storyVersion = 1;
- $bug->task = 0;
- $bug->severity = 3;
- $bug->type = 'others';
- $bug->status = $statusTypes['bug'][$bug->status];
- $bug->openedBuild = 'trunk';
- $bug->duplicateBug = 0;
- $bug->case = 0;
- $bug->caseVersion = 1;
- $bug->result = 0;
- if($bug->project == 0)
- {
- $bug->project = $this->map['projectOfProduct'][$bug->product];
- }
- else
- {
- $bug->project = $this->map['project'][$bug->project];
- }
- unset($bug->id);
- $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec();
- $this->map['issueID'][$issueID] = $this->dao->lastInsertID();
- $this->map['issueType'][$issueID] = 'bug';
- }
- self::$convertBugCount += count($bugs);
- }
-
- /**
- * Convert attachments.
- *
- * @access public
- * @return void
- */
- public function convertFile()
- {
- $this->setPath();
-
- /* Get file list */
- $files = $this->dao->dbh($this->sourceDBH)
- ->select('t1.id, t1.container_id as objectID, t1.container_type as objectType, t1.filename as title, t1.disk_filename as pathname, t1.filesize as size, t2.login as addedBy, t1.created_on as addedDate, description')
- ->from(REDMINE_TABLE_ATTACHMENTS)->alias('t1')
- ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.author_id = t2.id')
- ->fetchAll('id', $autoCompany = false);
-
- /* Insert into zentao */
- foreach($files as $fileID => $file)
- {
- if($file->description != '')
- {
- $file->title = $file->description;
- unset($file->description);
- }
- else
- {
- unset($file->description);
- }
-
- /* Transform objectType and objectID */
- if($file->objectType == 'Issue')
- {
- $file->objectType = $this->map['issueType'][$file->objectID];
- $file->objectID = $this->map['issueID'][$file->objectID];
- }
- elseif($file->objectType == 'Document')
- {
- $file->objectType = 'doc' ;
- $file->objectID = $this->map['docs'][$file->objectID];
- }
- elseif($file->objectType == 'WikiPage')
- {
- continue;
- }
- elseif($file->objectType == 'Version')
- {
- $doc->project = $this->map['project'][$file->objectID];
- $doc = $this->dao->dbh($this->dbh)->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($doc->project)->fetch();
- $doc->lib = 'project';
- $doc->module = 0;
- $doc->title = $file->title;
- $doc->type = 'file';
- $doc->addedBy = $file->addedBy;
- $doc->addedDate = $file->addedDate;
- $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($doc)->exec();
- self::$convertDocCount += 1;
-
- $file->objectType = 'doc';
- $file->objectID = $this->dao->lastInsertID();
- }
-
- $pathname = pathinfo($file->pathname);
- $file->extension = $pathname["extension"];
- unset($file->id);
-
- /* Insert into database. */
- $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec();
-
- /* Copy file. */
- $soureFile = $this->filePath . $file->pathname;
- if(!file_exists($soureFile))
- {
- self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile);
- continue;
- }
- $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname;
- $targetPath = dirname($targetFile);
- if(!is_dir($targetPath)) mkdir($targetPath, 0777, true);
- if(!copy($soureFile, $targetFile))
- {
- self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile);
- }
- }
- self::$convertFileCount += count($files);
- }
-
- /**
- * Clear the converted records.
- *
- * @access public
- * @return void
- */
- public function clear()
- {
- foreach($this->session->state as $table => $maxID)
- {
- $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec();
- }
- }
-}
+
+ * @package convert
+ * @version $Id $
+ * @link http://www.zentao.net
+ */
+class redmine11ConvertModel extends redmineConvertModel
+{
+ static $convertGroupCount = 0;
+ static $convertUserCount = 0;
+ static $convertProductCount = 0;
+ static $convertProjectCount = 0;
+ static $convertStoryCount = 0;
+ static $convertTaskCount = 0;
+ static $convertBugCount = 0;
+ static $convertProductPlanCount = 0;
+ static $convertTeamCount = 0;
+ static $convertReleaseCount = 0;
+ static $convertBuildCount = 0;
+ static $convertDocLibCount = 0;
+ static $convertDocCount = 0;
+ static $convertFileCount = 0;
+ public $issueType;
+
+ public function __construct($issueType)
+ {
+ parent::__construct();
+ $this->issueType = $issueType;
+ }
+ /**
+ * Execute the converter.
+ *
+ * @access public
+ * @return array
+ */
+ public function execute()
+ {
+ $this->clear();
+ $this->setTable();
+ $this->convertGroup();
+ $this->convertUser();
+ $this->convertUserGroup();
+ $this->convertProduct();
+ $this->convertProject();
+ $this->convertBuildAndRelease();
+ $this->convertProductPlan();
+ $this->convertProjectProduct();
+ $this->convertTeam();
+ $this->convertDocLib();
+ $this->convertDoc();
+ $this->convertNews();
+ $this->convertIssue();
+ $this->convertFile();
+ $this->dao->dbh($this->dbh);
+ $this->loadModel('tree')->fixModulePath();
+
+ $result['groups'] = self::$convertGroupCount;
+ $result['users'] = self::$convertUserCount ;
+ $result['products'] = self::$convertProductCount ;
+ $result['projects'] = self::$convertProjectCount ;
+ $result['stories'] = self::$convertStoryCount;
+ $result['tasks'] = self::$convertTaskCount ;
+ $result['bugs'] = self::$convertBugCount ;
+ $result['productPlans'] = self::$convertProductPlanCount;
+ $result['teams'] = self::$convertTeamCount;
+ $result['releases'] = self::$convertReleaseCount;
+ $result['builds'] = self::$convertBuildCount;
+ $result['docLibs'] = self::$convertDocLibCount ;
+ $result['docs'] = self::$convertDocCount;
+ $result['files'] = self::$convertFileCount;
+ return $result;
+ }
+
+ /**
+ * Set table names.
+ *
+ * @access public
+ * @return void
+ */
+ public function setTable()
+ {
+ //$dbPrefix = $this->post->dbPrefix;
+ $dbPrefix = '';
+ define('REDMINE_TABLE_ATTACHMENTS', $dbPrefix . 'attachments');
+ define('REDMINE_TABLE_AUTH_SOURCES', $dbPrefix . 'auth_sources');
+ define('REDMINE_TABLE_BOARDS', $dbPrefix . 'boards');
+ define('REDMINE_TABLE_CHANGES', $dbPrefix . 'changes');
+ define('REDMINE_TABLE_CHANGESETS', $dbPrefix . 'changesets');
+ define('REDMINE_TABLE_CHANGESETS_ISSUES', $dbPrefix . 'changesets_issues');
+ define('REDMINE_TABLE_COMMENTS', $dbPrefix . 'comments');
+ define('REDMINE_TABLE_CUSTOM_FIELDS', $dbPrefix . 'custom_fields');
+ define('REDMINE_TABLE_CUSTOM_FIELDS_PROJECTS', $dbPrefix . 'custom_fields_projects');
+ define('REDMINE_TABLE_CUSTOM_FIELDS_TRACKERS', $dbPrefix . 'custom_fields_trackers');
+ define('REDMINE_TABLE_CUSTOM_VALUES', $dbPrefix . 'custom_values');
+ define('REDMINE_TABLE_DOCUMENTS', $dbPrefix . 'documents');
+ define('REDMINE_TABLE_ENABLED_MODULES', $dbPrefix . 'enabled_modules');
+ define('REDMINE_TABLE_ENUMERATIONS', $dbPrefix . 'enumerations');
+ define('REDMINE_TABLE_GROUPS_USERS', $dbPrefix . 'groups_users');
+ define('REDMINE_TABLE_ISSUES', $dbPrefix . 'issues');
+ define('REDMINE_TABLE_ISSUE_CATEGORIES', $dbPrefix . 'issue_categories');
+ define('REDMINE_TABLE_ISSUE_RELATIONS', $dbPrefix . 'issue_relations');
+ define('REDMINE_TABLE_ISSUE_STATUSES', $dbPrefix . 'issue_statuses');
+ define('REDMINE_TABLE_JOURNALS', $dbPrefix . 'journals');
+ define('REDMINE_TABLE_JOURNAL_DETAILS', $dbPrefix . 'journal_details');
+ define('REDMINE_TABLE_MEMBERS', $dbPrefix . 'members');
+ define('REDMINE_TABLE_MEMBER_ROLES', $dbPrefix . 'member_roles');
+ define('REDMINE_TABLE_MESSAGES', $dbPrefix . 'messages');
+ define('REDMINE_TABLE_NEWS', $dbPrefix . 'news');
+ define('REDMINE_TABLE_OPEN_ID_AUTHENTICATION_ASSOCIATIONS', $dbPrefix . 'open_id_authentication_associations');
+ define('REDMINE_TABLE_OPEN_ID_AUTHENTICATION_NONCES', $dbPrefix . 'open_id_authentication_nonces');
+ define('REDMINE_TABLE_PROJECTS', $dbPrefix . 'projects');
+ define('REDMINE_TABLE_PROJECTS_TRACKERS', $dbPrefix . 'projects_trackers');
+ define('REDMINE_TABLE_QUERIES', $dbPrefix . 'queries');
+ define('REDMINE_TABLE_REPOSITORIES', $dbPrefix . 'repositories');
+ define('REDMINE_TABLE_ROLES', $dbPrefix . 'roles');
+ define('REDMINE_TABLE_SCHEMA_MIGRATIONS', $dbPrefix . 'schema_migrations');
+ define('REDMINE_TABLE_SETTINGS', $dbPrefix . 'settings');
+ define('REDMINE_TABLE_TIME_ENTRIES', $dbPrefix . 'time_entries');
+ define('REDMINE_TABLE_TOKENS', $dbPrefix . 'tokens');
+ define('REDMINE_TABLE_TRACKERS', $dbPrefix . 'trackers');
+ define('REDMINE_TABLE_USERS', $dbPrefix . 'users');
+ define('REDMINE_TABLE_USER_PREFERENCES', $dbPrefix . 'user_preferences');
+ define('REDMINE_TABLE_VERSIONS', $dbPrefix . 'versions');
+ define('REDMINE_TABLE_WATCHERS', $dbPrefix . 'watchers');
+ define('REDMINE_TABLE_WIKIS', $dbPrefix . 'wikis');
+ define('REDMINE_TABLE_WIKI_CONTENTS', $dbPrefix . 'wiki_contents');
+ define('REDMINE_TABLE_WIKI_CONTENT_VERSIONS', $dbPrefix . 'wiki_content_versions');
+ define('REDMINE_TABLE_WIKI_PAGES', $dbPrefix . 'wiki_pages');
+ define('REDMINE_TABLE_WIKI_REDIRECTS', $dbPrefix . 'wiki_redirects');
+ define('REDMINE_TABLE_WORKFLOWS', $dbPrefix . 'workflows');
+ }
+
+ /**
+ * Convert groups.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertGroup()
+ {
+ /* Get group list */
+ $groups = $this->dao->dbh($this->sourceDBH)
+ ->select("id, lastName AS name")
+ ->from(REDMINE_TABLE_USERS)
+ ->where('type')->eq('Group')
+ ->fetchAll('id', $autoCompany = false);
+
+ $zentaoGroupNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_GROUP)->fetchPairs();
+ $zentaoGroupIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_GROUP)->fetchPairs();
+
+ /* Insert into zentao */
+ $convertCount = 0;
+ foreach($groups as $groupID =>$group)
+ {
+ unset($group->id);
+ if(in_array("$group->name", $zentaoGroupNames))
+ {
+ self::$info['groups'][] = sprintf($this->lang->convert->errorGroupExists, $group->name);
+ $this->map['groups'][$groupID] = $zentaoGroupIDs[$group->name];
+ }
+ else
+ {
+ $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)
+ ->data($group)->exec();
+ $this->map['groups'][$groupID] = $this->dao->lastInsertID();
+ $convertCount ++;
+ }
+ }
+ self::$convertGroupCount += $convertCount;
+ }
+
+ /**
+ * Convert users.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertUser()
+ {
+ /* Get user list. */
+ $users = $this->dao->dbh($this->sourceDBH)
+ ->select("id, login AS account, firstname, lastname, mail as email")
+ ->from(REDMINE_TABLE_USERS)
+ ->where('type')->eq('User')
+ ->fetchAll('id', $autoCompany = false);
+
+ $zentaoUserNames = $this->dao->dbh($this->dbh)->select('id, account')->from(TABLE_USER)->fetchPairs();
+ $zentaoUserIDs = $this->dao->dbh($this->dbh)->select('account, id')->from(TABLE_USER)->fetchPairs();
+
+ /* Insert into zentao. */
+ $convertCount = 0;
+ foreach($users as $id => $user)
+ {
+ if(in_array("$user->account", $zentaoUserNames))
+ {
+ self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $user->account);
+ $this->map['users'][$id] = $zentaoUserIDs[$user->account];
+ }
+ else
+ {
+ $user->password = md5('123456');
+ $user->realname = $user->lastname . $user->firstname;
+ unset($user->id);
+ unset($user->lastname);
+ unset($user->firstname);
+ $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec();
+ $this->map['users'][$id] = $this->dao->lastInsertID();
+ $convertCount ++;
+ }
+ }
+ self::$convertUserCount += $convertCount;
+ }
+
+ /**
+ * convert relationship between user and group.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertUserGroup()
+ {
+ $this->map['groups'][0] = 0;
+ /* Get relation between user and group list. */
+ $userGroups = $this->dao->dbh($this->sourceDBH)
+ ->select("t1.group_id, t2.login as account")
+ ->from(REDMINE_TABLE_GROUPS_USERS)->alias('t1')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.user_id = t2.id')
+ ->fetchAll('', $autoCompany = false);
+
+ $zentaoUserGroups = $this->dao->dbh($this->dbh)->select('*')->from(TABLE_USERGROUP)->fetchAll();
+
+ /* Insert into zentao. */
+ $userGroupExist = false;
+ foreach($userGroups as $userGroup)
+ {
+ $userGroup->group = $this->map['groups'][$userGroup->group_id];
+ unset($userGroup->group_id);
+ foreach($zentaoUserGroups as $zentaoUserGroup)
+ {
+ if($userGroup->group == $zentaoUserGroup->group and $userGroup->account == $zentaoUserGroup->account)
+ {
+ $userGroupExist = true;
+ }
+ }
+ if($userGroupExist == false)
+ {
+ $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)->data($userGroup)->exec();
+ }
+ }
+ }
+
+ /**
+ * convert products.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertProduct()
+ {
+ /* Get product list */
+ $products = $this->dao->dbh($this->sourceDBH)
+ ->select("id, name, description as `desc`, created_on as createdDate")
+ ->from(REDMINE_TABLE_PROJECTS)
+ ->fetchAll('id', $autoComapny = false);
+
+ /* Insert into zentao */
+ foreach($products as $productID => $product)
+ {
+ unset($product->id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($product)->exec();
+ $this->map['products'][$productID] = $this->dao->lastInsertID();
+ }
+ self::$convertProductCount += count($products);
+ }
+
+ /**
+ * Convert projects.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertProject()
+ {
+ /* Get project list */
+ $projects = $this->dao->dbh($this->sourceDBH)
+ ->select("id, name, project_id, description as `desc`, effective_date AS end")
+ ->from(REDMINE_TABLE_VERSIONS)
+ ->fetchAll('id', $autoComapny = false);
+
+ /* Insert into zentao */
+ foreach($projects as $projectID => $project)
+ {
+ $productID = $project->project_id;
+ unset($project->id);
+ unset($project->project_id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_PROJECT)->data($project)->exec();
+ $this->map['projects'][$productID][$projectID] = $this->dao->lastInsertID();
+ $this->map['project'][$projectID] = $this->map['projects'][$productID][$projectID];
+ }
+
+ /* Create a same name project with product */
+ foreach($this->map['products'] as $productID)
+ {
+ $project = $this->dao->dbh($this->dbh)->select('name')->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch();
+ $this->dao->dbh($this->dbh)->insert(TABLE_PROJECT)->data($project)->exec();
+ $this->map['projectOfProduct'][$productID] = $this->dao->lastinsertID();
+ }
+ $convertCount = count($projects) + count($this->map['projectOfProduct']);
+ self::$convertProjectCount += $convertCount;
+ }
+
+ /**
+ * convert builds and releases
+ *
+ * @access public
+ * @return void
+ */
+ public function convertBuildAndRelease()
+ {
+ /* Get build list */
+ $buildAndReleases = $this->dao->dbh($this->sourceDBH)
+ ->select("id, name, project_id, description as `desc`, effective_date AS date")
+ ->from(REDMINE_TABLE_VERSIONS)
+ ->fetchAll('id', $autoCompany = false);
+
+ /* Insert into zentao */
+ $convertBuildsCount = 0;
+ $convertReleasesCount = 0;
+ $zentaoBuildNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_BUILD)->fetchPairs();
+ $zentaoBuildIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_BUILD)->fetchPairs();
+ $zentaoReleaseNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_RELEASE)->fetchPairs();
+ $zentaoReleaseIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_RELEASE)->fetchPairs();
+ foreach($buildAndReleases as $id => $buildAndRelease)
+ {
+ $buildAndRelease->project = $this->map['project'][$id];
+ $buildAndRelease->product = $this->map['products'][$buildAndRelease->project_id];
+ unset($buildAndRelease->id);
+ unset($buildAndRelease->project_id);
+
+ if(in_array($buildAndRelease->name, $zentaoBuildNames))
+ {
+ self::$info['builds'][] = sprintf($this->lang->convert->errorBuildExists, $buildAndRelease->name);
+ $buildAndRelease->build = $zentaoBuildIDs[$buildAndRelease->name];
+ }
+ else
+ {
+ $this->dao->dbh($this->dbh)->insert(TABLE_BUILD)->data($buildAndRelease)->exec();
+ $buildAndRelease->build = $this->dao->lastInsertID();
+ $convertBuildsCount ++;
+ }
+
+ unset($buildAndRelease->project);
+ if(in_array($buildAndRelease->name, $zentaoBuildNames))
+ {
+ self::$info['releases'][] = sprintf($this->lang->convert->errorReleaseExists, $buildAndRelease->name);
+ }
+ else
+ {
+ $this->dao->dbh($this->dbh)->insert(TABLE_RELEASE)->data($buildAndRelease)->exec();
+ $convertReleasesCount ++;
+ }
+ }
+ self::$convertBuildCount += $convertBuildsCount;
+ self::$convertReleaseCount += $convertReleasesCount;
+ }
+
+ /**
+ * convert productPlans
+ *
+ * @access public
+ * @return void
+ */
+ public function convertProductPlan()
+ {
+ /* Get productPlan list */
+ $productPlans = $this->dao->dbh($this->sourceDBH)
+ ->select("id, name as title, project_id, description as `desc`, effective_date as end, created_on AS begin")
+ ->from(REDMINE_TABLE_VERSIONS)
+ ->fetchAll('id', $autoCompany = false);
+ /* Insert into zentao */
+ foreach($productPlans as $id => $productPlan)
+ {
+ $productPlan->product = $this->map['products'][$productPlan->project_id];
+ unset($productPlan->id);
+ unset($productPlan->project_id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec();
+ }
+
+ /* Create a same plan with product */
+ foreach($this->map['products'] as $productID)
+ {
+ $productPlan = $this->dao->dbh($this->dbh)->select("name as title, createdDate as begin")->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch();
+ $productPlan->product = $productID;
+ $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec();
+ $this->map['planOfProduct'][$productID] = $this->dao->lastinsertID();
+ }
+ $convertCount = count($this->map['products']) + count($productPlans);
+ self::$convertProductPlanCount += $convertCount;
+ }
+
+ /**
+ * convert relationship between project and product.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertProjectProduct()
+ {
+ foreach($this->map['projects'] as $productID => $projects)
+ {
+ foreach($projects as $projectID => $project)
+ {
+ $this->dao->dbh($this->dbh)->insert(TABLE_PROJECTPRODUCT)
+ ->set('project')->eq($project)
+ ->set('product')->eq($this->map['products'][$productID])
+ ->exec();
+ }
+ }
+ }
+
+ /**
+ * convert teams.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertTeam()
+ {
+ /* Get team list */
+ $teams = $this->dao->dbh($this->sourceDBH)
+ ->select("t2.login as account, t1.project_id, t1.created_on AS joinDate")
+ ->from(REDMINE_TABLE_MEMBERS)->alias('t1')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.user_id = t2.id')
+ ->where('t2.type')->eq('User')
+ ->fetchAll('', $autoCompany = false);
+
+ /* Insert into zentao */
+ foreach($teams as $team)
+ {
+ $productID = $team->project_id;
+ unset($team->project_id);
+ foreach($this->map['projects'][$productID] as $projectID)
+ {
+ $team->project = $projectID;
+ $this->dao->dbh($this->dbh)->insert(TABLE_TEAM)->data($team)->exec();
+ }
+ }
+ self::$convertTeamCount += count($teams);
+ }
+
+ /**
+ * convert docLibs.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertDocLib()
+ {
+ /* Get docLib list */
+ $docLibs = $this->dao->dbh($this->sourceDBH)
+ ->select("id, name")->from(REDMINE_TABLE_ENUMERATIONS)
+ ->where('type')->eq('DocumentCategory')
+ ->fetchAll('id', $autoCompany = false);
+
+ /* Insert into zentao */
+ foreach($docLibs as $docLibID => $docLib)
+ {
+ unset($docLib->id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_DOCLIB)->data($docLib)->exec();
+ $this->map['docLibs'][$docLibID] = $this->dao->lastInsertID();
+ }
+ self::$convertDocLibCount += count($docLibs);
+ }
+
+ /**
+ * convert docs.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertDoc()
+ {
+ /* Get all docs */
+ $docs = $this->dao->dbh($this->sourceDBH)
+ ->select("t1.id, t1.project_id AS product, t2.id AS lib, t1.title, t1.description AS content, t1.created_on AS addedDate")
+ ->from(REDMINE_TABLE_DOCUMENTS)->alias('t1')
+ ->leftjoin(REDMINE_TABLE_ENUMERATIONS)->alias('t2')->on('t1.category_id = t2.id')
+ ->fetchAll('id', $autoCompany = false);
+
+ /* Insert into zentao */
+ foreach($docs as $docID => $doc)
+ {
+ unset($doc->id);
+ $doc->type = 'text';
+ $doc->project = 0;
+ $doc->product = $this->map['products'][$doc->product];
+ $doc->lib = $this->map['docLibs'][$doc->lib];
+ $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($doc)->exec();
+ $this->map['docs'][$docID] = $this->dao->lastInsertID();
+ }
+ self::$convertDocCount += count($docs);
+ }
+
+ /**
+ * convert news.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertNews()
+ {
+ /* Get news from redmine */
+ $news = $this->dao->dbh($this->sourceDBH)
+ ->select("t1.project_id as product, t1.title, t1.summary as digest, t1.description as content, t2.login as addedBy, t1.created_on as addedDate")
+ ->from(REDMINE_TABLE_NEWS)->alias('t1')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.author_id = t2.id')
+ ->fetchAll('', $autoCompany = false);
+
+ /* Create a news docLib */
+ $newLib->name = 'news';
+ $this->dao->dbh($this->dbh)->insert(TABLE_DOCLIB)->data($newLib)->exec();
+ $this->map['news'] = $this->dao->lastInsertID();
+ self::$convertDocLibCount += 1;
+
+ /* Insert into zentao */
+ foreach($news as $new)
+ {
+ $new->product = $this->map['products'][$new->product];
+ $new->project = 0;
+ $new->lib = $this->map['news'];
+ $new->type = 'text';
+
+ $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($new)->exec();
+ }
+ self::$convertDocCount += count($news);
+ }
+
+ /**
+ * convert issue
+ *
+ * @param array $aimTypes //aimTypes['issueTypeID'] = aimtype eg. aimTypes[1] = 'bug';
+ * @param array $statusTypes //statusTypes['task']['statusTypeID'] = statusType eg. statusTypes['task'][1] = 'wait';
+ * //statusTypes['bug']['statusTypeID'] = statusType eg. statusTypes['bug'][1] = 'active';
+ * @param array $priTypes //priTypes['task']['priTypeID'] = priType; eg. priTypes['task'][1] = 1;
+ * @access public
+ * @return void
+ */
+ public function convertIssue()
+ {
+ $aimTypes = $this->issueType->aimTypes;
+ $statusTypes = $this->issueType->statusTypes;
+ $priTypes = $this->issueType->priTypes;
+
+ foreach($aimTypes as $issueType => $aimType)
+ {
+ if('story' == $aimType)
+ {
+ $this->convertStory($issueType, $statusTypes, $priTypes);
+ }
+ elseif('task' == $aimType)
+ {
+ $this->convertTask($issueType, $statusTypes, $priTypes);
+ }
+ else
+ {
+ $this->convertBug($issueType, $statusTypes, $priTypes);
+ }
+ }
+ }
+
+ /**
+ * convert story
+ *
+ * @param array $issueType
+ * @param array $statusTypes
+ * @param array $priTypes
+ * @access public
+ * @return void
+ */
+ public function convertStory($issueType, $statusTypes, $priTypes)
+ {
+ /* Get story list*/
+ $stories = $this->dao->dbh($this->sourceDBH)
+ ->select("t1.id, t1.project_id as product, t1.subject as title, t1.description as spec, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.estimated_hours as estimate, t1.updated_on as lastEditedDate")
+ ->from(REDMINE_TABLE_ISSUES)->alias('t1')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id')
+ ->where('t1.tracker_id')->eq($issueType)
+ ->fetchAll('id', $autoCompany = false);
+
+ /* Insert into zentao */
+ foreach($stories as $issueID => $story)
+ {
+ $storySpec->title = $story->title;
+ $storySpec->spec = $story->spec;
+ unset($story->id);
+ unset($story->spec);
+
+ /* Insert story into table story */
+ $story->product = $this->map['products'][$story->product];
+ $story->module = 0;
+ $story->plan = $this->map['planOfProduct'][$story->product];
+ $story->fromBug = 0;
+ $story->pri = $priTypes['story'][$story->pri];
+ $story->status = $statusTypes['story'][$story->status];
+ $story->toBug = 0;
+ $story->duplicateStory = 0;
+ $this->dao->dbh($this->dbh)->insert(TABLE_STORY)->data($story)->exec();
+ $this->map['issueID'][$issueID] = $this->dao->lastInsertID();
+ $this->map['issueType'][$issueID] = 'story';
+
+ /* Insert data into table storySpec */
+ $storySpec->story = $this->map['issueID'][$issueID];
+ $storySpec->version = 1;
+ $this->dao->dbh($this->dbh)->insert(TABLE_STORYSPEC)->data($storySpec)->exec();
+ }
+ self::$convertStoryCount += count($stories);
+ }
+
+ /**
+ * convert task
+ *
+ * @param array $issueType
+ * @param array $statusTypes
+ * @param array $priTypes
+ * @access public
+ * @return void
+ */
+ public function convertTask($issueType, $statusTypes, $priTypes)
+ {
+ /* Get task list */
+ $tasks = $this->dao->dbh($this->sourceDBH)
+ ->select("t1.id, t1.project_id as product, t1.fixed_version_id as project, t1.subject as name, t1.description as `desc`, t1.due_date as deadline, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.estimated_hours as estimate, t1.updated_on as lastEditedDate")
+ ->from(REDMINE_TABLE_ISSUES)->alias('t1')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id')
+ ->where('t1.tracker_id')->eq($issueType)
+ ->fetchAll('id', $autoCompany = false);
+
+ /* Insert into zentao */
+ foreach($tasks as $issueID => $task)
+ {
+ $task->story = 0;
+ $task->storyVersion = 0;
+ $task->type = 'misc';
+ $task->pri = $priTypes['task'][$task->pri];
+ $task->status = $statusTypes['task'][$task->status];
+ if($task->project == 0)
+ {
+ $task->project = $this->map['projectOfProduct'][$task->product];
+ }
+ else
+ {
+ $task->project = $this->map['project'][$task->project];
+ }
+ unset($task->id);
+ unset($task->product);
+ $this->dao->dbh($this->dbh)->insert(TABLE_TASK)->data($task)->exec();
+ $this->map['issueID'][$issueID] = $this->dao->lastInsertID();
+ $this->map['issueType'][$issueID] = 'task';
+ }
+ self::$convertTaskCount += count($tasks);
+ }
+
+ /**
+ * convert bug
+ *
+ * @param array $issueType
+ * @param array $statusTypes
+ * @param array $priTypes
+ * @access public
+ * @return void
+ */
+ public function convertBug($issueType, $statusTypes, $priTypes)
+ {
+ /* Get bug list */
+ $bugs = $this->dao->dbh($this->sourceDBH)
+ ->select("t1.id, t1.project_id as product, t1.fixed_version_id project, t1.subject as title, t1.description as steps, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.updated_on as lastEditedDate")
+ ->from(REDMINE_TABLE_ISSUES)->alias('t1')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id')
+ ->where('t1.tracker_id')->eq($issueType)
+ ->fetchAll('id', $autoCompany = false);
+
+ /* Insert into zentao */
+ foreach($bugs as $issueID => $bug)
+ {
+ $bug->product = $this->map['products'][$bug->product];
+ $bug->module = 0;
+ $bug->story = 0;
+ $bug->storyVersion = 1;
+ $bug->task = 0;
+ $bug->severity = 3;
+ $bug->type = 'others';
+ $bug->status = $statusTypes['bug'][$bug->status];
+ $bug->openedBuild = 'trunk';
+ $bug->duplicateBug = 0;
+ $bug->case = 0;
+ $bug->caseVersion = 1;
+ $bug->result = 0;
+ if($bug->project == 0)
+ {
+ $bug->project = $this->map['projectOfProduct'][$bug->product];
+ }
+ else
+ {
+ $bug->project = $this->map['project'][$bug->project];
+ }
+ unset($bug->id);
+ $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec();
+ $this->map['issueID'][$issueID] = $this->dao->lastInsertID();
+ $this->map['issueType'][$issueID] = 'bug';
+ }
+ self::$convertBugCount += count($bugs);
+ }
+
+ /**
+ * Convert attachments.
+ *
+ * @access public
+ * @return void
+ */
+ public function convertFile()
+ {
+ $this->setPath();
+
+ /* Get file list */
+ $files = $this->dao->dbh($this->sourceDBH)
+ ->select('t1.id, t1.container_id as objectID, t1.container_type as objectType, t1.filename as title, t1.disk_filename as pathname, t1.filesize as size, t2.login as addedBy, t1.created_on as addedDate, description')
+ ->from(REDMINE_TABLE_ATTACHMENTS)->alias('t1')
+ ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.author_id = t2.id')
+ ->fetchAll('id', $autoCompany = false);
+
+ /* Insert into zentao */
+ foreach($files as $fileID => $file)
+ {
+ if($file->description != '')
+ {
+ $file->title = $file->description;
+ unset($file->description);
+ }
+ else
+ {
+ unset($file->description);
+ }
+
+ /* Transform objectType and objectID */
+ if($file->objectType == 'Issue')
+ {
+ $file->objectType = $this->map['issueType'][$file->objectID];
+ $file->objectID = $this->map['issueID'][$file->objectID];
+ }
+ elseif($file->objectType == 'Document')
+ {
+ $file->objectType = 'doc' ;
+ $file->objectID = $this->map['docs'][$file->objectID];
+ }
+ elseif($file->objectType == 'WikiPage')
+ {
+ continue;
+ }
+ elseif($file->objectType == 'Version')
+ {
+ $doc->project = $this->map['project'][$file->objectID];
+ $doc = $this->dao->dbh($this->dbh)->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($doc->project)->fetch();
+ $doc->lib = 'project';
+ $doc->module = 0;
+ $doc->title = $file->title;
+ $doc->type = 'file';
+ $doc->addedBy = $file->addedBy;
+ $doc->addedDate = $file->addedDate;
+ $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($doc)->exec();
+ self::$convertDocCount += 1;
+
+ $file->objectType = 'doc';
+ $file->objectID = $this->dao->lastInsertID();
+ }
+
+ $pathname = pathinfo($file->pathname);
+ $file->extension = $pathname["extension"];
+ unset($file->id);
+
+ /* Insert into database. */
+ $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec();
+
+ /* Copy file. */
+ $soureFile = $this->filePath . $file->pathname;
+ if(!file_exists($soureFile))
+ {
+ self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile);
+ continue;
+ }
+ $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname;
+ $targetPath = dirname($targetFile);
+ if(!is_dir($targetPath)) mkdir($targetPath, 0777, true);
+ if(!copy($soureFile, $targetFile))
+ {
+ self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile);
+ }
+ }
+ self::$convertFileCount += count($files);
+ }
+
+ /**
+ * Clear the converted records.
+ *
+ * @access public
+ * @return void
+ */
+ public function clear()
+ {
+ foreach($this->session->state as $table => $maxID)
+ {
+ $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec();
+ }
+ }
+}
diff --git a/module/convert/lang/en.php b/module/convert/lang/en.php
index 3e5e6d34d9..9765c29932 100644
--- a/module/convert/lang/en.php
+++ b/module/convert/lang/en.php
@@ -1,109 +1,109 @@
-
- * @package convert
- * @version $Id$
- * @link http://www.zentao.net
- */
-$lang->convert->common = 'Import';
-$lang->convert->next = 'Next';
-$lang->convert->pre = 'Back';
-$lang->convert->reload = 'Reload';
-$lang->convert->error = 'Error ';
-
-$lang->convert->start = 'Begin import';
-$lang->convert->desc = <<Welcome to use this convert wizard which will help you to import other system data to ZenTaoPMS.