package com.malk.service.teambition.impl; import cn.hutool.core.util.ObjectUtil; import com.auth0.jwt.algorithms.Algorithm; import com.malk.server.common.McException; import com.malk.server.dingtalk.DDConf; import com.malk.server.teambition.TBConf; import com.malk.server.teambition.TBR; import com.malk.service.teambition.TBClient; import com.malk.utils.UtilHttp; import com.malk.utils.UtilMap; import com.malk.utils.UtilToken; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j @Service public class TBClientImpl implements TBClient { @Autowired private TBConf tbConf; private static final Long EXPIRES_IN = 2 * 3600 * 1000L; private static final String TOKEN_APP_ID = "_appId"; // 获取访问授权 @Synchronized private String getAccessToken() { String accessToken = UtilToken.get("invalid-token-teambition"); if (StringUtils.isNotBlank(accessToken)) return accessToken; Algorithm algorithm = Algorithm.HMAC256(tbConf.getAppSecret()); long timestamp = System.currentTimeMillis(); Date issuedAt = new Date(timestamp); Date expiresAt = new Date(timestamp + EXPIRES_IN); accessToken = com.auth0.jwt.JWT.create() .withClaim(TOKEN_APP_ID, tbConf.getAppID()) .withIssuedAt(issuedAt) .withExpiresAt(expiresAt) .sign(algorithm); log.info("响应token, {}", accessToken); // token失效自动重置: TB传递过期时间2h, 重复调用就会刷新 UtilToken.put("invalid-token-teambition", accessToken, EXPIRES_IN); return accessToken; } // 初始化参数: 加载token private Map initHeaderToken() { Map header = new HashMap(); header.put("Authorization", getAccessToken()); header.put("X-Tenant-Id", tbConf.getTenantId()); header.put("X-Tenant-Type", TBConf.TENANT_TYPE); return header; } // 操作者ID: 若是查询, 以操作人视角作为权限 private Map initHeaderToken(String operatorId) { Map header = initHeaderToken(); header.put("x-operator-id", operatorId); return header; } // 加载token, 老版本接口 private Map initHeaderToken_Bearer() { Map header = initHeaderToken(); header.put("Authorization", "Bearer " + header.get("Authorization")); return header; } // // 操作者ID: 若是查询, 以操作人视角作为权限 // private Map initHeaderToken_Bearer(String operatorId) { // Map header = initHeaderToken_Bearer(); // header.put("x-operator-id", operatorId); // return header; // } @Override public List templateSearch(String ptIds, String q) { Map param = new HashMap(); param.put("ptIds", ptIds); param.put("q", q); param.put("organizationId", TBConf.TENANT_TYPE); TBR r = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project-template/search", initHeaderToken(), param, TBR.class); return (List) r.getResult(); } @Override public Map projectCreate(String name, String operatorId) { Map param = new HashMap(); param.put("organizationId", TBConf.TENANT_TYPE); Map body = new HashMap(); body.put("name", name); TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/project/create", initHeaderToken(operatorId), param, body, TBR.class); return (Map) tbr.getResult(); } @Override public Map projectCreateWithTemplate(String name, String templateId, String operatorId) { Map param = new HashMap(); param.put("organizationId", TBConf.TENANT_TYPE); Map body = new HashMap(); body.put("name", name); body.put("templateId", templateId); TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/project/create-from-template", initHeaderToken(operatorId), param, body, TBR.class); return (Map) tbr.getResult(); } @Override public List projectDetail(String projectIds, String name, String sourceId) { Map param = UtilMap.map("projectIds, name", projectIds, name); UtilMap.putNotEmpty(param, "sourceId", sourceId); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/query", initHeaderToken(), param, TBR.class); return (List) tbr.getResult(); } @Override public Map projectUpdate(String projectId, Map data, String operatorId) { TBR tbr = (TBR) UtilHttp.doPut(tbConf.getApiHost() + "/v3/project/" + projectId, initHeaderToken(operatorId), data, TBR.class); return (Map) tbr.getResult(); } @Override public Map updateProjectTag(String projectId, List projectTagIds, String operatorId) { Map body = UtilMap.map("projectTagIds", projectTagIds); Map result = null; try { TBR tbr = (TBR) UtilHttp.doPut(tbConf.getApiHost() + "/v3/project/" + projectId + "/project-tag", initHeaderToken(operatorId), body, TBR.class); result = (Map) tbr.getResult(); } catch (McException e) { // ppExt: 若修改分组相同, 不返回204, 会报错400, 已兼容 if (!"400".equals(e.getCode())) { // 记录错误信息 e.printStackTrace(); } } return result; } @Deprecated @Override public List userSearch(String query) { Map param = UtilMap.map("orgId, query, pageSize", tbConf.getTenantId(), query, TBConf.PAGE_SIZE_LIMIT); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/org/member/search", initHeaderToken_Bearer(), param, TBR.class); return (List) tbr.getResult(); } @Override public List idMapQuery(String tbId, String refer, String refId) { Map param = UtilMap.map("tbId, refer, refId", tbId, refer, refId); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/idmap/query", initHeaderToken_Bearer(), param, TBR.class); return (List) tbr.getResult(); } @Autowired private DDConf ddConf; @Override public List idMapQuery(String userId, boolean isTbID) { Map param = UtilMap.map(" refer, refId", "dingTalk-user", ddConf.getCorpId()); param.put(isTbID ? "tbId" : "extraUserId", userId); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/idmap/query", initHeaderToken_Bearer(), param, TBR.class); return (List) tbr.getResult(); } @Override public Map updateUser(String operatorId, List members) { Map body = new HashMap(); body.put("operatorId", operatorId); body.put("orgId", tbConf.getTenantId()); body.put("members", members); TBR tbr = (TBR) UtilHttp.doPut(tbConf.getApiHost() + "/org/member/update", initHeaderToken_Bearer(), body, TBR.class); return (Map) tbr.getResult(); } @Override public List createProjectMember(String projectId, List userIds, String operatorId) { Map body = UtilMap.map("userIds", userIds); TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/project/".concat(projectId).concat("/member/create-v2"), initHeaderToken(operatorId), body, TBR.class); return (List) tbr.getResult(); } @Override public List updateProjectMember(List userIds, List roleIds, String projectId) { Map body = UtilMap.map("userIds", userIds); body.put("roleIds", roleIds); // 合并字段避免map拆分异常, todo 待优化 map 方法 TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/project/".concat(projectId).concat("/member/role/assign"), initHeaderToken(), body, TBR.class); return (List) tbr.getResult(); } @Override public List queryProjectMember(String projectId, Map param) { param = UtilMap.put(param, "pageSize", TBConf.PAGE_SIZE_LIMIT); param.put("limit", TBConf.PAGE_SIZE_LIMIT); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/" + projectId + "/member", initHeaderToken(), param, TBR.class); return (List) tbr.getResult(); } @Override public List queryProjectRoles(String projectId) { Map param = UtilMap.map("pageSize", TBConf.PAGE_SIZE_LIMIT); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/" + projectId + "/role", initHeaderToken(), param, TBR.class); return (List) tbr.getResult(); } @Override public List queryTaskDetail(String taskId, String shortIds, String parentTaskId) { Map param = UtilMap.mapNotNull("taskId, shortIds, parentTaskId", taskId, shortIds, parentTaskId); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/task/query", initHeaderToken(), param, TBR.class); return (List) tbr.getResult(); } @Override public List queryTaskGroupList(String projectId, Map param) { TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/" + projectId + "/stage/search", initHeaderToken(), param, TBR.class); return (List) tbr.getResult(); } @Override public List queryProjectTaskList(String projectId, Map param, QueryAll lambda) { param = UtilMap.put(param, "pageSize", TBConf.PAGE_SIZE_LIMIT); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/" + projectId + "/task/query", initHeaderToken(), param, TBR.class); List dataList = (List) tbr.getResult(); if (ObjectUtil.isNotNull(lambda)) { boolean isAll = lambda.dataList(dataList); if (!isAll) { return dataList; } if (StringUtils.isNotBlank(tbr.getNextPageToken())) { param.put("pageToken", tbr.getNextPageToken()); queryProjectTaskList(projectId, param, lambda); } } return dataList; } @Override public Map updateTaskDueDate(String taskId, String dueDate, String operatorId) { Map body = UtilMap.map("dueDate", dueDate); TBR tbr = (TBR) UtilHttp.doPut(tbConf.getApiHost() + "/v3/task/" + taskId + "/dueDate", initHeaderToken(operatorId), body, TBR.class); return (Map) tbr.getResult(); } @Override public Map updateTaskExecutor(String taskId, String operatorId, String executorId, boolean disableActivity, boolean disableNotification) { Map body = UtilMap.map("executorId, disableActivity, disableNotification", executorId, disableActivity, disableNotification); TBR tbr = (TBR) UtilHttp.doPut(tbConf.getApiHost() + "/v3/task/" + taskId + "/executor", initHeaderToken(operatorId), body, TBR.class); return (Map) tbr.getResult(); } @Override public Map updateTaskCustomField(String taskId, String operatorId, Map body) { TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/task/" + taskId + "/customfield/update", initHeaderToken(operatorId), body, TBR.class); return (Map) tbr.getResult(); } @Override public Map updateTaskFlowStatus(String taskId, String operatorId, String taskflowstatusId, String tfsUpdateNote) { Map body = UtilMap.map("taskflowstatusId, tfsUpdateNote", taskflowstatusId, tfsUpdateNote); TBR tbr = (TBR) UtilHttp.doPut(tbConf.getApiHost() + "/v3/task/" + taskId + "/taskflowstatus", initHeaderToken(operatorId), body, TBR.class); return (Map) tbr.getResult(); } @Override public List queryProjectCustomField(String projectId, Map body) { body = UtilMap.put(body, "pageSize", TBConf.PAGE_SIZE_LIMIT); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/" + projectId + "/customfield/search", initHeaderToken(), body, TBR.class); return (List) tbr.getResult(); } @Override public List queryProjectCustomFlowStatus(String projectId, Map body) { body = UtilMap.put(body, "pageSize", TBConf.PAGE_SIZE_LIMIT); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/" + projectId + "/taskflowstatus/search", initHeaderToken(), body, TBR.class); return (List) tbr.getResult(); } @Override public List queryProjectCustomFlow(String projectId, Map body) { body = UtilMap.put(body, "pageSize", TBConf.PAGE_SIZE_LIMIT); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/" + projectId + "/taskflow/search", initHeaderToken(), body, TBR.class); return (List) tbr.getResult(); } @Override public List queryTaskDependency(String taskId, Map body) { body = UtilMap.put(body, "pageSize", TBConf.PAGE_SIZE_LIMIT); body.put("taskId", taskId); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "v3/task/dependency", initHeaderToken(), body, TBR.class); return (List) tbr.getResult(); } @Override public Map removeTaskDependency(String dependencyId, String operatorId) { TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/task/dependency/" + dependencyId + "/delete", initHeaderToken(operatorId), null, TBR.class); return (Map) tbr.getResult(); } @Override public List queryGanttBaselineList(String projectId, Map body) { body = UtilMap.put(body, "pageSize", TBConf.PAGE_SIZE_LIMIT); body.put("projectId", projectId); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/gantt/baseline", initHeaderToken(), body, TBR.class); return (List) tbr.getResult(); } @Override public List queryGanttBaselineTask(String baselineId, Map param, QueryAll lambda) { param = UtilMap.put(param, "pageSize", 10); param.put("baselineId", baselineId); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/gantt/baseline-task", initHeaderToken(), param, TBR.class); List dataList = (List) tbr.getResult(); if (ObjectUtil.isNotNull(lambda)) { boolean isAll = lambda.dataList(dataList); if (!isAll) { return dataList; } if (StringUtils.isNotBlank(tbr.getNextPageToken())) { param.put("pageToken", tbr.getNextPageToken()); queryGanttBaselineTask(baselineId, param, lambda); } } return dataList; } @Override public List queryTagList(Map param) { param = UtilMap.put(param, "pageSize", TBConf.PAGE_SIZE_LIMIT); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project-tag/query", initHeaderToken(), param, TBR.class); return (List) tbr.getResult(); } @Override public Map updateTag(String projectTagId, Map param) { TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project-tag/" + projectTagId, initHeaderToken(), param, TBR.class); return (Map) tbr.getResult(); } @Override public List queryProgramList(String programIds) { Map param = UtilMap.map("programIds", programIds); TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/program/query", initHeaderToken(), param, TBR.class); return (List) tbr.getResult(); } @Override public List queryProgramList_all() { TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/program/query", initHeaderToken(), null, null, TBR.class); return (List) tbr.getResult(); } @Override public List upsertProgramProject(String programId, List projectIds, String operatorId) { TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "v3/program/" + programId + "/project/create", initHeaderToken(operatorId), UtilMap.map("projectIds", projectIds), TBR.class); return (List) tbr.getResult(); } @Override public List queryProjectStatusField(String projectId) { TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "v3/project/" + projectId + "/status/customfield/list", initHeaderToken(), null, TBR.class); return (List) tbr.getResult(); } @Override public Map updateProjectStatusField(String projectId, String operatorId, Map body) { TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/project/" + projectId + "/status/customfield/create", initHeaderToken(operatorId), body, TBR.class); return (Map) tbr.getResult(); } }