Procházet zdrojové kódy

bug_fix: 修改了任务添加修改删除时权限判断有误的bug

eyes4 před 6 měsíci
rodič
revize
3d963f3195

+ 1 - 1
pmr-biz-manager/src/routes/api/prj/member/add.ts

@@ -41,7 +41,7 @@ export function statusGuard(json: IRequest, cached_data: ICachedData): Promise<v
         if (!prj_info) return reject(Resp.gen_err(Resp.ResourceNotFound));
         // if (prj_info.leader_id !== cached_data.user_id)
         if (!await is_project_modifiable(user, prj_info.id))
-            return reject(Resp.gen_err(Resp.Forbidden, '您没有权限添加项目组成员,请确认您是项目负责人ak。'));
+            return reject(Resp.gen_err(Resp.Forbidden, '您没有权限添加项目组成员,请确认您是项目负责人或特权人员。'));
         let phase = await PrjPhaseDefine.findOne({where: {id: prj_info.phase_id}, raw: true});
         if (!phase) return reject(Resp.gen_err(Resp.ResourceNotFound, '项目状态信息出错,id: ' + prj_info.id));
 

+ 33 - 22
pmr-biz-manager/src/routes/api/prj/plan/add_task.ts

@@ -15,7 +15,7 @@ import {BpmnModel} from "@core-models/BpmnModel";
 import {bpmn_flow_on_end} from "@src/utils/bpmn_work_helper";
 import {PrjPlanTaskDraft} from "@core-models/PrjPlanTaskDraft";
 import {ChangeMarker} from "@src/utils/define";
