* action: make history work in compatible mode.
This commit is contained in:
@@ -20,6 +20,7 @@ class history extends wg
|
||||
'actions?: array', // 操作列表数据。
|
||||
'users?: array', // 用户 Map 数据。
|
||||
'commentUrl?: string', // 备注对话框 URL。
|
||||
'editCommentUrl?: string', // 修改备注对话框 URL。
|
||||
'title?: string|array', // 标题。
|
||||
'commentBtn?: string|array' // 是否允许添加备注。
|
||||
);
|
||||
@@ -74,7 +75,15 @@ class history extends wg
|
||||
|
||||
protected function build(): wg
|
||||
{
|
||||
list($panel, $objectID, $objectType, $title, $actions, $commentUrl, $commentBtn) = $this->prop(array('panel', 'objectID', 'objectType', 'title', 'actions', 'commentUrl', 'commentBtn'));
|
||||
global $config;
|
||||
|
||||
list($panel, $objectID, $objectType, $title, $actions, $commentUrl, $editCommentUrl, $commentBtn) = $this->prop(array('panel', 'objectID', 'objectType', 'title', 'actions', 'commentUrl', 'editCommentUrl', 'commentBtn'));
|
||||
|
||||
if(isset($config->zin->mode) && $config->zin->mode == 'compatible')
|
||||
{
|
||||
if(is_null($commentUrl)) $commentUrl = createLink('action', 'commentZin', "objectType=$objectType&objectID=$objectID");
|
||||
if(is_null($editCommentUrl)) $editCommentUrl = createLink('action', 'editCommentZin', 'actionID={actionID}');
|
||||
}
|
||||
|
||||
return zui::historyPanel
|
||||
(
|
||||
@@ -84,6 +93,7 @@ class history extends wg
|
||||
set::actions($actions),
|
||||
set::title($title),
|
||||
set::commentUrl($commentUrl),
|
||||
set::editCommentUrl($editCommentUrl),
|
||||
set::commentBtn($commentBtn),
|
||||
set($this->getRestProps())
|
||||
);
|
||||
|
||||
@@ -357,6 +357,48 @@ class action extends control
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论。
|
||||
* Comment.
|
||||
*
|
||||
* @param string $objectType
|
||||
* @param int $objectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function commentZin(string $objectType, int $objectID)
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
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));
|
||||
}
|
||||
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) and !in_array($story->product, $products) and empty($story->lib)) return $this->send(array('result' => 'fail', 'message' => $this->lang->error->accessDenied));
|
||||
}
|
||||
|
||||
$actionID = $this->action->create($objectType, $objectID, 'Commented', $this->post->comment);
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api')
|
||||
{
|
||||
return $this->send(array('status' => 'success', 'data' => $actionID));
|
||||
}
|
||||
|
||||
return $this->send(array('status' => 'success', 'closeModal' => true, 'callback' => array('name' => 'zui.HistoryPanel.update', 'params' => array('objectType' => $objectType, 'objectID' => $objectID))));
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->action->create;
|
||||
$this->view->objectType = $objectType;
|
||||
$this->view->objectID = $objectID;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit comment of a action.
|
||||
*
|
||||
@@ -384,6 +426,51 @@ class action extends control
|
||||
return $this->send(array('result' => 'success', 'locate' => 'reload', 'load' => true, 'closeModal' => true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑评论。
|
||||
* Edit comment.
|
||||
*
|
||||
* @param int $actionID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function editCommentZin(int $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->lastComment, $commentData->uid);
|
||||
}
|
||||
|
||||
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);
|
||||
return $this->send(array('status' => 'success', 'closeModal' => true, 'callback' => array('name' => 'zui.HistoryPanel.update', 'params' => array('objectType' => $action->objectType, 'objectID' => $action->objectID))));
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->action->editComment;
|
||||
$this->view->actionID = $actionID;
|
||||
$this->view->comment = $this->action->formatActionComment($action->comment);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore stages.
|
||||
*
|
||||
@@ -474,4 +561,20 @@ class action extends control
|
||||
{
|
||||
$this->action->cleanActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 Ajax 获取操作记录列表。
|
||||
* Get action list by ajax.
|
||||
*
|
||||
* @param string $objectType
|
||||
* @param int $objectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetList(string $objectType, int $objectID)
|
||||
{
|
||||
$actions = $this->action->getList($objectType, $objectID);
|
||||
$actions = $this->action->buildActionList($actions);
|
||||
return $this->send($actions);
|
||||
}
|
||||
}
|
||||
|
||||
+96
-24
@@ -927,21 +927,29 @@ class actionModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印一个对象的所有操作记录。
|
||||
* Print actions of an object.
|
||||
*
|
||||
* @param object $action
|
||||
* @param string $desc
|
||||
* @param object $action
|
||||
* @param string $desc
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function renderAction($action, $desc = '')
|
||||
public function renderAction(object $action, string $desc = '')
|
||||
{
|
||||
if(!isset($action->objectType) || !isset($action->action)) return;
|
||||
if(!isset($action->objectType) || !isset($action->action)) return false;
|
||||
|
||||
$objectType = $action->objectType;
|
||||
$actionType = strtolower($action->action);
|
||||
|
||||
/**
|
||||
*
|
||||
* 设置操作的描述。
|
||||
*
|
||||
* 1. 如果模块中定义了操作的描述,使用模块中定义的。
|
||||
* 2. 如果模块中没有定义,使用公共的操作描述。
|
||||
* 3. 如果公共的操作描述中没有定义,使用默认的操作描述。
|
||||
*
|
||||
* Set the desc string of this action.
|
||||
*
|
||||
* 1. If the module of this action has defined desc of this actionType, use it.
|
||||
@@ -950,39 +958,39 @@ class actionModel extends model
|
||||
*/
|
||||
if(empty($desc))
|
||||
{
|
||||
if($action->objectType == 'story' && $action->action == 'reviewed' && strpos($action->extra, ',') !== false)
|
||||
if(($action->objectType == 'story' or $action->objectType == 'demand') && $action->action == 'reviewed' && strpos($action->extra, ',') !== false)
|
||||
{
|
||||
$desc = $this->lang->$objectType->action->rejectreviewed;
|
||||
$desc = $this->lang->{$objectType}->action->rejectreviewed;
|
||||
}
|
||||
elseif($action->objectType == 'productplan' && in_array($action->action, array('startedbychild','finishedbychild','closedbychild','activatedbychild', 'createchild')))
|
||||
{
|
||||
$desc = $this->lang->$objectType->action->changebychild;
|
||||
$desc = $this->lang->{$objectType}->action->changebychild;
|
||||
}
|
||||
elseif($action->objectType == 'module' && in_array($action->action, array('created', 'moved', 'deleted')))
|
||||
{
|
||||
$desc = $this->lang->$objectType->action->{$action->action};
|
||||
$desc = $this->lang->{$objectType}->action->{$action->action};
|
||||
}
|
||||
elseif(strpos('createmr,editmr,removemr', $action->action) !== false && strpos($action->extra, '::') !== false)
|
||||
{
|
||||
$mrAction = str_replace('mr', '', $action->action) . 'Action';
|
||||
list($mrDate, $mrActor, $mrLink) = explode('::', $action->extra);
|
||||
|
||||
if(isonlybody()) $mrLink .= ($this->config->requestType == 'GET' ? '&onlybody=yes' : '?onlybody=yes');
|
||||
if(isInModal()) $mrLink .= ($this->config->requestType == 'GET' ? '&onlybody=yes' : '?onlybody=yes');
|
||||
|
||||
$this->app->loadLang('mr');
|
||||
$desc = sprintf($this->lang->mr->$mrAction, $mrDate, $mrActor, $mrLink);
|
||||
$desc = sprintf($this->lang->mr->{$mrAction}, $mrDate, $mrActor, $mrLink);
|
||||
}
|
||||
elseif($this->config->edition == 'max' && strpos($this->config->action->assetType, ",{$action->objectType},") !== false && $action->action == 'approved')
|
||||
elseif(in_array($this->config->edition, array('max', 'ipd')) && strpos($this->config->action->assetType, ",{$action->objectType},") !== false && $action->action == 'approved')
|
||||
{
|
||||
$desc = empty($this->lang->action->approve->{$action->extra}) ? '' : $this->lang->action->approve->{$action->extra};
|
||||
}
|
||||
elseif(isset($this->lang->$objectType) && isset($this->lang->$objectType->action->$actionType))
|
||||
elseif(isset($this->lang->{$objectType}) && isset($this->lang->{$objectType}->action->{$actionType}))
|
||||
{
|
||||
$desc = $this->lang->$objectType->action->$actionType;
|
||||
$desc = $this->lang->{$objectType}->action->{$actionType};
|
||||
}
|
||||
elseif($action->objectType == 'instance' && isset($this->lang->action->desc->$actionType))
|
||||
elseif($action->objectType == 'instance' && isset($this->lang->action->desc->{$actionType}))
|
||||
{
|
||||
$desc = $this->lang->action->desc->$actionType;
|
||||
$desc = $this->lang->action->desc->{$actionType};
|
||||
$extra = json_decode($action->extra);
|
||||
if($actionType == 'adjustmemory')
|
||||
{
|
||||
@@ -991,7 +999,6 @@ class actionModel extends model
|
||||
}
|
||||
if(!empty($extra))
|
||||
{
|
||||
if(empty($extra->data)) $extra->data = new stdclass();
|
||||
$action->oldName = zget($extra->data, 'oldName', '');
|
||||
$action->newName = zget($extra->data, 'newName', '');
|
||||
$action->oldVersion = zget($extra->data, 'oldVersion', '');
|
||||
@@ -1004,15 +1011,15 @@ class actionModel extends model
|
||||
$action->extra = '';
|
||||
|
||||
if(!empty($extra->result->code) && $extra->result->code != 200 && !empty($extra->result->message)) $action->comment = $extra->result->message;
|
||||
if(is_string($extra->result) && $extra->result != 'fail' && !empty($extra->message))
|
||||
if(is_string($extra->result) && $extra->result != 'fail')
|
||||
{
|
||||
$action->comment = "\n" . $extra->message;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(isset($this->lang->action->desc->$actionType))
|
||||
elseif(isset($this->lang->action->desc->{$actionType}))
|
||||
{
|
||||
$desc = $this->lang->action->desc->$actionType;
|
||||
$desc = $this->lang->action->desc->{$actionType};
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1023,11 +1030,13 @@ class actionModel extends model
|
||||
$action->date = substr($action->date, 0, 19);
|
||||
if($this->app->getViewType() == 'mhtml') $action->date = date('m-d H:i', strtotime($action->date));
|
||||
|
||||
/* 遍历actions, 替换变量。 */
|
||||
/* Cycle actions, replace vars. */
|
||||
foreach($action as $key => $value)
|
||||
{
|
||||
if($key == 'history') continue;
|
||||
|
||||
/* 如果desc是数组,替换变量。 */
|
||||
/* Desc can be an array or string. */
|
||||
if(is_array($desc))
|
||||
{
|
||||
@@ -1043,19 +1052,20 @@ class actionModel extends model
|
||||
}
|
||||
else
|
||||
{
|
||||
if($actionType == 'restoredsnapshot' && in_array($action->objectType, array('vm', 'zanode')) && $value == 'defaultSnap') $value = $this->lang->$objectType->snapshot->defaultSnapName;
|
||||
if($actionType == 'restoredsnapshot' && in_array($action->objectType, array('vm', 'zanode')) && $value == 'defaultSnap') $value = $this->lang->{$objectType}->snapshot->defaultSnapName;
|
||||
|
||||
$desc = str_replace('$' . $key, $value, $desc);
|
||||
}
|
||||
}
|
||||
|
||||
/* 如果desc是数组,处理extra。 */
|
||||
/* If the desc is an array, process extra. Please bug/lang. */
|
||||
if(!is_array($desc)) return $desc;
|
||||
|
||||
$extra = strtolower($action->extra);
|
||||
|
||||
/* Fix bug #741. */
|
||||
if(isset($desc['extra'])) $desc['extra'] = $this->lang->$objectType->{$desc['extra']};
|
||||
if(isset($desc['extra'])) $desc['extra'] = $this->lang->{$objectType}->{$desc['extra']};
|
||||
|
||||
$actionDesc = '';
|
||||
if(isset($desc['extra'][$extra]))
|
||||
@@ -1067,12 +1077,12 @@ class actionModel extends model
|
||||
$actionDesc = str_replace('$extra', $action->extra, $desc['main']);
|
||||
}
|
||||
|
||||
if($action->objectType == 'story' && $action->action == 'reviewed')
|
||||
if(($action->objectType == 'story' or $action->objectType == 'demand') && $action->action == 'reviewed')
|
||||
{
|
||||
if(strpos($action->extra, ',') !== false)
|
||||
{
|
||||
list($extra, $reason) = explode(',', $extra);
|
||||
$desc['reason'] = $this->lang->$objectType->{$desc['reason']};
|
||||
$desc['reason'] = $this->lang->{$objectType}->{$desc['reason']};
|
||||
$actionDesc = str_replace(array('$extra', '$reason'), array($desc['extra'][$extra], $desc['reason'][$reason]), $desc['main']);
|
||||
}
|
||||
|
||||
@@ -1088,7 +1098,7 @@ class actionModel extends model
|
||||
if(!empty($extra) && strpos($extra, '|') !== false)
|
||||
{
|
||||
list($operate, $storyID) = explode('|', $extra);
|
||||
$desc['operate'] = $this->lang->$objectType->{$desc['operate']};
|
||||
$desc['operate'] = $this->lang->{$objectType}->{$desc['operate']};
|
||||
$link = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$storyID"), "#$storyID ") : "#$storyID";
|
||||
$actionDesc = str_replace(array('$extra', '$operate'), array($link, $desc['operate'][$operate]), $desc['main']);
|
||||
}
|
||||
@@ -1111,6 +1121,68 @@ class actionModel extends model
|
||||
return $actionDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化操作备注。
|
||||
* Format action comment.
|
||||
*
|
||||
* @param string $comment
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function formatActionComment($comment): string
|
||||
{
|
||||
if(str_contains($comment, '<pre class="prettyprint lang-html">'))
|
||||
{
|
||||
$before = explode('<pre class="prettyprint lang-html">', $comment);
|
||||
$after = explode('</pre>', $before[1]);
|
||||
$htmlCode = $after[0];
|
||||
return $before[0] . htmlspecialchars($htmlCode) . $after[1];
|
||||
}
|
||||
|
||||
return strip_tags($comment) === $comment
|
||||
? nl2br($comment)
|
||||
: $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建操作记录列表,便于前端组件进行渲染。
|
||||
* Build action list for render by frontend component.
|
||||
*
|
||||
* @param array $actions
|
||||
* @param array $users
|
||||
* @param bool $commentEditable
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function buildActionList(array $actions, array $users = null, $commentEditable = true): array
|
||||
{
|
||||
if(empty($users)) $users = $this->loadModel('user')->getPairs('noletter');
|
||||
|
||||
$list = array();
|
||||
foreach($actions as $action)
|
||||
{
|
||||
$item = new stdClass();
|
||||
if(strlen(trim(($action->comment))) !== 0)
|
||||
{
|
||||
$item->comment = $this->formatActionComment($action->comment);
|
||||
$item->commentEditable = $commentEditable && end($actions) == $action && $action->actor == $this->app->user->account && common::hasPriv('action', 'editComment');
|
||||
}
|
||||
|
||||
if($action->action === 'assigned' || $action->action === 'toaudit') $action->extra = zget($users, $action->extra);
|
||||
$action->actor = zget($users, $action->actor);
|
||||
if(str_contains($action->actor, ':')) $action->actor = substr($action->actor, strpos($action->actor, ':') + 1);
|
||||
|
||||
if(!empty($action->history)) $item->historyChanges = $this->renderChanges($action->objectType, $action->history);
|
||||
|
||||
$item->id = $action->id;
|
||||
$item->action = $action->action;
|
||||
$item->content = $this->renderAction($action);
|
||||
|
||||
$list[] = $item;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print changes of every action.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The comment view file of action module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Hao Sun <sunhao@easycorp.ltd>
|
||||
* @package action
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
$actions = array();
|
||||
$actions[] = 'submit';
|
||||
$actions[] = array('data-dismiss' => 'modal', 'text' => $lang->close);
|
||||
|
||||
set::title($title);
|
||||
|
||||
form
|
||||
(
|
||||
set::url('action', 'commentZin', "objectType=$objectType&objectID=$objectID"),
|
||||
setClass('comment-form'),
|
||||
editor
|
||||
(
|
||||
set::name('actioncomment')
|
||||
),
|
||||
set::actions($actions)
|
||||
);
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The comment view file of action module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Hao Sun <sunhao@easycorp.ltd>
|
||||
* @package action
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
$actions = array();
|
||||
$actions[] = 'submit';
|
||||
$actions[] = isInModal() ? array('data-dismiss' => 'modal', 'text' => $lang->close) : 'cancel';
|
||||
|
||||
set::title($title);
|
||||
|
||||
form
|
||||
(
|
||||
set::url('action', 'editComment', "actionID=$actionID"),
|
||||
setClass('comment-form is-edit'),
|
||||
editor
|
||||
(
|
||||
set::name('lastComment'),
|
||||
html($comment)
|
||||
),
|
||||
set::actions($actions)
|
||||
);
|
||||
Reference in New Issue
Block a user