| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- <?php
- /**
- * The control file of action module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
- * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Chunsheng Wang <chunsheng@cnezsoft.com>
- * @package action
- * @version $Id$
- * @link https://www.zentao.net
- */
- class action extends control
- {
- /**
- * 创建一个动作或者删除所有的补丁动作,此方法由Ztools使用。
- * Create a action or delete all patch actions, this method is used by the Ztools.
- *
- * @param string $objectType
- * @param string $actionType
- * @param string $objectName
- * @access public
- * @return void
- */
- public function create($objectType, $actionType, $objectName)
- {
- $actionID = $this->action->create($objectType, 0, $actionType, '', $objectName);
- if($actionID)
- {
- $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess));
- }
- else
- {
- $this->send(array('result' => 'fail', 'message' => 'error'));
- }
- }
- /**
- * 回收站。
- * Trash.
- *
- * @param string $browseType
- * @param string $type all|hidden
- * @param bool $byQuery
- * @param int $queryID
- * @param string $orderBy
- * @param int $recTotal
- * @param int $recPerPage
- * @param int $pageID
- * @access public
- * @return void
- */
- public function trash($browseType = 'all', $type = 'all', $byQuery = false, $queryID = 0, $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
- {
- /* Url存入session。 */
- /* Save url into session. */
- $this->actionZen->saveUrlIntoSession();
- /* 保存用于替换搜索语言项的对象名称。 */
- /* Save the object name used to replace the search language item. */
- $this->session->set('objectName', zget($this->lang->action->objectTypes, $browseType, ''), 'admin');
- /* 生成表单搜索数据。 */
- /* Build the search form. */
- $actionURL = $this->createLink('action', 'trash', "browseType=$browseType&type=$type&byQuery=true&queryID=myQueryID");
- $this->action->buildTrashSearchForm($queryID, $actionURL);
- /* 分页初始化。 */
- /* Load paper. */
- $this->app->loadClass('pager', true);
- $pager = pager::init($recTotal, $recPerPage, $pageID);
- /* 生成排序规则。 */
- /* Generate the sort rules. */
- $sort = common::appendOrder($orderBy);
- $trashes = $byQuery ? $this->action->getTrashesBySearch($browseType, $type, $queryID, $sort, $pager) : $this->action->getTrashes($browseType, $type, $sort, $pager);
- $objectTypeList = array_keys($this->action->getTrashObjectTypes($type));
- /* 获取头部模块标题导航。 */
- /* Build the header navigation title. */
- $preferredType = $this->actionZen->getTrashesHeaderNavigation($objectTypeList);
- /* 初始化项目、产品、执行列表。 */
- /* Initialize the project, product, execution list. */
- $projectList = array();
- $productList = array();
- $executionList = array();
- /* 获取执行所属的项目名称。 */
- /* Get the projects name of executions. */
- if($browseType == 'execution') $this->view->projectList = $projectList = $this->loadModel('project')->getByIdList(array_column($trashes, 'project'), 'all');
- /* 获取用户故事所属的产品名称。 */
- /* Get the products name of story. */
- if(in_array($browseType, array('story', 'requirement')))
- {
- $storyIdList = array();
- foreach($trashes as $trash) $storyIdList[] = $trash->objectID;
- $this->view->productList = $this->loadModel('story')->getByList($storyIdList, 'all');
- }
- /* 获取任务的执行名称。 */
- /* Get the executions name of task. */
- if($browseType == 'task') $this->view->executionList = $executionList = $this->loadModel('execution')->getByIdList(array_column($trashes, 'execution'), 'all');
- /* 补充操作记录的信息。 */
- /* Supplement the information recorded by the operation. */
- foreach($trashes as $trash) $this->actionZen->processTrash($trash, $projectList, $productList, $executionList);
- $this->view->title = $this->lang->action->trash;
- $this->view->trashes = $trashes;
- $this->view->type = $type;
- $this->view->currentObjectType = $browseType;
- $this->view->orderBy = $orderBy;
- $this->view->pager = $pager;
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
- $this->view->preferredType = $preferredType;
- $this->view->byQuery = $byQuery;
- $this->view->queryID = $queryID;
- $this->display();
- }
- /**
- * 恢复一个回收站对象。
- * Undelete an object.
- *
- * @param int $actionID
- * @param string $browseType
- * @param string $confirmChange
- * @access public
- * @return void
- */
- public function undelete($actionID, $browseType = 'all', $confirmChange = 'no')
- {
- $result = $this->actionZen->checkActionExist($actionID);
- if(is_array($result) && $result['result'] == 'fail') return $this->send($result);
- $oldAction = $result;
- /* 当对象类型为program、project、execution、product时,需要检查是否有重复的对象。 */
- /* When the object type is program, project, execution, product, you need to check if there are duplicate objects. */
- if(in_array($oldAction->objectType, array('program', 'project', 'execution', 'product', 'build')))
- {
- $table = $this->config->objectTables[$oldAction->objectType];
- list($repeatObject, $object) = $this->action->getRepeatObject($oldAction, $table);
- if($repeatObject)
- {
- list($replaceName, $replaceCode) = $this->actionZen->getReplaceNameAndCode($repeatObject, $object, $table);
- if($confirmChange == 'no')
- {
- $message = $this->actionZen->getConfirmNoMessage($repeatObject, $object, $oldAction, $replaceName, $replaceCode);
- if($message)
- {
- $url = $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes");
- return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.confirm({message: '{$message}', icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) => {if(res) $.ajaxSubmit({url: '{$url}'}); });"));
- }
- }
- elseif($confirmChange == 'yes')
- {
- $this->actionZen->recoverObject($repeatObject, $object, $replaceName, $replaceCode, $table, $oldAction);
- }
- }
- if($oldAction->objectType == 'execution')
- {
- $confirmLang = $this->actionZen->restoreStages($oldAction, $confirmChange);
- $url = $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes");
- if($confirmLang !== true) return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.confirm({message: '{$confirmLang}', icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) => {if(res) $.ajaxSubmit({url: '{$url}'});});"));
- }
- }
- if($oldAction->objectType == 'module' && $confirmChange == 'no')
- {
- $module = $this->loadModel('tree')->getById($oldAction->objectID);
- $repeatName = $this->tree->checkUnique($module);
- if($module->type == 'doc' && $module->parent > 0 && !$repeatName)
- {
- $parents = $this->tree->getParents($oldAction->objectID, true);
- $isDeletedParent = false;
- foreach($parents as $parent)
- {
- if($parent->id == $oldAction->objectID) continue;
- if($parent->deleted)
- {
- $isDeletedParent = true;
- break;
- }
- }
- if($isDeletedParent)
- {
- $url = $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes");
- return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.confirm({message: '{$this->lang->action->undeleteModuleTip}', icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) => {if(res) $.ajaxSubmit({url: '{$url}'});});"));
- }
- }
- }
- elseif($oldAction->objectType == 'task' && $confirmChange == 'no')
- {
- $task = $this->loadModel('task')->getById($oldAction->objectID);
- $isDeleted = $this->dao->select('deleted')->from(TABLE_EXECUTION)->where('id')->eq($task->execution)->fetch('deleted');
- $url = $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes");
- if($isDeleted) return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.confirm({message: '{$this->lang->action->undeleteTaskTip}'}).then((res) => {if(res) $.ajaxSubmit({url: '{$url}'});});"));
- }
- elseif($oldAction->objectType == 'board')
- {
- $board = $this->loadModel('board')->getCanvas($oldAction->objectID);
- $isDeleted = $this->dao->select('deleted')->from(TABLE_BOARD_LIB)->where('id')->eq($board->lib)->fetch('deleted');
- $url = $this->createLink('action', 'trash', "browseType=boardspace");
- if($isDeleted) return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.confirm({message: '{$this->lang->action->undeleteBoardTip}'}).then((res) => {if(res) loadPage('{$url}');});"));
- }
- elseif($oldAction->objectType == 'doctemplate')
- {
- $templateScopeAndType = $this->dao->select('id,lib,module')->from(TABLE_DOC)->where('id')->eq($oldAction->objectID)->fetchAll('id');
- $scopeID = zget($templateScopeAndType[$oldAction->objectID], 'lib', 0);
- $typeID = zget($templateScopeAndType[$oldAction->objectID], 'module', 0);
- if($confirmChange == 'no')
- {
- $isDeletedType = $this->dao->select('deleted')->from(TABLE_MODULE)->where('type')->eq('docTemplate')->andWhere('id')->eq($typeID)->fetch('deleted');
- $isDeletedScope = $this->dao->select('deleted')->from(TABLE_DOCLIB)->where('type')->eq('template')->andWhere('id')->eq($scopeID)->fetch('deleted');
- if($isDeletedType == '1' || $isDeletedScope == '1')
- {
- $url = $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes");
- return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.confirm({message: '{$this->lang->action->undeleteTemplateTip}', icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) => {if(res) $.ajaxSubmit({url: '{$url}'});});"));
- }
- }
- if($confirmChange == 'yes')
- {
- $this->dao->update(TABLE_DOCLIB)->set('deleted')->eq('0')->where('id')->eq($scopeID)->exec();
- $this->dao->update(TABLE_MODULE)->set('deleted')->eq('0')->where('id')->eq($typeID)->exec();
- $parentType = $this->dao->select('parent')->from(TABLE_MODULE)->where('id')->eq($typeID)->fetch('parent');
- if(!empty($parentType)) $this->dao->update(TABLE_MODULE)->set('deleted')->eq('0')->where('id')->eq($parentType)->exec();
- }
- }
- $result = $this->action->undelete($actionID);
- if(true !== $result) return $this->send(array('result' => 'fail', 'load' => array('confirm' => $result)));
- $extra = $oldAction->extra == actionModel::BE_HIDDEN ? 'hidden' : 'all';
- $sameTypeObjects = $this->action->getTrashes($oldAction->objectType, $extra, 'id_desc', null);
- $browseType = ($sameTypeObjects && $browseType != 'all') ? $oldAction->objectType : 'all';
- return $this->send(array('result' => 'success', 'load' => $this->createLink('action', 'trash', "browseType=$browseType&type=$extra")));
- }
- /**
- * 隐藏一个已经被删除的对象。
- * Hide an deleted object.
- *
- * @param int $actionID
- * @param string $browseType
- * @access public
- * @return void
- */
- public function hideOne($actionID, $browseType = 'all')
- {
- $result = $this->actionZen->checkActionExist($actionID);
- if(is_array($result) && isset($result['result']) && $result['result'] == 'fail') return $this->send($result);
- $this->action->hideOne($actionID);
- $oldAction = $result;
- $sameTypeObjects = $this->action->getTrashes($oldAction->objectType, 'all', 'id_desc', null);
- $browseType = ($sameTypeObjects && $browseType != 'all') ? $oldAction->objectType : 'all';
- return $this->send(array('result' => 'success', 'load' => $this->createLink('action', 'trash', "browseType={$browseType}")));
- }
- /**
- * 隐藏所有被删除的对象。
- * Hide all deleted objects.
- *
- * @param string $confirm yes|no
- * @access public
- * @return void
- */
- public function hideAll($confirm = 'no')
- {
- if($confirm == 'no')
- {
- $url = inlink('hideAll', "confirm=yes");
- $message = $this->lang->action->confirmHideAll;
- return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.confirm({message: '{$message}', icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) => {if(res) $.ajaxSubmit({url: '{$url}'});});"));
- }
- $this->action->hideAll();
- return $this->send(array('result' => 'success', 'load' => true));
- }
- /**
- * 评论。
- * Comment.
- *
- * @param string $objectType
- * @param int $objectID
- * @access public
- * @return void
- */
- public function comment($objectType, $objectID)
- {
- if(!empty($_POST))
- {
- $isInZinPage = isInModal() || in_array($objectType, $this->config->action->newPageModule);
- /* 当评论的是任务,需判断当前用户是否拥有任务的权限。 */
- /* When commenting on a task, you need to determine whether the current user has the permission of the task. */
- if(strtolower($objectType) == 'task')
- {
- $task = $this->loadModel('task')->getById($objectID);
- $executions = explode(',', $this->app->user->view->sprints);
- if(!in_array($task->execution, $executions)) return $this->send(array('result' => 'fail', 'message' => $this->lang->error->accessDenied));
- }
- /* 当评论的是用户故事,需判断当前用户是否有此用户故事的权限。 */
- /* When commenting on a story, you need to determine whether the current user has the permission of the story. */
- elseif(strtolower($objectType) == 'story')
- {
- $story = $this->loadModel('story')->getById($objectID);
- $executions = explode(',', $this->app->user->view->sprints);
- $products = explode(',', $this->app->user->view->products);
- if(!array_intersect(array_keys($story->executions), $executions) && !in_array($story->product, $products) && empty($story->lib)) return $this->send(array('result' => 'fail', 'message' => $this->lang->error->accessDenied));
- }
- /* 获取评论内容并生成一条action数据。 */
- $commentData = form::data($this->config->action->form->comment)
- ->setIF($this->post->comment, 'actioncomment', $this->post->comment)
- ->get();
- if(!$commentData->actioncomment && $_FILES)
- {
- $files = array_filter($_FILES['files']['name']);
- if(!empty($files)) $commentData->actioncomment = implode(',', $files);
- }
- if($commentData->actioncomment)
- {
- $actionID = $this->action->create($objectType, $objectID, 'Commented', $commentData->actioncomment);
- if(empty($actionID))
- {
- if($isInZinPage) return $this->send(array('result' => 'fail', 'message' => $this->lang->error->accessDenied));
- return print(js::error($this->lang->error->accessDenied));
- }
- if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'data' => $actionID));
- }
- if($isInZinPage) return $this->send(array('status' => 'success', 'closeModal' => true, 'callback' => array('name' => 'zui.HistoryPanel.update', 'params' => array('objectType' => $objectType, 'objectID' => (int)$objectID))));
- /* 用于旧页面。*/
- /* For oldPage. */
- return print(js::reload('parent'));
- }
- $this->view->title = $this->lang->action->create;
- $this->view->objectType = $objectType;
- $this->view->objectID = $objectID;
- $this->display();
- }
- /**
- * 编辑评论。
- * Edit comment.
- *
- * @param int $actionID
- * @access public
- * @return void
- */
- public function editComment($actionID)
- {
- $action = $this->action->getById($actionID);
- if(!empty($_POST))
- {
- /* 获取表单内的数据。 */
- /* Get form data. */
- $commentData = form::data($this->config->action->form->editComment)->get();
- $error = false;
- /* 判断是否符合更新的条件。 */
- /* Determine whether the update conditions are met. */
- if(strlen(trim(strip_tags($commentData->lastComment, '<img>'))) != 0)
- {
- $error = $this->action->updateComment($actionID, $commentData);
- }
- if(!$error)
- {
- /* 不符合更新条件,返回错误。 */
- /* The update conditions are not met and an error is returned. */
- dao::$errors['submit'][] = $this->lang->action->historyEdit;
- return $this->send(array('result' => 'fail', 'message' => dao::getError()));
- }
- $action = $this->action->getById($actionID);
- if(isInModal() || in_array($action->objectType, $this->config->action->newPageModule))
- {
- return $this->send(array('status' => 'success', 'closeModal' => true, 'callback' => array('name' => 'zui.HistoryPanel.update', 'params' => array('objectType' => $action->objectType, 'objectID' => (int)$action->objectID))));
- }
- return $this->send(array('result' => 'success', 'locate' => 'reload'));
- }
- $action = $this->loadModel('file')->replaceImgURL($action, 'comment');
- $this->view->title = $this->lang->action->editComment;
- $this->view->actionID = $actionID;
- $this->view->objectType = $action->objectType;
- $this->view->comment = $this->action->formatActionComment($action->comment);
- $this->view->files = $this->file->getByObject('comment', $actionID);
- $this->display();
- }
- /**
- * 通过 Ajax 获取操作记录列表。
- * Get action list by ajax.
- *
- * @param string $objectType
- * @param int $objectID
- * @access public
- * @return void
- */
- public function ajaxGetList($objectType, $objectID)
- {
- $this->app->loadLang($objectType);
- $actions = $this->action->getList($objectType, $objectID);
- $actions = $this->action->buildActionList($actions);
- return $this->send($actions);
- }
- /**
- * Clear dynamic records older than one month.
- *
- * @access public
- * @return void
- */
- public function cleanActions()
- {
- $this->action->cleanActions();
- }
- /**
- * 通过 Ajax 获取该日期的更多记录。
- * Get more actions by ajax.
- *
- * @param int $lastActionID
- * @access public
- * @return void
- */
- public function ajaxGetMoreActions($lastActionID)
- {
- $actions = $this->action->getMoreActions($lastActionID);
- $lastAction = end($actions);
- $this->view->actions = $actions;
- $this->view->hasMore = $lastAction ? $this->action->hasMoreAction($lastAction) : false;
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
- $this->display();
- }
- }
|