* action: make history work in compatible mode.

This commit is contained in:
sunhao
2023-11-21 10:21:19 +08:00
parent 13f1f67aad
commit 5128fb123e
5 changed files with 267 additions and 25 deletions
+11 -1
View File
@@ -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())
);
+103
View File
@@ -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
View File
@@ -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.
*
+28
View File
@@ -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)
);
+29
View File
@@ -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)
);