diff --git a/module/common/model.php b/module/common/model.php index b156a20753..57ac36ba67 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -2492,6 +2492,49 @@ class commonModel extends model } } } + + /** + * Check operate effort. + * + * @param object $effort + * @access public + * @return bool + */ + public function canOperateEffort(object $effort) + { + if($this->app->user->admin) return true; + + if(empty((array)$effort)) return true; + + $actor = $effort->account; + + /* 如果是本人,可以直接修改。 */ + if($actor == $this->app->user->account) return true; + + /* 如果当前账户是项目负责人,则可以修改团队成员日志。*/ + if(!empty($effort->project)) + { + $PM = $this->dao->select('PM')->from(TABLE_PROJECT)->where('id')->eq($effort->project)->fetch('PM'); + if($PM == $this->app->user->account) return true; + } + + /* 如果当前账户是执行负责人,则可以修改团队成员日志。*/ + if(!empty($effort->execution)) + { + $PM = $this->dao->select('PM')->from(TABLE_PROJECT)->where('id')->eq($effort->execution)->fetch('PM'); + if($PM == $this->app->user->account) return true; + } + + /* 如果当前账户是上级部门(包括当前部门)负责人,则可以修改下属员工的日志。*/ + $actorDeptPath = $this->dao->select('path')->from(TABLE_DEPT)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t2.dept = t1.id') + ->where('t2.account')->eq($actor) + ->fetch('path'); + $deptManagers = $this->dao->select('manager')->from(TABLE_DEPT)->where('id')->in(explode(',', trim($actorDeptPath, ',')))->fetchPairs(); + if(in_array($this->app->user->account, $deptManagers)) return true; + + return false; + } } class common extends commonModel diff --git a/module/common/test/model/canoperateeffort.php b/module/common/test/model/canoperateeffort.php new file mode 100755 index 0000000000..6b7ee6d181 --- /dev/null +++ b/module/common/test/model/canoperateeffort.php @@ -0,0 +1,92 @@ +#!/usr/bin/env php +gen(30); + +$project = zdTable('project'); +$project->id->range('1-5'); +$project->project->range('0'); +$project->name->prefix("项目")->range('1-5'); +$project->code->prefix("project")->range('1-5'); +$project->PM->range('admin,user1,user2,user3,user4'); +$project->model->range("scrum"); +$project->auth->range("[]"); +$project->path->range("[]"); +$project->type->range("project"); +$project->grade->range("1"); +$project->days->range("5"); +$project->status->range("wait"); +$project->desc->range("[]"); +$project->budget->range("100000,200000"); +$project->budgetUnit->range("CNY"); +$project->percent->range("0-0"); +$project->gen(5); + +$execution = zdTable('project'); +$execution->id->range('6-10'); +$execution->project->range('1-5'); +$execution->name->prefix("执行")->range('1-5'); +$execution->code->prefix("execution")->range('1-5'); +$execution->PM->range('user4,user5,user6,user7,user8'); +$execution->auth->range("[]"); +$execution->path->range("[]"); +$execution->type->range("sprint"); +$execution->grade->range("1"); +$execution->days->range("5"); +$execution->status->range("wait"); +$execution->desc->range("[]"); +$execution->gen(5, true, false); + +$dept = zdTable('dept')->config('dept'); +$dept->manager->range('admin,user1,user2,user3,user4'); +$dept->gen(50); + +/** + +title=commonModel->canOperateEffort(); +timeout=0 +cid=1 + +*/ + +global $tester; +$tester->loadModel('common'); + +$effort = new stdclass(); +$effort->account = 'admin'; +r($tester->common->canOperateEffort($effort)) && p() && e('1'); //判断当前用户是管理员 + +unset($effort->account); +r($tester->common->canOperateEffort($effort)) && p() && e('1'); //判断日志为空的情况 + +su('user1'); +$effort->account = 'user2'; +r($tester->common->canOperateEffort($effort)) && p() && e('0'); //判断当前用户不是日志的记录者的情况 + +$effort->account = 'user1'; +r($tester->common->canOperateEffort($effort)) && p() && e('1'); //判断当前用户是日志的记录者的情况 + +$effort->project = 2; +r($tester->common->canOperateEffort($effort)) && p() && e('1'); //判断当前用户是日志所属项目管理者的情况 + +$effort->account = 'user4'; +$effort->project = 3; +r($tester->common->canOperateEffort($effort)) && p() && e('0'); //判断当前用户不是日志所属项目管理者的情况 + +su('user5'); +$effort->project = 2; +$effort->execution = 7; +r($tester->common->canOperateEffort($effort)) && p() && e('1'); //判断当前用户是日志所属执行负责人的情况 + +su('user6'); +r($tester->common->canOperateEffort($effort)) && p() && e('0'); //判断当前用户不是日志所属执行负责人的情况 + +$effort->project = 0; +$effort->execution = 0; +r($tester->common->canOperateEffort($effort)) && p() && e('0'); //判断当前用户不是部门负责人的情况 + +su('user2'); +$effort->account = 'user23'; +r($tester->common->canOperateEffort($effort)) && p() && e('1'); //判断当前用户是部门负责人的情况 diff --git a/module/task/lang/de.php b/module/task/lang/de.php index 7b791a3c2c..2bcbfb482e 100644 --- a/module/task/lang/de.php +++ b/module/task/lang/de.php @@ -177,6 +177,7 @@ $lang->task->teamMember = 'Team Member'; $lang->task->addMember = 'Add Member'; $lang->task->to = 'To'; $lang->task->suffixHour = 'h'; +$lang->task->update = 'Update'; /* Fields of zt_taskestimate. */ $lang->task->task = 'Task'; @@ -277,6 +278,7 @@ $lang->task->createDenied = "Aufgben erstellen it in diesem {$lang- $lang->task->cannotDeleteParent = 'Cannot delete parent task'; $lang->task->addChildTask = 'Because the task has already consumed consumption, to ensure data consistency, we will help you create a subtask with the same name to record the consumption.'; $lang->task->selectTestStoryTip = "The following {$lang->SRCommon} will be subtasks of this task"; +$lang->task->effortOperateTips = 'Only the project manager, the executive supervisor, and the department head have the authority to %s logs belonging to others.'; $lang->task->error = new stdclass(); $lang->task->error->totalNumber = '"Total Cost" must be numbers.'; diff --git a/module/task/lang/en.php b/module/task/lang/en.php index eaf5dbd307..3f03aea094 100755 --- a/module/task/lang/en.php +++ b/module/task/lang/en.php @@ -177,6 +177,7 @@ $lang->task->teamMember = 'Team Member'; $lang->task->addMember = 'Add Member'; $lang->task->to = 'To'; $lang->task->suffixHour = 'h'; +$lang->task->update = 'Update'; /* Fields of zt_taskestimate. */ $lang->task->task = 'Task'; @@ -277,6 +278,7 @@ $lang->task->createDenied = 'Create Task is denied in this ' . $lan $lang->task->cannotDeleteParent = 'Cannot delete parent task'; $lang->task->addChildTask = 'Because the task has cost hours, ZenTao will create a child task with the same name to record the cost housrs to ensure data consistency.'; $lang->task->selectTestStoryTip = "The following {$lang->SRCommon} will be subtasks of this task"; +$lang->task->effortOperateTips = 'Only the project manager, the executive supervisor, and the department head have the authority to %s logs belonging to others.'; $lang->task->error = new stdclass(); $lang->task->error->totalNumber = '"Total Cost" must be numbers.'; diff --git a/module/task/lang/fr.php b/module/task/lang/fr.php index 6f3454ad6f..0eaf8d9766 100644 --- a/module/task/lang/fr.php +++ b/module/task/lang/fr.php @@ -177,6 +177,7 @@ $lang->task->teamMember = 'Team Member'; $lang->task->addMember = 'Add Member'; $lang->task->to = 'To'; $lang->task->suffixHour = 'h'; +$lang->task->update = 'Update'; /* Fields of zt_taskestimate. */ $lang->task->task = 'Task'; @@ -277,6 +278,7 @@ $lang->task->createDenied = 'La création de tâches est interdite $lang->task->cannotDeleteParent = 'Impossible de supprimer la tâche parente'; $lang->task->addChildTask = 'Because the task has already consumed consumption, to ensure data consistency, we will help you create a subtask with the same name to record the consumption.'; $lang->task->selectTestStoryTip = "The following {$lang->SRCommon} will be subtasks of this task"; +$lang->task->effortOperateTips = 'Only the project manager, the executive supervisor, and the department head have the authority to %s logs belonging to others.'; $lang->task->error = new stdclass(); $lang->task->error->totalNumber = '"Coût Total" doit être numérique.'; diff --git a/module/task/lang/zh-cn.php b/module/task/lang/zh-cn.php index 243b2011e2..79db760334 100755 --- a/module/task/lang/zh-cn.php +++ b/module/task/lang/zh-cn.php @@ -177,6 +177,7 @@ $lang->task->teamMember = '团队成员'; $lang->task->addMember = '添加成员'; $lang->task->to = '至'; $lang->task->suffixHour = 'h'; +$lang->task->update = '更新'; /* Fields of zt_taskestimate. */ $lang->task->task = '任务'; @@ -277,6 +278,7 @@ $lang->task->createDenied = "你不能在该{$lang->projectCommon} $lang->task->cannotDeleteParent = '不能删除父任务。'; $lang->task->addChildTask = '因该任务已经产生消耗,为保证数据一致性,我们会帮您创建一条同名子任务记录该消耗。'; $lang->task->selectTestStoryTip = "以下{$lang->SRCommon}将作为此任务的子任务"; +$lang->task->effortOperateTips = '只有项目负责人、执行负责人、所属部门负责人才能%s他人日志。'; $lang->task->error = new stdclass(); $lang->task->error->totalNumber = '"耗时"必须为数字'; diff --git a/module/task/model.php b/module/task/model.php index 270fa134a2..3f9f7153bb 100755 --- a/module/task/model.php +++ b/module/task/model.php @@ -667,7 +667,11 @@ class taskModel extends model */ public function canOperateEffort(object $task, object $effort = null): bool { - if(empty($task->team)) return true; + if(empty($task->team)) + { + if($effort === null) $effort = new stdclass(); + return $this->loadModel('common')->canOperateEffort($effort); + } /* Check for add effort. */ if(empty($effort)) diff --git a/module/task/ui/recordworkhour.html.php b/module/task/ui/recordworkhour.html.php index 4740624a27..d4acdeac18 100644 --- a/module/task/ui/recordworkhour.html.php +++ b/module/task/ui/recordworkhour.html.php @@ -63,6 +63,8 @@ if($efforts) $effortRows = array(); foreach($efforts as $effort) { + $canOperateEffort = $this->task->canOperateEffort($task, $effort); + $operateTips = $canOperateEffort ? '' : $lang->task->effortOperateTips; $effortRows[] = h::tr ( h::td($effort->id), @@ -77,6 +79,8 @@ if($efforts) ( setClass('btn ghost toolbar-item square size-sm text-primary edit-effort'), on::click()->call('loadModal', createLink('task', 'editEffort', "id={$effort->id}")), + !$canOperateEffort ? set::disabled(true) : null, + set::title($operateTips ? sprintf($operateTips, $lang->task->update) : ''), icon('edit'), ) : null, common::hasPriv('task', 'deleteWorkhour') ? a @@ -84,6 +88,8 @@ if($efforts) setClass('btn ghost toolbar-item square size-sm ajax-submit text-primary'), set('data-confirm', $lang->task->confirmDeleteEffort), set::href(createLink('task', 'deleteWorkhour', "id={$effort->id}")), + !$canOperateEffort ? set::disabled(true) : null, + set::title($operateTips ? sprintf($operateTips, $lang->delete) : ''), icon('trash') ) : null )