diff --git a/api/v1/entries/execution.php b/api/v1/entries/execution.php
index 534b70d98f..4134a3c3d3 100644
--- a/api/v1/entries/execution.php
+++ b/api/v1/entries/execution.php
@@ -36,7 +36,7 @@ class executionEntry extends Entry
if(!$fields) $this->send(200, $execution);
/* Set other fields. */
- $fields = explode(',', $fields);
+ $fields = explode(',', strtolower($fields));
foreach($fields as $field)
{
switch($field)
@@ -50,6 +50,19 @@ class executionEntry extends Entry
$execution->modules = $data->data->tree;
}
break;
+ case 'moduleoptionmenu':
+ $execution->moduleOptionMenu = $this->loadModel('tree')->getTaskOptionMenu($executionID, 0, 0, 'allModule');
+ break;
+ case 'members':
+ $execution->members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');;
+ unset($execution->members['']);
+ break;
+ case 'stories':
+ $stories = $this->loadModel('story')->getExecutionStories($executionID);
+ foreach($stories as $storyID => $story) $stories[$storyID] = $this->filterFields($story, 'id,title,module,pri,status,stage,estimate');
+
+ $execution->stories = array_values($stories);
+ break;
}
}
diff --git a/api/v1/entries/executions.php b/api/v1/entries/executions.php
index 41de1524eb..594f5722cd 100644
--- a/api/v1/entries/executions.php
+++ b/api/v1/entries/executions.php
@@ -20,8 +20,10 @@ class executionsEntry extends entry
*/
public function get($projectID = 0)
{
+ $appendFields = $this->param('fields', '');
+
$control = $this->loadController('execution', 'all');
- $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
+ $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1));
$data = $this->getData();
if(isset($data->status) and $data->status == 'success')
@@ -30,6 +32,7 @@ class executionsEntry extends entry
$result = array();
foreach($data->data->executionStats as $execution)
{
+ $execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields);
$result[] = $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'executions' => $result));
diff --git a/api/v1/entries/file.php b/api/v1/entries/file.php
new file mode 100644
index 0000000000..b69ed0539d
--- /dev/null
+++ b/api/v1/entries/file.php
@@ -0,0 +1,28 @@
+
+ * @package entries
+ * @version 1
+ * @link http://www.zentao.net
+ */
+class fileEntry extends Entry
+{
+ /**
+ * PUT method.
+ *
+ * @access public
+ * @return void
+ */
+ public function put($fileID)
+ {
+ $uid = $this->param('uid', '');
+ $action = $this->param('action', '');
+ if($action == 'remove') unset($_SESSION['album']['used'][$uid][$fileID]);
+
+ $this->send(200, array('id' => $fileID));
+ }
+}
diff --git a/api/v1/entries/files.php b/api/v1/entries/files.php
new file mode 100644
index 0000000000..17faf9f28f
--- /dev/null
+++ b/api/v1/entries/files.php
@@ -0,0 +1,37 @@
+
+ * @package entries
+ * @version 1
+ * @link http://www.zentao.net
+ */
+class filesEntry extends Entry
+{
+ /**
+ * POST method.
+ *
+ * @access public
+ * @return void
+ */
+ public function post()
+ {
+ $uid = $this->param('uid', '');
+
+ $control = $this->loadController('file', 'ajaxUpload');
+ $control->ajaxUpload($uid);
+
+ $data = $this->getData();
+
+ if(!$data or !isset($data->status)) return $this->send400('error');
+ if(isset($data->status) and $data->status == 'error')
+ {
+ return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message);
+ }
+
+ $this->send(200, array('id' => $data->id));
+ }
+}
diff --git a/api/v1/entries/langs.php b/api/v1/entries/langs.php
new file mode 100644
index 0000000000..a29ee1b0f8
--- /dev/null
+++ b/api/v1/entries/langs.php
@@ -0,0 +1,51 @@
+
+ * @package entries
+ * @version 1
+ * @link http://www.zentao.net
+ */
+class langsEntry extends entry
+{
+ /**
+ * GET method.
+ *
+ * @access public
+ * @return void
+ */
+ public function get()
+ {
+ $modules = $this->param('modules', '');
+ $language = $this->param('lang', '');
+
+ if($language and !isset($this->config->langs[$language])) return $this->sendError(400, 'Error lang parameter');
+ if(empty($modules)) return $this->sendError(400, 'Need modules');
+
+ if(empty($language)) $language = 'zh-cn';
+ $this->app->setClientLang($language);
+
+ $modules = explode(',', $modules);
+ foreach($modules as $module)
+ {
+ if($module == 'all')
+ {
+ foreach(glob($this->app->getModuleRoot() . '*') as $modulePath)
+ {
+ if(!is_dir($modulePath)) continue;
+
+ $moduleName = basename($modulePath);
+ $this->app->loadLang($moduleName);
+ }
+ break;
+ }
+
+ $this->app->loadLang($module);
+ }
+
+ return $this->send(200, $this->lang);
+ }
+}
diff --git a/api/v1/entries/program.php b/api/v1/entries/program.php
index f423487ef4..17a023d90b 100644
--- a/api/v1/entries/program.php
+++ b/api/v1/entries/program.php
@@ -9,6 +9,6 @@
* @version 1
* @link http://www.zentao.net
*/
-class ProgramEntry extends Entry
+class programEntry extends Entry
{
}
diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php
index 77f9c45f28..4ff7ba360f 100644
--- a/api/v1/entries/projects.php
+++ b/api/v1/entries/projects.php
@@ -21,6 +21,7 @@ class projectsEntry extends entry
public function get($programID = 0)
{
if(!$programID) $programID = $this->param('program', 0);
+ $appendFields = $this->param('fields', '');
$control = $this->loadController('project', 'browse');
$control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1));
@@ -32,6 +33,7 @@ class projectsEntry extends entry
$result = array();
foreach($data->data->projectStats as $project)
{
+ $project = $this->filterFields($project, 'id,name,code,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields);
$result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time');
}
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result));
@@ -57,6 +59,7 @@ class projectsEntry extends entry
$fields = 'name,begin,end,products';
$this->batchSetPost($fields);
+ $this->setPost('code', $this->request('code', ''));
$this->setPost('acl', $this->request('acl', 'private'));
$this->setPost('parent', $this->request('program', 0));
$this->setPost('whitelist', $this->request('whitelist', array()));
@@ -64,7 +67,7 @@ class projectsEntry extends entry
$this->setPost('model', $this->request('model', 'scrum'));
$control = $this->loadController('project', 'create');
- $this->requireFields('name,begin,end,products');
+ $this->requireFields('name,code,begin,end,products');
$control->create($this->request('model', 'scrum'));
diff --git a/api/v1/entries/tabs.php b/api/v1/entries/tabs.php
new file mode 100644
index 0000000000..0448b012e9
--- /dev/null
+++ b/api/v1/entries/tabs.php
@@ -0,0 +1,45 @@
+
+ * @package entries
+ * @version 1
+ * @link http://www.zentao.net
+ */
+class tabsEntry extends baseEntry
+{
+ /**
+ * Get tabs.
+ *
+ * @param string $moduleName work|
+ * @access public
+ * @return void
+ */
+ public function get($moduleName)
+ {
+ $menus = array();
+ if($moduleName == 'work')
+ {
+ $this->app->loadLang('my');
+ $tabs = array('calendar', 'task', 'bug', 'story', 'issue', 'risk', 'myMeeting');
+
+ foreach($tabs as $menuKey)
+ {
+ if(!common::hasPriv('my', $menuKey)) continue;
+ $label = $this->lang->my->$menuKey;
+ if($menuKey == 'calendar') $label = $this->lang->my->calendarAction;
+
+ $menu = new stdclass();
+ $menu->code = $menuKey;
+ $menu->name = $label;
+
+ $menus[] = $menu;
+ }
+ }
+
+ $this->send(200, array('tabs' => $menus));
+ }
+}
diff --git a/api/v1/entries/tasks.php b/api/v1/entries/tasks.php
index 0a6b31ac07..3f04889092 100644
--- a/api/v1/entries/tasks.php
+++ b/api/v1/entries/tasks.php
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
-class tasksEntry extends entry
+class tasksEntry extends entry
{
/**
* GET method.
@@ -61,7 +61,7 @@ class tasksEntry extends entry
*/
public function post($executionID)
{
- $fields = 'name,type,assignedTo,estimate,story,parent,execution,module,pri,desc,estStarted,deadline,mailto';
+ $fields = 'name,type,assignedTo,estimate,story,execution,project,module,pri,desc,estStarted,deadline,mailto,team,teamEstimate,multiple,uid';
$this->batchSetPost($fields);
$assignedTo = $this->request('assignedTo');
@@ -71,7 +71,7 @@ class tasksEntry extends entry
$this->requireFields('name,assignedTo,type,estStarted,deadline');
$control->create($executionID, $this->request('storyID', 0), $this->request('moduleID', 0), $this->request('copyTaskID', 0), $this->request('copyTodoID', 0));
-
+
$data = $this->getData();
if(!isset($data->id)) return $this->sendError(400, $data->message);
diff --git a/api/v1/entries/todoactivate.php b/api/v1/entries/todoactivate.php
new file mode 100644
index 0000000000..fe26a2ef2a
--- /dev/null
+++ b/api/v1/entries/todoactivate.php
@@ -0,0 +1,32 @@
+
+ * @package entries
+ * @version 1
+ * @link http://www.zentao.net
+ */
+class todoActivateEntry extends Entry
+{
+ /**
+ * GET method.
+ *
+ * @param int $taskID
+ * @access public
+ * @return void
+ */
+ public function get($todoID)
+ {
+ $control = $this->loadController('todo', 'activate');
+ $control->activate($todoID);
+
+ $data = $this->getData();
+ if($data->status == 'fail') return $this->sendError(400, $data->message);
+
+ $todo = $this->loadModel('todo')->getByID($todoID);
+ $this->send(200, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time'));
+ }
+}
diff --git a/api/v1/entries/todofinish.php b/api/v1/entries/todofinish.php
new file mode 100644
index 0000000000..6d6f97339d
--- /dev/null
+++ b/api/v1/entries/todofinish.php
@@ -0,0 +1,32 @@
+
+ * @package entries
+ * @version 1
+ * @link http://www.zentao.net
+ */
+class todoFinishEntry extends Entry
+{
+ /**
+ * GET method.
+ *
+ * @param int $taskID
+ * @access public
+ * @return void
+ */
+ public function get($todoID)
+ {
+ $control = $this->loadController('todo', 'finish');
+ $control->finish($todoID);
+
+ $data = $this->getData();
+ if($data->status == 'fail') return $this->sendError(400, $data->message);
+
+ $todo = $this->loadModel('todo')->getByID($todoID);
+ $this->send(200, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time'));
+ }
+}
diff --git a/api/v1/entries/todos.php b/api/v1/entries/todos.php
index e03e26d90d..81e612c152 100644
--- a/api/v1/entries/todos.php
+++ b/api/v1/entries/todos.php
@@ -20,7 +20,7 @@ class todosEntry extends entry
public function get()
{
$control = $this->loadController('my', 'todo');
- $control->todo($this->param('date', 'all'), $this->param('user', ''), $this->param('status', 'all'), $this->param('order', 'date_desc'), 0, $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
+ $control->todo($this->param('type', 'all'), $this->param('userID', ''), $this->param('status', 'all'), $this->param('order', 'date_desc,status,begin'), $this->param('total', 0), $this->param('limit', 100), $this->param('page', 1));
$data = $this->getData();
if(!isset($data->status)) return $this->sendError(400, 'error');
@@ -63,7 +63,7 @@ class todosEntry extends entry
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
$todo = $this->loadModel('todo')->getByID($data->id);
-
+
$this->send(201, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time'));
}
}
diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php
index cc96d1349e..970f749d2f 100644
--- a/api/v1/entries/user.php
+++ b/api/v1/entries/user.php
@@ -52,12 +52,13 @@ class userEntry extends Entry
unset($profile->password);
$info->profile = $this->format($profile, 'last:time,locked:time,birthday:date,join:date');
- $info->profile->role = array('code' => $info->profile->role, 'name' => $this->lang->user->roleList[$info->profile->role]);
+ $info->profile->role = array('code' => $info->profile->role, 'name' => $this->lang->user->roleList[$info->profile->role]);
+ $info->profile->admin = strpos($this->app->company->admins, ",{$profile->account},") !== false;
if(!$fields) return $this->send(200, $info);
/* Set other fields. */
- $fields = explode(',', $fields);
+ $fields = explode(',', strtolower($fields));
$this->loadModel('my');
foreach($fields as $field)
@@ -67,13 +68,23 @@ class userEntry extends Entry
case 'product':
$info->product = array('total' => 0, 'products' => array());
- $products = $this->my->getProducts();
+ $products = $this->my->getProducts('ownbyme');
if($products)
{
$info->product['total'] = $products->allCount;
$info->product['products'] = $products->products;
}
break;
+ case 'undoneproduct':
+ $info->undoneProduct = array('total' => 0, 'products' => array());
+
+ $products = $this->my->getProducts('undone');
+ if($products)
+ {
+ $info->undoneProduct['total'] = $products->allCount;
+ $info->undoneProduct['products'] = $products->products;
+ }
+ break;
case 'project':
$info->project = array('total' => 0, 'projects' => array());
@@ -84,11 +95,26 @@ class userEntry extends Entry
$info->project['projects'] = $projects->projects;
}
break;
+ case 'execution':
+ $info->execution = array('total' => 0, 'executions' => array());
+ if(!common::hasPriv('my', 'execution')) break;
+
+ $control = $this->loadController('my', 'execution');
+ $control->execution($this->param('type', 'undone'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
+ $data = $this->getData();
+
+ if($data->status == 'success')
+ {
+ $info->execution['total'] = $data->data->pager->recTotal;
+ $info->execution['executions'] = array_values((array)$data->data->executions);
+ }
+ break;
case 'actions':
$info->actions = $this->my->getActions();
break;
case 'task':
$info->task = array('total' => 0, 'tasks' => array());
+ if(!common::hasPriv('my', 'task')) break;
$control = $this->loadController('my', 'task');
$control->task($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
@@ -97,12 +123,13 @@ class userEntry extends Entry
if($data->status == 'success')
{
$info->task['total'] = $data->data->pager->recTotal;
- $info->task['tasks'] = $data->data->tasks;
+ $info->task['tasks'] = array_values((array)$data->data->tasks);
}
break;
case 'bug':
$info->bug = array('total' => 0, 'bugs' => array());
+ if(!common::hasPriv('my', 'bug')) break;
$control = $this->loadController('my', 'bug');
$control->bug($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
@@ -110,54 +137,120 @@ class userEntry extends Entry
if($data->status == 'success')
{
+ $bugs = array();
+ foreach($data->data->bugs as $bug)
+ {
+ $status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]);
+ if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed);
+ if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed);
+ if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs);
+ $bug->status = $status;
+
+ $bugs[$bug->id] = $bug;
+ }
+
+ $storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1')
+ ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
+ ->where('t1.id')->in(array_keys($bugs))
+ ->andWhere('t1.story')->ne('0')
+ ->andWhere('t1.storyVersion != t2.version')
+ ->fetchAll();
+ foreach($storyChangeds as $bugID)
+ {
+ $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->storyChanged);
+ $bugs[$bugID]->status = $status;
+ }
+
$info->bug['total'] = $data->data->pager->recTotal;
- $info->bug['bugs'] = $data->data->bugs;
+ $info->bug['bugs'] = array_values($bugs);
}
break;
case 'todo':
$info->todo = array('total' => 0, 'todos' => array());
+ if(!common::hasPriv('my', 'todo')) break;
$control = $this->loadController('my', 'todo');
- $control->todo($this->param('date', 'all'), '', 'all', 'date_desc', 0, 0, $this->param('limit', 10), 1);
+ $control->todo($this->param('date', 'all'), '', 'all', 'date_desc', 0, 0, $this->param('limit', 5), 1);
$data = $this->getData();
if($data->status == 'success')
{
$info->todo['total'] = $data->data->pager->recTotal;
- $info->todo['todos'] = $data->data->todos;
+ $info->todo['todos'] = array_values((array)$data->data->todos);
+ }
+
+ break;
+ case 'story':
+ $info->story = array('total' => 0, 'stories' => array());
+ if(!common::hasPriv('my', 'story')) break;
+
+ $control = $this->loadController('my', 'story');
+ $control->story($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1));
+ $data = $this->getData();
+
+ if($data->status == 'success')
+ {
+ $stories = array();
+ foreach($data->data->stories as $story)
+ {
+ $story->status = array('code' => $story->status, 'name' => $this->lang->story->statusList[$story->status]);
+ $stories[$story->id] = $story;
+ }
+
+ $info->story['total'] = $data->data->pager->recTotal;
+ $info->story['stories'] = array_values($stories);
}
break;
case 'issue':
+ $info->issue = array('total' => 0, 'issues' => array());
+ if(!common::hasPriv('my', 'issue')) break;
+
if(!empty($this->config->maxVersion))
{
- $info->issue = array('total' => 0, 'issues' => array());
-
$control = $this->loadController('my', 'issue');
- $control->issue('createdBy', 'id_desc', 0, $this->param('limit', 10), 1);
+ $control->issue('createdBy', 'id_desc', 0, $this->param('limit', 5), 1);
$data = $this->getData();
if($data->status == 'success')
{
$info->issue['total'] = $data->data->pager->recTotal;
- $info->issue['issues'] = $data->data->issues;
+ $info->issue['issues'] = array_values((array)$data->data->issues);
}
}
break;
case 'risk':
+ $info->risk = array('total' => 0, 'risks' => array());
+ if(!common::hasPriv('my', 'risk')) break;
+
if(!empty($this->config->maxVersion))
{
- $info->risk = array('total' => 0, 'risks' => array());
-
$control = $this->loadController('my', 'risk');
- $control->risk('createdBy', 'id_desc', 0, $this->param('limit', 10), 1);
+ $control->risk('createdBy', 'id_desc', 0, $this->param('limit', 5), 1);
$data = $this->getData();
if($data->status == 'success')
{
$info->risk['total'] = $data->data->pager->recTotal;
- $info->risk['risks'] = $data->data->risks;
+ $info->risk['risks'] = array_values((array)$data->data->risks);
+ }
+ }
+ break;
+ case 'meeting':
+ $info->meeting = array('total' => 0, 'meetings' => array());
+ if(!common::hasPriv('my', 'myMeeting')) break;
+
+ if(!empty($this->config->maxVersion))
+ {
+ $control = $this->loadController('my', 'myMeeting');
+ $control->myMeeting('all', 'id_desc', 0, $this->param('limit', 5), 1);
+ $data = $this->getData();
+
+ if($data->status == 'success')
+ {
+ $info->meeting['total'] = $data->data->pager->recTotal;
+ $info->meeting['meetings'] = array_values((array)$data->data->meetings);
}
}
break;
@@ -167,6 +260,16 @@ class userEntry extends Entry
case 'contribute':
$info->contribute = $this->my->getContribute();
break;
+ case 'rights':
+ $inAdminGroup = $this->dao->select('t1.*')->from(TABLE_USERGROUP)->alias('t1')
+ ->leftJoin(TABLE_GROUP)->alias('t2')->on('t1.group=t2.id')
+ ->where('t1.account')->eq($info->profile->account)
+ ->andWhere('t2.role')->eq('admin')
+ ->fetch();
+
+ $info->rights = array();
+ $info->rights['admin'] = (!empty($inAdminGroup) or $this->app->user->admin);
+ $info->rights['rights'] = $this->app->user->rights['rights'];
}
}
diff --git a/api/v1/entries/users.php b/api/v1/entries/users.php
index 58dea59897..aa68973ca1 100644
--- a/api/v1/entries/users.php
+++ b/api/v1/entries/users.php
@@ -9,7 +9,7 @@
* @version 1
* @link http://www.zentao.net
*/
-class usersEntry extends entry
+class usersEntry extends entry
{
/**
* GET method.
@@ -19,22 +19,32 @@ class usersEntry extends entry
*/
public function get()
{
- $control = $this->loadController('company', 'browse');
- $control->browse('inside', 0, $this->param('type', 'bydept'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
- $data = $this->getData();
+ if(!common::hasPriv('company', 'browse')) return $this->sendError(400, 'error: no company-browse priv.');
- if(isset($data->status) and $data->status == 'success')
+ $appendFields = $this->param('fileds', '');
+ $type = $this->param('type', 'bydept');
+ $limit = (int)$this->param('limit', 20);
+
+ $pager = null;
+ if($limit)
{
- $users = $data->data->users;
- $pager = $data->data->pager;
- $result = array();
- foreach($users as $user) $result[] = $this->format($user, 'locked:time');
- return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'users' => $result));
+ $this->app->loadClass('pager', $static = true);
+ $pager = pager::init(0, $limit, $this->param('page', 1));
}
- if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
+ $users = $this->loadModel('company')->getUsers($this->param('browse', 'inside'), $type, 0, 0, $this->param('order', 'id_desc'), $pager);
+ $result = array();
+ foreach($users as $user)
+ {
+ $user = $this->filterFields($user, 'id,dept,account,realname,role,pinyin,email,' . $appendFields);
+ $result[] = $this->format($user, 'locked:time');
+ }
- return $this->sendError(400, 'error');
+ $pageID = $pager ? $pager->pageID : 1;
+ $total = $pager ? $pager->recTotal : count($result);
+ $limit = $pager ? $pager->recPerPage : $total;
+
+ return $this->send(200, array('page' => $pageID, 'total' => $total, 'limit' => $limit, 'users' => $result));
}
/**
diff --git a/config/routes.php b/config/routes.php
index c55fa34bb2..0ab76b3989 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -5,6 +5,12 @@
$routes = array();
$routes['/tokens'] = 'tokens';
+$routes['/langs'] = 'langs';
+
+$routes['/tabs/:module'] = 'tabs';
+
+$routes['/files'] = 'files';
+$routes['/files/:id'] = 'file';
$routes['/configurations'] = 'configs';
$routes['/configurations/:name'] = 'config';
@@ -62,8 +68,10 @@ $routes['/projects/:projectID/issues'] = 'issues';
$routes['/issues'] = 'issues';
$routes['/issues/:issueID'] = 'issue';
-$routes['/todos'] = 'todos';
-$routes['/todos/:id'] = 'todo';
+$routes['/todos'] = 'todos';
+$routes['/todos/:id'] = 'todo';
+$routes['/todos/:id/finish'] = 'todoFinish';
+$routes['/todos/:id/activate'] = 'todoActivate';
$routes['/projects/:projectID/builds'] = 'builds';
$routes['/builds'] = 'builds';
diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php
index 39f469e22a..7a0f698d7d 100644
--- a/framework/api/entry.class.php
+++ b/framework/api/entry.class.php
@@ -486,6 +486,8 @@ class baseEntry
$type = $field[1];
$isArray = false;
+ if(!isset($object->$key)) continue;
+
$pos = strpos($type, ']');
if($pos !== FALSE)
{
@@ -519,6 +521,31 @@ class baseEntry
}
}
+ /**
+ * Filter fields.
+ *
+ * @param object $object
+ * @param array $filters
+ * @access public
+ * @return object
+ */
+ public function filterFields($object, $allowable = '')
+ {
+ if(empty($allowable)) return $object;
+ if(is_string($allowable)) $allowable = explode(',', $allowable);
+
+ $filtered = new stdclass();
+ foreach($allowable as $field)
+ {
+ $field = trim($field);
+ if(empty($field)) continue;
+ if(!isset($object->$field)) continue;
+ $filtered->$field = $object->$field;
+ }
+
+ return $filtered;
+ }
+
/**
* 类型转换.
* Typecasting.
diff --git a/module/action/model.php b/module/action/model.php
index 7a18b7d1db..9ce593c030 100755
--- a/module/action/model.php
+++ b/module/action/model.php
@@ -69,7 +69,7 @@ class actionModel extends model
$this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec();
- $actionID = $this->dbh->lastInsertID();
+ $actionID = $this->dao->lastInsertID();
if($this->post->uid) $this->file->updateObjectID($this->post->uid, $objectID, $objectType);
diff --git a/module/block/lang/zh-cn.php b/module/block/lang/zh-cn.php
index dbd8e2ed9f..7ce129a602 100644
--- a/module/block/lang/zh-cn.php
+++ b/module/block/lang/zh-cn.php
@@ -585,3 +585,20 @@ $lang->block->flowchart['project'] = array('项目经理', '创建' . $lang->exe
if($config->systemMode == 'new') $lang->block->flowchart['project'] = array('项目经理', '创建项目、' . $lang->executionCommon, '维护团队', "关联需求", '分解任务', '跟踪进度');
$lang->block->flowchart['dev'] = array('研发人员', '领取任务和Bug', '设计实现方案', '更新状态', '完成任务和Bug', '提交代码');
$lang->block->flowchart['tester'] = array('测试人员', '撰写用例', '执行用例', '提交Bug', '验证Bug', '关闭Bug');
+
+$lang->block->zentaoapp = new stdclass();
+$lang->block->zentaoapp->thisYearInvestment = '今年投入';
+$lang->block->zentaoapp->sinceTotalInvestment = '从使用至今,总投入';
+$lang->block->zentaoapp->myStory = '我的需求';
+$lang->block->zentaoapp->allStorySum = '需求总数';
+$lang->block->zentaoapp->storyCompleteRate = '需求完成率';
+$lang->block->zentaoapp->latestExecution = '近期执行';
+$lang->block->zentaoapp->involvedExecution = '我参与的执行';
+$lang->block->zentaoapp->mangedProduct = '负责产品';
+$lang->block->zentaoapp->involvedProject = '参与项目';
+$lang->block->zentaoapp->customIndexCard = '定制首页卡片';
+$lang->block->zentaoapp->createStory = '提需求';
+$lang->block->zentaoapp->createEffort = '记日志';
+$lang->block->zentaoapp->createDoc = '建文档';
+$lang->block->zentaoapp->createTodo = '建待办';
+$lang->block->zentaoapp->workbench = '工作台';
diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php
index 8c11dead7d..fe7157f155 100644
--- a/module/bug/lang/zh-cn.php
+++ b/module/bug/lang/zh-cn.php
@@ -150,12 +150,15 @@ $lang->bug->assignToMeAB = '指派给我';
$lang->bug->openedByMeAB = '由我创建';
$lang->bug->resolvedByMeAB = '由我解决';
-$lang->bug->ditto = '同上';
-$lang->bug->dittoNotice = '该bug与上一bug不属于同一产品!';
-$lang->bug->noAssigned = '未指派';
-$lang->bug->noBug = '暂时没有Bug。';
-$lang->bug->noModule = '
您现在还没有模块信息
请维护测试模块
';
-$lang->bug->delayWarning = " 延期%s天 ";
+$lang->bug->ditto = '同上';
+$lang->bug->dittoNotice = '该bug与上一bug不属于同一产品!';
+$lang->bug->noAssigned = '未指派';
+$lang->bug->noBug = '暂时没有Bug。';
+$lang->bug->noModule = '您现在还没有模块信息
请维护测试模块
';
+$lang->bug->delayWarning = " 延期%s天 ";
+$lang->bug->labelConfirmed = '已确认';
+$lang->bug->labelPostponed = '被延期';
+$lang->bug->storyChanged = '需求变动';
/* 页面标签。*/
$lang->bug->lblAssignedTo = '当前指派';
diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php
index 59b4a7c9c2..db5ccc3076 100644
--- a/module/common/lang/zh-cn.php
+++ b/module/common/lang/zh-cn.php
@@ -34,6 +34,7 @@ $lang->logout = '退出';
$lang->login = '登录';
$lang->help = '帮助';
$lang->aboutZenTao = '关于禅道';
+$lang->ztWebsite = '禅道系统网址';
$lang->profile = '个人档案';
$lang->changePassword = '修改密码';
$lang->unfoldMenu = '展开导航';
@@ -104,9 +105,10 @@ $lang->customField = '自定义表单项';
$lang->lineNumber = '行号';
$lang->tutorialConfirm = '检测到你尚未退出新手教程模式,是否现在退出?';
-$lang->preShortcutKey = '[快捷键:←]';
-$lang->nextShortcutKey = '[快捷键:→]';
-$lang->backShortcutKey = '[快捷键:Alt+↑]';
+$lang->preShortcutKey = '[快捷键:←]';
+$lang->nextShortcutKey = '[快捷键:→]';
+$lang->backShortcutKey = '[快捷键:Alt+↑]';
+$lang->shortcutOperation = '快捷操作';
$lang->select = '选择';
$lang->selectAll = '全选';
@@ -307,7 +309,8 @@ $lang->createObjects['program'] = '项目集';
$lang->createObjects['doc'] = '文档';
/* 语言 */
-$lang->lang = 'Language';
+$lang->lang = 'Language';
+$lang->setLang = '语音设置';
/* 风格列表。*/
$lang->theme = '主题';
diff --git a/module/file/control.php b/module/file/control.php
index ba4318d1d4..b36252c3c3 100644
--- a/module/file/control.php
+++ b/module/file/control.php
@@ -78,8 +78,9 @@ class file extends control
if($uid) $_SESSION['album'][$uid][] = $fileID;
if(defined('RUN_MODE') && RUN_MODE == 'api')
{
+ if($uid) $_SESSION['album']['used'][$uid][$fileID] = $fileID;
$_SERVER['SCRIPT_NAME'] = 'index.php';
- die(json_encode(array('status' => 'success', 'data' => commonModel::getSysURL() . $this->config->webRoot . $url)));
+ return $this->send(array('status' => 'success', 'id' => $fileID, 'data' => commonModel::getSysURL() . $this->config->webRoot . $url));
}
else
{
@@ -91,7 +92,7 @@ class file extends control
$error = strip_tags(sprintf($this->lang->file->errorCanNotWrite, $this->file->savePath, $this->file->savePath));
if(defined('RUN_MODE') && RUN_MODE == 'api')
{
- die(json_encode(array('status' => 'error', 'message' => $error)));
+ return $this->send(array('status' => 'error', 'message' => $error));
}
else
{
@@ -99,7 +100,7 @@ class file extends control
}
}
}
- die(json_encode(array('status' => 'error', 'message' => $this->lang->file->uploadImagesExplain)));
+ return $this->send(array('status' => 'error', 'message' => $this->lang->file->uploadImagesExplain));
}
/**
diff --git a/module/file/model.php b/module/file/model.php
index 5cc061e6f7..112a8b4d6d 100644
--- a/module/file/model.php
+++ b/module/file/model.php
@@ -834,7 +834,7 @@ class fileModel extends model
$data = new stdclass();
$data->objectID = $objectID;
$data->objectType = $objectType;
- $data->extra = 'editor';
+ if(!defined('RUN_MODE') OR RUN_MODE != 'api') $data->extra = 'editor';
if(isset($_SESSION['album']['used'][$uid]) and $_SESSION['album']['used'][$uid])
{
$this->dao->update(TABLE_FILE)->data($data)->where('id')->in($_SESSION['album']['used'][$uid])->exec();
diff --git a/module/group/model.php b/module/group/model.php
index 32f14009c9..379decbf3b 100644
--- a/module/group/model.php
+++ b/module/group/model.php
@@ -372,7 +372,10 @@ class groupModel extends model
$dynamic = array();
foreach($actions['actions'] as $moduleName => $moduleActions)
{
- if($moduleName != 'todo' and isset($actions['views']) and !in_array($this->lang->navGroup->$moduleName, $actions['views'])) continue;
+ $groupName = $moduleName;
+ if(isset($this->lang->navGroup->$moduleName)) $groupName = $this->lang->navGroup->$moduleName;
+ if($moduleName == 'case') $groupName = $this->lang->navGroup->testcase;
+ if($groupName != 'my' and isset($actions['views']) and !in_array($groupName, $actions['views'])) continue;
$dynamic[$moduleName] = $moduleActions;
}
diff --git a/module/my/lang/zh-cn.php b/module/my/lang/zh-cn.php
index 6eef0eb79e..6c5335819b 100644
--- a/module/my/lang/zh-cn.php
+++ b/module/my/lang/zh-cn.php
@@ -3,6 +3,7 @@ global $config;
/* 方法列表。*/
$lang->my->index = '首页';
+$lang->my->data = '我的数据';
$lang->my->todo = '我的待办';
$lang->my->calendar = '日程';
$lang->my->work = '待处理';
diff --git a/module/my/model.php b/module/my/model.php
index ce75ba9b1e..2e858a1e26 100644
--- a/module/my/model.php
+++ b/module/my/model.php
@@ -60,49 +60,75 @@ class myModel extends model
/**
* Get my charged products.
*
+ * @param string $type undone|ownbyme
* @access public
* @return object
*/
- public function getProducts()
+ public function getProducts($type = 'undone')
{
- $products = $this->dao->select('t1.id as id,t1.*')->from(TABLE_PRODUCT)->alias('t1')
- ->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id')
- ->where('t1.deleted')->eq(0)
- ->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->products)->fi()
- ->orderBy('t1.order_asc')
- ->fetchAll('id');
+ $products = $this->dao->select('t1.*, t2.name as programName')->from(TABLE_PRODUCT)->alias('t1')
+ ->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id')
+ ->where('t1.deleted')->eq(0)
+ ->beginIF($type == 'undone')->andWhere('t1.status')->eq('normal')->fi()
+ ->beginIF($type == 'ownbyme')->andWhere('t1.PO')->eq($this->app->user->account)->fi()
+ ->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->products)->fi()
+ ->orderBy('t1.order_asc')
+ ->fetchAll('id');
$productKeys = array_keys($products);
- $stories = $this->dao->select('product, sum(estimate) AS estimateCount')
- ->from(TABLE_STORY)
- ->where('deleted')->eq(0)
- ->andWhere('product')->in($productKeys)
- ->groupBy('product')
- ->fetchPairs();
- $plans = $this->dao->select('product, count(*) AS count')
- ->from(TABLE_PRODUCTPLAN)
- ->where('deleted')->eq(0)
- ->andWhere('product')->in($productKeys)
- ->andWhere('end')->gt(helper::now())
- ->groupBy('product')
- ->fetchPairs();
- $releases = $this->dao->select('product, count(*) AS count')
- ->from(TABLE_RELEASE)
- ->where('deleted')->eq(0)
- ->andWhere('product')->in($productKeys)
- ->groupBy('product')
- ->fetchPairs();
- $executions = $this->dao->select('t1.product,t2.id,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
- ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
- ->where('t1.product')->in($productKeys)
- ->andWhere('t2.type')->in('stage,sprint')
- ->andWhere('t2.deleted')->eq(0)
- ->orderBy('t1.project')
- ->fetchAll('product');
- foreach($executions as $key => $execuData)
+ $storyGroups = $this->dao->select('id,product,status,stage,estimate')
+ ->from(TABLE_STORY)
+ ->where('deleted')->eq(0)
+ ->andWhere('product')->in($productKeys)
+ ->groupBy('product')
+ ->fetchGroup('product', 'id');
+ $summaryStories = array();
+ foreach($storyGroups as $productID => $stories)
{
- $execution = $this->loadModel('execution')->getById($execuData->id);
- $executions[$key]->progress = ($execution->totalConsumed + $execution->totalLeft) ? floor($execution->totalConsumed / ($execution->totalConsumed + $execution->totalLeft) * 1000) / 1000 * 100 : 0;
+ $summaryStory = new stdclass();
+ $summaryStory->total = count($stories);
+
+ $finishedTotal = 0;
+ $leftTotal = 0;
+ $estimateCount = 0;
+ foreach($stories as $story)
+ {
+ $estimateCount += $story->estimate;
+ ($story->status == 'closed' or $story->stage == 'released' or $story->stage == 'closed') ? $finishedTotal ++ : $leftTotal ++;
+ }
+
+ $summaryStory->finishedTotal = $finishedTotal;
+ $summaryStory->leftTotal = $leftTotal;
+ $summaryStory->estimateCount = $estimateCount;
+ $summaryStory->finishedRate = $summaryStory->total == 0 ? 0 : ($finishedTotal / $summaryStory->total) * 100;
+ $summaryStories[$productID] = $summaryStory;
+ }
+
+ $plans = $this->dao->select('product, count(*) AS count')
+ ->from(TABLE_PRODUCTPLAN)
+ ->where('deleted')->eq(0)
+ ->andWhere('product')->in($productKeys)
+ ->andWhere('end')->gt(helper::now())
+ ->groupBy('product')
+ ->fetchPairs();
+ $releases = $this->dao->select('product, count(*) AS count')
+ ->from(TABLE_RELEASE)
+ ->where('deleted')->eq(0)
+ ->andWhere('product')->in($productKeys)
+ ->groupBy('product')
+ ->fetchPairs();
+ $executions = $this->dao->select('t1.product,t2.id,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
+ ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
+ ->where('t1.product')->in($productKeys)
+ ->andWhere('t2.type')->in('stage,sprint')
+ ->andWhere('t2.deleted')->eq(0)
+ ->orderBy('t1.project')
+ ->fetchAll('product');
+ $this->loadModel('execution');
+ foreach($executions as $productID => $execution)
+ {
+ $execution = $this->execution->getById($execution->id);
+ $executions[$productID]->progress = ($execution->totalConsumed + $execution->totalLeft) ? floor($execution->totalConsumed / ($execution->totalConsumed + $execution->totalLeft) * 1000) / 1000 * 100 : 0;
}
$allCount = count($products);
@@ -112,7 +138,12 @@ class myModel extends model
$product->plans = isset($plans[$product->id]) ? $plans[$product->id] : 0;
$product->releases = isset($releases[$product->id]) ? $releases[$product->id] : 0;
if(isset($executions[$product->id])) $product->executions = $executions[$product->id];
- $product->storyEstimateCount = isset($stories[$product->id]) ? $stories[$product->id] : 0;
+ $product->storyEstimateCount = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->estimateCount : 0;
+ $product->storyTotal = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->total : 0;
+ $product->storyFinishedTotal = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->finishedTotal : 0;
+ $product->storyLeftTotal = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->leftTotal : 0;
+ $product->storyFinishedRate = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->finishedRate : 0;
+ $product->latestExecution = isset($executions[$product->id]) ? $executions[$product->id] : '';
if($product->status != 'closed') $unclosedCount ++;
if($product->status == 'closed') unset($products[$key]);
}
@@ -137,22 +168,37 @@ class myModel extends model
public function getDoingProjects()
{
$data = new stdClass();
- $doingProjects = array();
- $projects = $this->loadModel('project')->getOverviewList('byStatus', 'all', 'id_desc');
+ $doingProjects = $this->loadModel('project')->getOverviewList('byStatus', 'doing', 'id_desc');
$maxCount = 5;
- foreach($projects as $key => $project)
+ $myProjects = array();
+ foreach($doingProjects as $key => $project)
{
- if($project->status == 'doing')
+ if($project->PM == $this->app->user->account)
{
- $workhour = $this->project->getWorkhour($project->id);
- $projects[$key]->progress = ($workhour->totalConsumed + $workhour->totalLeft) ? floor($workhour->totalConsumed / ($workhour->totalConsumed + $workhour->totalLeft) * 1000) / 1000 * 100 : 0;
- $doingProjects[] = $projects[$key];
- if(count($doingProjects) >= $maxCount) break;
+ $myProjects[$key] = $project;
+ unset($doingProjects[$key]);
+ }
+ if(count($myProjects) >= $maxCount) break;
+ }
+ if(count($myProjects) < $maxCount and !empty($doingProjects))
+ {
+ foreach($doingProjects as $key => $project)
+ {
+ $myProjects[$key] = $project;
+ if(count($myProjects) >= $maxCount) break;
}
}
- $data->doingCount = count($doingProjects);
- $data->projects = $doingProjects;
+ foreach($myProjects as $key => $project)
+ {
+ $workhour = $this->project->getWorkhour($project->id);
+ $project->progress = ($workhour->totalConsumed + $workhour->totalLeft) ? floor($workhour->totalConsumed / ($workhour->totalConsumed + $workhour->totalLeft) * 1000) / 1000 * 100 : 0;
+ $project->delay = (helper::diffDate(helper::today(), $project->end) > 0);
+ $project->link = common::hasPriv('project', 'view') ? helper::createLink('project', 'view', "projectID={$project->id}") : '';
+ }
+
+ $data->doingCount = count($myProjects);
+ $data->projects = array_values($myProjects);
return $data;
}
@@ -164,20 +210,36 @@ class myModel extends model
*/
public function getOverview()
{
- $allConsumed = 0;
- $thisYearConsumed = 0;
+ $inAdminGroup = $this->dao->select('t1.*')->from(TABLE_USERGROUP)->alias('t1')
+ ->leftJoin(TABLE_GROUP)->alias('t2')->on('t1.group=t2.id')
+ ->where('t1.account')->eq($this->app->user->account)
+ ->andWhere('t2.role')->eq('admin')
+ ->fetch();
- $projects = $this->loadModel('project')->getOverviewList('byStatus', 'all', 'id_desc');
- $projectsConsumed = $this->project->getProjectsConsumed(array_keys($projects), 'THIS_YEAR');
- foreach($projects as $project)
+ $overview = new stdclass();
+ if(!empty($inAdminGroup) or $this->app->user->admin)
{
- $allConsumed += $project->consumed;
- $thisYearConsumed += $projectsConsumed[$project->id]->totalConsumed;
- }
+ $allConsumed = 0;
+ $thisYearConsumed = 0;
- $overview->projectTotal = count($projects);
- $overview->allConsumed = $allConsumed;
- $overview->thisYearConsumed = $thisYearConsumed;
+ $projects = $this->loadModel('project')->getOverviewList('byStatus', 'all', 'id_desc', 0);
+ $projectsConsumed = $this->project->getProjectsConsumed(array_keys($projects), 'THIS_YEAR');
+ foreach($projects as $project)
+ {
+ $allConsumed += $project->consumed;
+ $thisYearConsumed += $projectsConsumed[$project->id]->totalConsumed;
+ }
+
+ $overview->projectTotal = count($projects);
+ $overview->allConsumed = round($allConsumed, 1);
+ $overview->thisYearConsumed = round($thisYearConsumed, 1);
+ }
+ else
+ {
+ $overview->myTaskTotal = (int)$this->dao->select('count(*) AS count')->from(TABLE_TASK)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->fetch('count');
+ $overview->myStoryTotal = (int)$this->dao->select('count(*) AS count')->from(TABLE_STORY)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->andWhere('type')->eq('story')->fetch('count');
+ $overview->myBugTotal = (int)$this->dao->select('count(*) AS count')->from(TABLE_BUG)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->fetch('count');
+ }
return $overview;
}
@@ -223,7 +285,10 @@ class myModel extends model
*/
public function getActions()
{
- $actions = $this->loadModel('action')->getDynamic('all', 'today', 'date_desc');
+ $this->app->loadClass('pager', $static = true);
+ $pager = new pager(0, 50, 1);
+
+ $actions = $this->loadModel('action')->getDynamic('all', 'all', 'date_desc', $pager);
$users = $this->loadModel('user')->getList();
$simplifyUsers = array();
@@ -237,8 +302,14 @@ class myModel extends model
$simplifyUsers[$user->account] = $simplifyUser;
}
+ $i = 1;
+ $maxCount = 5;
+ $filterActions = array();
foreach($actions as $key => $action)
{
+ if($i > $maxCount) break;
+ if($action->objectType == 'user') continue;
+
$simplifyUser = zget($simplifyUsers, $action->actor, '');
$actionActor = $simplifyUser;
if(empty($simplifyUser))
@@ -249,9 +320,12 @@ class myModel extends model
$actionActor->realname = $action->actor;
$actionActor->avatar = '';
}
- $actions[$key]->actor = $actionActor;
+
+ $action->actor = $actionActor;
+ $filterActions[] = $action;
+ $i++;
}
- return $actions;
+ return $filterActions;
}
}
diff --git a/module/product/model.php b/module/product/model.php
index 7a70c6ee92..2c6c6a5642 100644
--- a/module/product/model.php
+++ b/module/product/model.php
@@ -145,14 +145,15 @@ class productModel extends model
*/
public function saveState($productID, $products)
{
- if($productID > 0) $this->session->set('product', (int)$productID);
- if($productID == 0 and $this->cookie->lastProduct) $this->session->set('product', (int)$this->cookie->lastProduct);
- if($productID == 0 and $this->session->product == '') $this->session->set('product', key($products));
+ if($productID == 0 and $this->cookie->lastProduct) $productID = $this->cookie->lastProduct;
+ if($productID == 0 and $this->session->product == '') $productID = key($products);
+ $this->session->set('product', (int)$productID, $this->app->tab);
+
if(!isset($products[$this->session->product]))
{
- $product = $this->getById($productID);
- if(empty($product)) $this->session->set('product', key($products));
- if($productID && strpos(",{$this->app->user->view->products},", ",{$this->session->product},") === false) $this->accessDenied();
+ $productID = key($products);
+ $this->session->set('product', (int)$productID, $this->app->tab);
+ if($productID && strpos(",{$this->app->user->view->products},", ",{$productID},") === false) $this->accessDenied();
}
if($this->cookie->preProductID != $productID)
{
diff --git a/module/program/model.php b/module/program/model.php
index 5911c2cea0..01e4bf238c 100644
--- a/module/program/model.php
+++ b/module/program/model.php
@@ -443,7 +443,8 @@ class programModel extends model
$projectList = $this->dao->select('*')->from(TABLE_PROJECT)
->where('deleted')->eq('0')
->beginIF($this->config->systemMode == 'new')->andWhere('type')->eq('project')->fi()
- ->beginIF($browseType != 'all')->andWhere('status')->eq($browseType)->fi()
+ ->beginIF($browseType != 'all' and $browseType != 'undone')->andWhere('status')->eq($browseType)->fi()
+ ->beginIF($browseType == 'undone')->andWhere('status')->in('wait,doing')->fi()
->beginIF($path)->andWhere('path')->like($path . '%')->fi()
->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'new')->andWhere('id')->in($this->app->user->view->projects)->fi()
->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'classic')->andWhere('id')->in($this->app->user->view->sprints)->fi()
diff --git a/module/project/model.php b/module/project/model.php
index 24dcbda385..44358df6ad 100644
--- a/module/project/model.php
+++ b/module/project/model.php
@@ -286,18 +286,18 @@ class projectModel extends model
$hours = $this->dao->select('t2.parent as project, sum(t1.consumed) as consumed, sum(t1.estimate) as estimate')->from(TABLE_TASK)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id')
- ->where('t2.parent')->in($projectIdList)
+ ->where('t2.project')->in($projectIdList)
->andWhere('t1.deleted')->eq(0)
->andWhere('t1.parent')->lt(1)
- ->groupBy('t2.parent')
+ ->groupBy('t2.project')
->fetchAll('project');
$leftTasks = $this->dao->select('t2.parent as project, count(*) as tasks')->from(TABLE_TASK)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id')
- ->where('t2.parent')->in($projectIdList)
+ ->where('t2.project')->in($projectIdList)
->andWhere('t1.deleted')->eq(0)
->andWhere('t1.status')->in('wait,doing,pause')
- ->groupBy('t2.parent')
+ ->groupBy('t2.project')
->fetchPairs();
$this->loadModel('product');
@@ -412,13 +412,13 @@ class projectModel extends model
{
$projects = array();
- $totalConsumeds = $this->dao->select('project,ROUND(SUM(consumed), 1) AS totalConsumed')
- ->from(TABLE_TASK)
- ->where('project')->in($projectIdList)
- ->beginIF($time == 'THIS_YEAR')->andWhere('realStarted')->ge(date("Y-01-01 00:00:00"))->fi()
- ->andWhere('deleted')->eq(0)
- ->andWhere('parent')->lt(1)
- ->groupBy('project')
+ $totalConsumeds = $this->dao->select('t2.project,ROUND(SUM(t1.consumed), 1) AS totalConsumed')->from(TABLE_TASKESTIMATE)->alias('t1')
+ ->leftJoin(TABLE_TASK)->alias('t2')->on('t1.task=t2.id')
+ ->where('t2.project')->in($projectIdList)
+ ->beginIF($time == 'THIS_YEAR')->andWhere('LEFT(t1.`date`, 4)')->eq(date('Y'))->fi()
+ ->andWhere('t2.deleted')->eq(0)
+ ->andWhere('t2.parent')->lt(1)
+ ->groupBy('t2.project')
->fetchAll('project');
foreach($projectIdList as $projectID)
diff --git a/module/task/control.php b/module/task/control.php
index 0c39718954..4348f64c7b 100644
--- a/module/task/control.php
+++ b/module/task/control.php
@@ -138,7 +138,7 @@ class task extends control
$this->executeHooks($taskID);
/* Return task id when call the API. */
- if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $taskID));
+ if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $taskID));
/* If link from no head then reload. */
if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
@@ -300,7 +300,7 @@ class task extends control
foreach($mails as $mail) $taskIDList[] = $mail->taskID;
/* Return task id list when call the API. */
- if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'idList' => $taskIDList));
+ if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'idList' => $taskIDList));
/* Locate the browser. */
if(!empty($iframe)) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
@@ -408,7 +408,7 @@ class task extends control
}
}
- if(defined('RUN_MODE') && RUN_MODE == 'api')
+ if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api'))
{
return $this->send(array('status' => 'success', 'data' => $taskID));
}
@@ -576,7 +576,7 @@ class task extends control
if(dao::isError())
{
- if($this->viewType == 'json') return $this->send(array('result' => 'fail', 'message' => dao::getError()));
+ if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
die(js::error(dao::getError()));
}
@@ -585,7 +585,7 @@ class task extends control
$this->executeHooks($taskID);
- if($this->viewType == 'json') return $this->send(array('result' => 'success'));
+ if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success'));
if(isonlybody()) die(js::closeModal('parent.parent', 'this'));
die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
}
@@ -780,7 +780,7 @@ class task extends control
if(dao::isError())
{
- if($this->viewType == 'json') return $this->send(array('result' => 'fail', 'message' => dao::getError()));
+ if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
die(js::error(dao::getError()));
}
@@ -808,7 +808,7 @@ class task extends control
}
}
- if($this->viewType == 'json') return $this->send(array('result' => 'success'));
+ if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success'));
if(isonlybody()) die(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
}
@@ -940,7 +940,7 @@ class task extends control
$changes = $this->task->finish($taskID);
if(dao::isError())
{
- if($this->viewType == 'json') return $this->send(array('result' => 'fail', 'message' => dao::getError()));
+ if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
die(js::error(dao::getError()));
}
$files = $this->loadModel('file')->saveUpload('task', $taskID);
diff --git a/module/task/model.php b/module/task/model.php
index 52acee0b86..0a0606e289 100644
--- a/module/task/model.php
+++ b/module/task/model.php
@@ -22,7 +22,6 @@ class taskModel extends model
*/
public function create($executionID)
{
-
if($this->post->estimate < 0)
{
dao::$errors[] = $this->lang->task->error->recordMinus;
diff --git a/module/testcase/control.php b/module/testcase/control.php
index aed4fff98d..313833643a 100644
--- a/module/testcase/control.php
+++ b/module/testcase/control.php
@@ -1307,7 +1307,7 @@ class testcase extends control
{
$cases = array();
$orderBy = " ORDER BY " . str_replace(array('|', '^A', '_'), ' ', $orderBy);
- $stmt = $this->dbh->query($this->session->testcaseQueryCondition . $orderBy . ($this->post->limit ? ' LIMIT ' . $this->post->limit : ''));
+ $stmt = $this->dao->query($this->session->testcaseQueryCondition . $orderBy . ($this->post->limit ? ' LIMIT ' . $this->post->limit : ''));
while($row = $stmt->fetch())
{
$caseID = isset($row->case) ? $row->case : $row->id;
@@ -1368,7 +1368,7 @@ class testcase extends control
$result = isset($results[$case->id]) ? $results[$case->id] : array();
$case->real = '';
- if(!empty($result))
+ if(!empty($result) and !isset($relatedSteps[$case->id]))
{
$firstStep = reset($result);
$case->real = $firstStep['real'];
diff --git a/module/todo/control.php b/module/todo/control.php
index 0746c82942..d8dcb8f1c3 100644
--- a/module/todo/control.php
+++ b/module/todo/control.php
@@ -312,6 +312,7 @@ class todo extends control
{
$todo = $this->todo->getById($todoID);
if($todo->status == 'done' or $todo->status == 'closed') $this->todo->activate($todoID);
+ if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
if(isonlybody()) die(js::reload('parent.parent'));
die(js::reload('parent'));
}
@@ -476,8 +477,10 @@ class todo extends control
if($todo->type == 'task') $app = 'execution';
if($todo->type == 'story') $app = 'product';
$cancelURL = $this->server->HTTP_REFERER;
+ if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'message' => sprintf($this->lang->todo->$confirmNote, $todo->idvalue), 'locate' => $confirmURL));
die(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
}
+ if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
if(isonlybody())die(js::reload('parent.parent'));
die(js::reload('parent'));
}
diff --git a/module/todo/lang/zh-cn.php b/module/todo/lang/zh-cn.php
index f709d457b2..400422870f 100644
--- a/module/todo/lang/zh-cn.php
+++ b/module/todo/lang/zh-cn.php
@@ -112,6 +112,7 @@ $lang->todo->lblClickCreate = "点击添加待办";
$lang->todo->noTodo = '该类型没有待办事务';
$lang->todo->noAssignedTo = '被指派人不能为空';
$lang->todo->unfinishedTodo = '待办ID %s 不是完成状态,不能关闭。';
+$lang->todo->today = '今日待办';
$lang->todo->periods['all'] = '所有';
$lang->todo->periods['before'] = '未完';
diff --git a/module/user/lang/zh-cn.php b/module/user/lang/zh-cn.php
index 2c4e33c843..b221554de6 100644
--- a/module/user/lang/zh-cn.php
+++ b/module/user/lang/zh-cn.php
@@ -186,8 +186,9 @@ $lang->user->personalData['createdIssues'] = '创建的问题数';
$lang->user->personalData['resolvedIssues'] = '解决的问题数';
$lang->user->personalData['createdDocs'] = '创建的文档数';
-$lang->user->keepLogin['on'] = '保持登录';
-$lang->user->loginWithDemoUser = '使用demo帐号登录:';
+$lang->user->keepLogin['on'] = '保持登录';
+$lang->user->loginWithDemoUser = '使用demo帐号登录:';
+$lang->user->scanToLogin = '扫一扫登录';
$lang->user->tpl = new stdclass();
$lang->user->tpl->type = '类型';
@@ -199,12 +200,16 @@ $lang->usertpl = new stdclass();
$lang->usertpl->title = '模板名称';
$lang->user->placeholder = new stdclass();
-$lang->user->placeholder->account = '英文、数字和下划线的组合,三位以上';
-$lang->user->placeholder->password1 = '六位以上';
-$lang->user->placeholder->role = '职位影响内容和用户列表的顺序。';
-$lang->user->placeholder->group = '分组决定用户的权限列表。';
-$lang->user->placeholder->commiter = '版本控制系统(subversion)中的帐号';
-$lang->user->placeholder->verify = '请输入您的系统登录密码';
+$lang->user->placeholder->account = '英文、数字和下划线的组合,三位以上';
+$lang->user->placeholder->password1 = '六位以上';
+$lang->user->placeholder->role = '职位影响内容和用户列表的顺序。';
+$lang->user->placeholder->group = '分组决定用户的权限列表。';
+$lang->user->placeholder->commiter = '版本控制系统(subversion)中的帐号';
+$lang->user->placeholder->verify = '请输入您的系统登录密码';
+
+$lang->user->placeholder->loginPassword = '请输入密码';
+$lang->user->placeholder->loginAccount = '请输入用户名';
+$lang->user->placeholder->loginUrl = '请输入禅道系统网址';
$lang->user->placeholder->passwordStrength[1] = '6位以上,包含大小写字母,数字。';
$lang->user->placeholder->passwordStrength[2] = '10位以上,包含大小写字母,数字,特殊字符。';
@@ -219,6 +224,8 @@ $lang->user->error->reserved = "【ID %s】的用户名已被系统预留"
$lang->user->error->weakPassword = "【ID %s】的密码强度小于系统设定。";
$lang->user->error->dangerPassword = "【ID %s】的密码不能使用【%s】这些常用若口令。";
+$lang->user->error->url = "网址不正确,请联系管理员";
+$lang->user->error->verify = "用户名或密码错误";
$lang->user->error->verifyPassword = "验证失败,请检查您的系统登录密码是否正确";
$lang->user->error->originalPassword = "原密码不正确";
$lang->user->error->companyEmpty = "公司名称不能为空!";
@@ -267,16 +274,19 @@ $lang->user->process4DB = "检测到您可能在使用一键安装包环境,
$lang->user->mkdirWin = <<
|
- 不能创建临时目录,请确认目录%s是否存在并有操作权限。
+ 不能创建临时目录,请确认目录%s是否存在并有操作权限。
Can't create tmp directory, make sure the directory %s exists and has permission to operate.
|