-import {is_project_modifiable} from "@src/utils/prj_premission_helper";
+import {is_project_modifiable, is_project_task_addable} from "@src/utils/prj_premission_helper";
 
 interface IData {
     /**
@@ -29,7 +29,7 @@ interface IData {
     /**
      * 计划结束时间(YYYY-MM-DD)
      */
-    end_at?: string;
+    end_at: string;
     /**
      * 负责人id
      */
@@ -49,28 +49,32 @@ interface IData {
     /**
      * 父级任务id,父级任务id,为空时表示本身是一级任务
      */
-    task_pid?: string|null;
+    task_pid?: string | null;
 }
 
-/// 项目任务提交申请后,只允许在副本中添加
-function statusGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
+function guard(json: IRequest, cached_data: ICachedData): Promise<void> {
     return new Promise<void>(async (resolve, reject) => {
         let user = cached_data.user_id;
         let data = <IData>json.data;
         if (!user) return reject(Resp.gen_err(Resp.Forbidden));
         if (user === ADMINISTRATOR) return resolve();
+        // 检查计划结束时间是否晚于计划开始时间
+        data.begin_at += ' 00:00:00';
+        data.end_at += ' 23:59:59';
+        if (dayjs(data.end_at).diff(dayjs(data.begin_at)) <= 0)
+            return reject(Resp.gen_err(Resp.ParamsError, '计划结束时间必须晚于计划开始时间。'));
         let prj_info = await PrjInfo.findOne({where: {id: data.prj_id}, raw: true});
         if (!prj_info) return reject(Resp.gen_err(Resp.ResourceNotFound));
-        // 检查用户是否是项目负责人,只有项目负责人或特权人员才可以添加任务
-        if (!await is_project_modifiable(user, prj_info.id)) {
+        // 只有项目负责人或特权人员才可以添加任务
+        if (!await is_project_task_addable(user, prj_info.id)) {
             return reject(Resp.gen_err(Resp.Forbidden, '您不是项目负责人或特权人员,不能添加任务。'));
         }
         let phase = await PrjPhaseDefine.findOne({where: {id: prj_info.phase_id}, raw: true});
         if (!phase) return reject(Resp.gen_err(Resp.ResourceNotFound, '项目状态信息出错,id: ' + prj_info.id));
         if (phase.order_index < 20) return reject(Resp.gen_err(Resp.InvalidFlow, '需要先对项目进行立项,立项后才可制订计划。'));
-        if (phase.order_index >=30 && phase.order_index <= 40 && data.draft === false)
+        if (phase.order_index >= 30 && phase.order_index <= 40 && data.draft === false)
             return reject(Resp.gen_err(Resp.InvalidFlow, '项目计划审核中,当前阶段不允许添加。'));
-        if (phase.order_index >= 60 && phase.order_index <=70 && data.draft === false)
+        if (phase.order_index >= 60 && phase.order_index <= 70 && data.draft === false)
             return reject(Resp.gen_err(Resp.InvalidFlow, '当前项目阶段不允许直接添加计划,应在草稿中修改后重新提交审核。'));
         if (phase.order_index >= 80) return reject(Resp.gen_err(Resp.InvalidFlow, '当前项目阶段不允许添加计划。'));
 
@@ -80,7 +84,7 @@ function statusGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
 
 // 如添加的是子任务,查找父任务是否存在
 // 如任务已经执行,不能再作为主任务添加子任务
-function checkParentGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
+function check_parent_guard(json: IRequest, cached_data: ICachedData): Promise<void> {
     return new Promise<void>(async (resolve, reject) => {
         let data = <IData>json.data;
         if (data.task_pid === undefined) return resolve();
@@ -100,10 +104,10 @@ function add(json: IRequest, params: IMethodParams, cached_data: ICachedData): P
         try {
             let user = cached_data.user_id;
             let data = <IData>json.data;
-            if (data.begin_at && data.end_at) {
-                if (dayjs(data.end_at).diff(data.begin_at) < 0)
-                    throw Resp.gen_err(Resp.IIllegalRequest, '任务预计完成时间不能早于或等于任务开始时间。')
-            }
+            // if (data.begin_at && data.end_at) {
+            //     if (dayjs(data.end_at).diff(data.begin_at) < 0)
+            //         throw Resp.gen_err(Resp.IIllegalRequest, '任务预计完成时间不能早于或等于任务开始时间。')
+            // }
 
             let id = IdGen.id();
 
@@ -113,14 +117,14 @@ function add(json: IRequest, params: IMethodParams, cached_data: ICachedData): P
                 prj_id: data.prj_id,
                 name: data.name,
                 handler_id: data.handler_id,
-                begin_at: data.begin_at + ' 00:00:00',
-                end_at: data.end_at ? data.end_at + ' 23:59:59' : null,
+                begin_at: data.begin_at,
+                end_at:  data.end_at,
                 creator_id: user,
                 description: data.description,
 
                 created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
                 order_id: IdGen.id(),
-                change_marker: data.draft? ChangeMarker.Added: undefined
+                change_marker: data.draft ? ChangeMarker.Added : undefined
             }
             value = DataCURD.filter_null(value);
 
@@ -130,17 +134,24 @@ function add(json: IRequest, params: IMethodParams, cached_data: ICachedData): P
             await update_parent_task_info(data.draft, data.prj_id, data.task_pid, t);
 
             // 检查计划审核工作流程是否已经启动,没有的话就建一个
-            let flow = await BpmnCase.findOne({where: {prj_id: data.prj_id, model_id: 'plan'}, transaction: t, raw: true});
+            let flow = await BpmnCase.findOne({
+                where: {prj_id: data.prj_id, model_id: 'plan'},
+                transaction: t,
+                raw: true
+            });
             if (!flow && data.draft === false) {
                 let bpmn = await BpmnModel.findOne({where: {id: 'plan'}, transaction: t});
                 if (!bpmn) throw Resp.gen_err(Resp.InternalServerError, '项目流程模型数据缺失!');
-                let flow = new FlowEngine(bpmn.id, bpmn.content, {prj_id: data.prj_id, owner: cached_data.user_id}, bpmn_flow_on_end);
+                let flow = new FlowEngine(bpmn.id, bpmn.content, {
+                    prj_id: data.prj_id,
+                    owner: cached_data.user_id
+                }, bpmn_flow_on_end);
                 await flow.run();
                 await BpmnCase.create({
                     id: flow.id,
                     model_id: bpmn.id,
                     model: bpmn.content,
-                    started_at: dayjs(),
+                    started_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
                     creator_id: cached_data.user_id,
                     prj_id: data.prj_id,
                     // state: await flow.state(),
@@ -148,7 +159,7 @@ function add(json: IRequest, params: IMethodParams, cached_data: ICachedData): P
             }
 
             /// 如果计划任务是草稿,且还没有生成计划变更任务,则生成任务
-            if (data.draft === true ) {
+            if (data.draft === true) {
                 await start_plan_alt_flow(data.prj_id, cached_data.user_id, t);
             }
 
@@ -247,7 +258,7 @@ const v1_0: IApiProcessor = {
     },
     method: add,
     method_params: {},
-    guards: [statusGuard, checkParentGuard]
+    guards: [guard, check_parent_guard]
 }
 
 

+ 2 - 8
pmr-biz-manager/src/routes/api/prj/plan/get_tasks.ts

@@ -230,9 +230,7 @@ function get_tasks(json: IRequest, params: IMethodParams, cached_data: ICachedDa
             let data = <IData>json.data;
             let prj = await PrjInfo.findOne({where: {id: data.prj_id}, raw: true});
             if (!prj) return reject(Resp.gen_err(Resp.DataExists, `项目不存在,id:${data.prj_id}`));
-            Logger.trace(prj);
             let phase = await PrjPhaseDefine.findOne({where: {id: prj.phase_id}, raw: true});
-            Logger.trace(phase);
             let result: any = {
                 status: phase!.order_index,
                 tasks: new Array<any>(),
@@ -245,12 +243,8 @@ function get_tasks(json: IRequest, params: IMethodParams, cached_data: ICachedDa
                     end_at: "rw"
                 } : clone(ui_status[prj.phase_id]),
             }
-            Logger.trace(`data.draft: ${data.draft} ui_status doing: `);
-            console.log(ui_status['doing']);
-            console.log(data.draft ? {"test": test}: ui_status[prj.phase_id]);
-            // 检查用户是否是项目负责人,只有项目负责人才可以修改任务
-            Logger.trace(`get_tasks: user_id: ${cached_data.user_id} leader_id: ${prj.leader_id}  alter: ${result.ui_status.alter}` );
-            if (cached_data.user_id !== prj.leader_id) {
+
+            if (cached_data.user_id !== prj.leader_id && prj.phase_id === 'doing') {
                 result.ui_status.alter = false;
             }
             let model = data.draft ? PrjPlanTaskDraft : PrjPlanTask;

+ 10 - 5
pmr-biz-manager/src/routes/api/prj/plan/modify_task.ts

@@ -62,8 +62,7 @@ function time_guard(json: IRequest, cached_data: ICachedData): Promise<void> {
     });
 }
 
-/// 项目任务提交申请后,不允许修改
-function statusGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
+function guard(json: IRequest, cached_data: ICachedData): Promise<void> {
     return new Promise<void>(async (resolve, reject) => {
         let user = cached_data.user_id;
         let data = <IData>json.data;
@@ -73,8 +72,8 @@ function statusGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
         let task = await model.findOne({where: {id: data.task_id}, raw: true});
         if (!task)
             return reject(Resp.gen_err(Resp.ResourceNotFound, '计划任务项不存在。'));
-        if (!await is_project_task_modifiable(user, task.id))
-            return reject(Resp.gen_err(Resp.Forbidden, '您没有权限修改任务。'));
+        if (!await is_project_task_modifiable(model, user, task.id))
+            return reject(Resp.gen_err(Resp.Forbidden, `您没有权限修改任务 ${task.id}。`));
 
         let prj_info = await PrjInfo.findOne({where: {id: task.prj_id}, raw: true});
         if (!prj_info) return reject(Resp.gen_err(Resp.ResourceNotFound));
@@ -119,6 +118,12 @@ function modify(json: IRequest, params: IMethodParams, cached_data: ICachedData)
 
             if (data.begin_at) data.begin_at += ' 00:00:00';
             if (data.end_at) data.end_at += ' 23:59:59';
+            // 检查起止时间是否合法
+            let begin_at = data.begin_at || task.begin_at;
+            let end_at = data.end_at || task.end_at;
+            if (dayjs(end_at).diff(dayjs(begin_at)) <= 0)
+                throw Resp.gen_err(Resp.ParamsError, '任务结束时间必须晚于开始时间。');
+
             if (data.draft) {
                 Logger.trace(`[prj-plan-task-modify] draft task:  ${data.task_id}, change_marker: ${(<PrjPlanTaskDraft>task).change_marker}`);
                 if ((<PrjPlanTaskDraft>task).change_marker !== ChangeMarker.Added) {
@@ -300,7 +305,7 @@ const v1_0: IApiProcessor = {
             description: "description"
         }
     },
-    guards: [time_guard, statusGuard]
+    guards: [time_guard, guard]
 }
 
 module.exports = {

+ 4 - 2
pmr-biz-manager/src/routes/api/prj/plan/recover_task.ts

@@ -5,8 +5,9 @@ import {Resp} from "@util/Resp";
 import {PrjPhaseDefine} from "@core-models/PrjPhaseDefine";
 import {update_parent_task_info} from "@src/utils/plan_task_helper";
 import {PrjPlanTaskDraft} from "@core-models/PrjPlanTaskDraft";
+import {PrjPlanTask} from "@core-models/PrjPlanTask";
 import {ChangeMarker} from "@src/utils/define";
-import {is_project_task_modifiable} from "../../../../utils/prj_premission_helper";
+import {is_project_task_modifiable} from "@src/utils/prj_premission_helper";
 
 interface IData {
     /**
@@ -34,7 +35,8 @@ function statusGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
         // if (cached_data.user_id !== prj_info.leader_id) {
         //     return reject(Resp.gen_err(Resp.Forbidden, '您不是项目负责人,不能恢复任务。'));
         // }
-        if (!await is_project_task_modifiable(user, task.id))
+
+        if (!await is_project_task_modifiable(PrjPlanTask, user, task.id))
             return reject(Resp.gen_err(Resp.Forbidden, '您没有权限恢复任务。'));
 
         if (task.change_marker !== ChangeMarker.Deleted) {

+ 1 - 1
pmr-biz-manager/src/routes/api/prj/plan/remove_task.ts

@@ -40,7 +40,7 @@ function statusGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
 
         let prj_info = await PrjInfo.findOne({where: {id: task.prj_id}, raw: true});
         if (!prj_info) return reject(Resp.gen_err(Resp.ResourceNotFound));
-        if (!await is_project_task_modifiable(user, task.id))
+        if (!await is_project_task_modifiable(model, user, task.id))
             return reject(Resp.gen_err(Resp.Forbidden, '您没有权限删除任务。'));
 
         if (task.status === TaskStatus.Completed || task.status === TaskStatus.Cancelled) {

+ 1 - 1
pmr-biz-manager/src/routes/api/prj/plan/set_check_flow.ts

@@ -55,7 +55,7 @@ function statusGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
         let prj_info = await PrjInfo.findOne({where: {id: task.prj_id}, raw: true});
         if (!prj_info) return reject(Resp.gen_err(Resp.ResourceNotFound));
 
-        if (!await is_project_task_modifiable(user, task.id))
+        if (!await is_project_task_modifiable(model, user, task.id))
             return reject(Resp.gen_err(Resp.Forbidden, '您没有权限设置任务审核流程。'));
 
         if (task.status >= TaskStatus.ApplyForReview)

+ 72 - 16
pmr-biz-manager/src/utils/prj_premission_helper.ts

@@ -3,12 +3,18 @@ import {PrjMembers} from "@core-models/PrjMembers";
 import {PrjInfo} from "@core-models/PrjInfo";
 import {QueryTypes} from "sequelize";
 import {PrjPlanTask} from "@core-models/PrjPlanTask";
+import {Logger} from "@util/Logger";
+import {PrjPlanTaskDraft} from "@core-models/PrjPlanTaskDraft";
 
 /// 是否是项目特权账户
 export async function is_project_privileged_account(account_id: string): Promise<boolean> {
     // 检查账户是否为特权账户
     let result = await AcsUserInfo.findOne({where: {id: account_id}, raw: true});
-    if (result && result.ext_info.full_range === true) return true;
+    if (result && result.ext_info.full_range === true) {
+        Logger.trace(`${account_id} 是项目特权人员。`);
+        return true;
+    }
+    Logger.trace(`${account_id} 不是项目特权人员。`);
     return false;
 }
 
@@ -19,21 +25,33 @@ export async function is_project_member(account_id: string, project_id: string):
         where: {member_id: account_id, prj_id: project_id, draft: false},
         raw: true
     });
-    if (result) return true;
+    if (result) {
+        Logger.trace(`${account_id} 是项目 ${project_id} 的项目组成员。`);
+        return true;
+    }
+    Logger.trace(`${account_id} 不是项目 ${project_id} 的项目组成员。`);
     return false;
 }
 
 /// 是否是项目负责人
 export async function is_project_leader(account_id: string, project_id: string): Promise<boolean> {
     let prj = await PrjInfo.findOne({where: {id: project_id}, raw: true});
-    if (prj && prj.leader_id === account_id) return true;
+    if (prj && prj.leader_id === account_id) {
+        Logger.trace(`${account_id} 是项目 ${project_id} 的项目负责人。`);
+        return true;
+    }
+    Logger.trace(`${account_id} 不是项目 ${project_id} 的项目负责人。`);
     return false;
 }
 
 /// 是否是项目商务负责人
 export async function is_project_business_leader(account_id: string, project_id: string): Promise<boolean> {
     let prj = await PrjInfo.findOne({where: {id: project_id}, raw: true});
-    if (prj && prj.bizman_id === account_id) return true;
+    if (prj && prj.bizman_id === account_id) {
+        Logger.trace(`${account_id} 是项目 ${project_id} 的商务负责人。`);
+        return true;
+    }
+    Logger.trace(`${account_id} 不是项目 ${project_id} 的商务负责人。`);
     return false;
 }
 
@@ -45,8 +63,11 @@ export async function is_project_checker(account_id: string, project_id: string)
         where checker_obj->>'id' = :user_id and prj_info.id = :prj_id
     `, {replacements: {user_id: account_id, prj_id: project_id}, type: QueryTypes.SELECT});
 
-    if (result && result.length > 0) return true;
-
+    if (result && result.length > 0) {
+        Logger.trace(`${account_id} 是项目 ${project_id} 的审核组成员。`);
+        return true;
+    }
+    Logger.trace(`${account_id} 不是项目 ${project_id} 的审核组成员。`);
     return false;
 }
 
@@ -60,8 +81,11 @@ export async function is_project_task_checker(account_id: string, project_id: st
           and prj_task.prj_id = :prj_id
     `, {replacements: {user_id: account_id, prj_id: project_id}, type: QueryTypes.SELECT});
 
-    if (result && result.length > 0) return true;
-
+    if (result && result.length > 0) {
+        Logger.trace(`${account_id} 是项目 ${project_id} 的任务审核组成员。`);
+        return true;
+    }
+    Logger.trace(`${account_id} 不是项目 ${project_id} 的任务审核组成员。`);
     return false;
 }
 
@@ -75,8 +99,12 @@ export async function is_project_accessible(account_id: string, project_id: stri
         await is_project_member(account_id, project_id) ||
         await is_project_checker(account_id, project_id) ||
         await is_project_task_checker(account_id, project_id)
-    )) return true;
+    )) {
+        Logger.trace(`${account_id} 有权访问项目 ${project_id}。`);
+        return true;
+    }
 
+    Logger.trace(`${account_id} 没有权限访问项目 ${project_id}。`);
     return false;
 }
 
@@ -85,8 +113,12 @@ export async function is_project_modifiable(account_id: string, project_id: stri
     if (
         await is_project_leader(account_id, project_id) ||
         await is_project_privileged_account(account_id)
-    ) return true;
+    ) {
+        Logger.trace(`${account_id} 是权修改项目 ${project_id} 的信息。`);
+        return true;
+    }
 
+    Logger.trace(`${account_id} 没有权限修改项目 ${project_id} 的信息。`);
     return false;
 }
 
@@ -96,22 +128,46 @@ export async function is_project_task_accessible(account_id: string, task_id: st
     if (task && (
         task.handler_id === account_id ||
         await is_project_accessible(account_id, task.prj_id)
-    )) return true;
+    )) {
+        Logger.trace(`${account_id} 有权访问项目 ${task.prj_id} 的任务 ${task_id}。`);
+        return true;
+    }
 
+    Logger.trace(`${account_id} 没有权限访问任务 ${task_id}。`);
     return false;
 }
 
-/// 是否有修改项目任务的权限
-export async function is_project_task_modifiable(account_id: string, task_id: string): Promise<boolean> {
-    let task = await PrjPlanTask.findOne({where: {id: task_id}, raw: true});
-    if (task &&  await is_project_modifiable(account_id, task.prj_id)) return true;
+/// 是否有权限添加任务
+export async function is_project_task_addable(account_id: string, project_id: string): Promise<boolean> {
+    if ( await is_project_modifiable(account_id, project_id)) {
+        Logger.trace(`${account_id} 有权添加项目 ${project_id} 的任务。`);
+        return true;
+    }
 
+    Logger.trace(`${account_id} 没有权限添加项目 ${project_id} 的任务。`);
+    return false;
+}
+
+/// 是否有修改项目任务的权限
+export async function is_project_task_modifiable(model: any, account_id: string, task_id: string): Promise<boolean> {
+    let task = await model.findOne({where: {id: task_id}, raw: true});
+    if (task &&  await is_project_modifiable(account_id, task.prj_id)) {
+        Logger.trace(`${account_id} 有权修改项目 ${task.prj_id} 的任务 ${task_id}。`);
+        return true;
+    }
+
+    Logger.trace(`${account_id} 没有权限修改任务 ${task_id}。`);
     return false;
 }
 
 /// 是否有修改项目任务进度的权限
 export async function is_project_task_progress_modifiable(account_id: string, task_id: string): Promise<boolean> {
     let task = await PrjPlanTask.findOne({where: {id: task_id}, raw: true});
-    if (task && (task.handler_id === account_id || await is_project_modifiable(account_id, task.prj_id))) return true;
+    if (task && (task.handler_id === account_id || await is_project_modifiable(account_id, task.prj_id))) {
+        Logger.trace(`${account_id} 有权修改项目 ${task.prj_id} 的任务 ${task_id}的进度。`);
+        return true;
+    }
+
+    Logger.trace(`${account_id} 没有权限修改任务 ${task_id}的进度。`);
     return false;
 }