diff --git a/orgmanax-dto/src/main/java/cn/axzo/orgmanax/dto/nodeuser/req/BatchDeleteNodeUserCheckReq.java b/orgmanax-dto/src/main/java/cn/axzo/orgmanax/dto/nodeuser/req/BatchDeleteNodeUserCheckReq.java
index ccb36b2..18b64b9 100644
--- a/orgmanax-dto/src/main/java/cn/axzo/orgmanax/dto/nodeuser/req/BatchDeleteNodeUserCheckReq.java
+++ b/orgmanax-dto/src/main/java/cn/axzo/orgmanax/dto/nodeuser/req/BatchDeleteNodeUserCheckReq.java
@@ -3,7 +3,6 @@ package cn.axzo.orgmanax.dto.nodeuser.req;
import lombok.Data;
import javax.validation.constraints.NotNull;
-import java.util.List;
import java.util.Set;
/**
@@ -33,4 +32,15 @@ public class BatchDeleteNodeUserCheckReq {
* 操作者ID
*/
private Long operatorId;
-}
+
+ /**
+ * 登录单位
+ */
+ private Long loginOuId;
+
+ /**
+ * 单位类型
+ */
+ private Integer ouType;
+
+}
\ No newline at end of file
diff --git a/orgmanax-server/pom.xml b/orgmanax-server/pom.xml
index bfdf316..2f840f4 100644
--- a/orgmanax-server/pom.xml
+++ b/orgmanax-server/pom.xml
@@ -50,6 +50,10 @@
org.springframework.cloud
spring-cloud-starter-bootstrap
+
+ cn.axzo.pokonyan
+ pokonyan
+
diff --git a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/mq/producer/OrgUserChangedEventProducer.java b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/mq/producer/OrgUserChangedEventProducer.java
index 0f99987..166e24e 100644
--- a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/mq/producer/OrgUserChangedEventProducer.java
+++ b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/mq/producer/OrgUserChangedEventProducer.java
@@ -58,6 +58,7 @@ public class OrgUserChangedEventProducer {
MQEventEnum mqEvent = MQEventEnum.ORG_USER_MOVEMENT;
return Event.builder()
.shardingKey(String.valueOf(event.getPersonId()))
+ .targetId(String.valueOf(event.getPersonId()))
.targetType(mqEvent.getModel())
.eventCode(mqEvent.getEventCode())
.data(event)
diff --git a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/dto/CheckUserOperateParam.java b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/dto/CheckUserOperateParam.java
index e0ab5b4..deee942 100644
--- a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/dto/CheckUserOperateParam.java
+++ b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/dto/CheckUserOperateParam.java
@@ -7,6 +7,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
+import java.util.List;
import java.util.Set;
/**
@@ -22,6 +23,7 @@ public class CheckUserOperateParam {
private Set personIds;
private Long workspaceId;
private boolean isWorkspace;
+ private List topNodeIds;
public void check() {
if (ObjectUtils.anyNull(personIds, workspaceId, operatorId)) {
diff --git a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/foundation/impl/NodeUserFoundationServiceImpl.java b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/foundation/impl/NodeUserFoundationServiceImpl.java
index ede35b9..228b217 100644
--- a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/foundation/impl/NodeUserFoundationServiceImpl.java
+++ b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/foundation/impl/NodeUserFoundationServiceImpl.java
@@ -29,6 +29,7 @@ import cn.axzo.orgmanax.infra.dao.orgjob.entity.OrgJob;
import cn.axzo.orgmanax.infra.dao.orgjob.repository.OrgJobQueryRepository;
import cn.axzo.orgmanax.infra.dao.unit.repository.UnitQueryRepository;
import cn.axzo.orgmanax.server.mq.OrganizationalNodeUserUpsertedPayload;
+import cn.axzo.orgmanax.server.mq.enums.MQEventEnum;
import cn.axzo.orgmanax.server.node.event.inner.NodeEventType;
import cn.axzo.orgmanax.server.nodeuser.event.inner.payload.NodeUserUpsertedPayload;
import cn.axzo.orgmanax.server.nodeuser.foundation.NodeUserFoundationService;
@@ -49,11 +50,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
import java.util.stream.Collectors;
/**
@@ -218,7 +215,7 @@ public class NodeUserFoundationServiceImpl implements NodeUserFoundationService
OrgProjectWorkerWithdrawReq workerReq = new OrgProjectWorkerWithdrawReq();
workerReq.setWorkspaceId(req.getWorkspaceId());
if (req.isUnitDelete()) {
- quitReq.setOuId(req.getOuId());
+ workerReq.setOuId(req.getOuId());
workerReq.setWorkspaceId(nodeUserList.get(0).getWorkspaceId());
}
workerReq.setPersonIds(req.getPersonIds());
@@ -239,6 +236,15 @@ public class NodeUserFoundationServiceImpl implements NodeUserFoundationService
.build();
eventProducer.send(OrganizationalNodeUserUpsertedPayload.from(null, e, "-1",
new JSONObject().fluentPut("operateLogSaveParam", saveParam)));
+ MQEventEnum mqEvent = MQEventEnum.NODE_USER_DELETE;
+ Event nodeUserDelete = Event.builder()
+ .shardingKey(String.valueOf(e.getPersonId()))
+ .targetId(String.valueOf(e.getPersonId()))
+ .targetType(mqEvent.getModel())
+ .eventCode(mqEvent.getEventCode())
+ .data(e)
+ .build();
+ eventProducer.send(nodeUserDelete);
}
private void checkDeleteReq(NodeUserDelete req) {
@@ -265,9 +271,6 @@ public class NodeUserFoundationServiceImpl implements NodeUserFoundationService
/**
* 根据条件聚合查询节点用户
- *
- * @param req
- * @return
*/
@Override
public List searchEntUser(SearchEntNodeUserReq req) {
diff --git a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/service/impl/NodeUserCheckServiceImpl.java b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/service/impl/NodeUserCheckServiceImpl.java
index c09e086..d511b84 100644
--- a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/service/impl/NodeUserCheckServiceImpl.java
+++ b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/nodeuser/service/impl/NodeUserCheckServiceImpl.java
@@ -21,7 +21,6 @@ import cn.axzo.orgmanax.infra.client.tyr.RoleUserGateway;
import cn.axzo.orgmanax.infra.client.workspace.WorkspaceGateway;
import cn.axzo.orgmanax.infra.client.workspace.dto.Workspace;
import cn.axzo.orgmanax.server.cooperateship.service.CooperateShipService;
-import cn.axzo.orgmanax.server.node.service.NodeService;
import cn.axzo.orgmanax.server.nodeuser.dto.CheckUserOperateParam;
import cn.axzo.orgmanax.server.nodeuser.service.NodeUserCheckService;
import cn.axzo.orgmanax.server.nodeuser.service.NodeUserService;
@@ -60,8 +59,6 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
private final NodeUserService nodeUserService;
- private final NodeService nodeService;
-
private final KarmaThirdApiClient karmaThirdApiClient;
// 单位类型默认角色关系,后面可以座位管理员的逻辑进行迭代
@@ -78,10 +75,6 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
@Value("${entTeamLeader:entTeamLeader}")
private String entTeamLeader;
- // 企业内班组工人岗位编码
- @Value("${entWorker:entWorker}")
- private String entWorker;
-
@Override
public List checkUnit(BatchDeleteNodeUserCheckReq req) {
List resultList = new ArrayList<>();
@@ -114,7 +107,6 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
ListOrgCooperateShipReq listOrgCooperateShipReq = new ListOrgCooperateShipReq();
listOrgCooperateShipReq.setOuIds(Collections.singleton(ouId));
- listOrgCooperateShipReq.setStatuses(CollUtil.newHashSet(0, 1));
listOrgCooperateShipReq.setWorkspaceTypes(CollUtil.newHashSet(2));
List listPersonJoinedWorkspace = cooperateShipService.list(listOrgCooperateShipReq);
Set inProjectPersonIds = filterByPerson(listPersonJoinedWorkspace, personIds);
@@ -154,6 +146,7 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
.operatorId(req.getOperatorId())
.personIds(req.getPersonIds())
.workspaceId(req.getWorkspaceId())
+ .topNodeIds(Collections.singletonList(topNodeId))
.build(), failInfoMap);
transformFailMap(failInfoMap, resultList);
return resultList;
@@ -189,46 +182,71 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
List resultList = new ArrayList<>();
Map> failInfoMap = new HashMap<>();
ListOrgCooperateShipReq listOrgCooperateShipReq = new ListOrgCooperateShipReq();
- if (NumberUtil.isPositiveNumber(req.getNodeId())) {
- listOrgCooperateShipReq.setOuIds(Collections.singleton(req.getOuId()));
- }
+ listOrgCooperateShipReq.setOuIds(Collections.singleton(req.getOuId()));
listOrgCooperateShipReq.setWorkspaceIds(Collections.singleton(req.getWorkspaceId()));
- listOrgCooperateShipReq.setStatuses(CollUtil.newHashSet(0, 1));
List cooperateShipRespList = cooperateShipService.list(listOrgCooperateShipReq);
Axssert.checkNotEmpty(cooperateShipRespList, "操作失败,获取协同组织失败");
+
// 协同节点关联的顶级部门节点列表
List nodeIds = cooperateShipRespList.stream().map(OrgCooperateShipDTO::getOrganizationalNodeId).distinct().collect(Collectors.toList());
List nodePersonIds = Lists.newArrayList(req.getPersonIds());
- nodePersonIds.add(personId);
ListNodeUserReq query = ListNodeUserReq.builder()
.topNodeIds(nodeIds)
.personIds(nodePersonIds)
+ .findByTopNodeId(true)
.needs(ListNodeUserReq.Needs.builder().job(true).build())
.findByAncestorNodeId(true)
.build();
- // 查询当前登录及待删除人员在当前项目中的参与记录(仅限当前登录单位)
+ // 查询待删除人员在当前项目中的参与记录(仅限当前登录单位)
List nodeUsers = nodeUserService.list(query);
- // 校验当前入参
- checkPermission(nodeUsers);
- // 过滤当前操作人员
- nodeUsers = nodeUsers.stream()
- .filter(e -> !Objects.equals(e.getPersonId(), personId))
- .collect(Collectors.toList());
+
+ // 校验当前操作人
+ checkPermission(nodeUsers, personId, req.getPersonIds());
+
if (CollUtil.isEmpty(nodeUsers)) {
req.getPersonIds().forEach(e -> {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
addFailInfo(failInfoMap, e, checkFailInfo);
});
- }
- if (CollUtil.isEmpty(nodeUsers)) {
transformFailMap(failInfoMap, resultList);
return resultList;
}
- nodeUsers.stream().filter(e -> e.getIdentityType().equals(IdentityType.WORKER_LEADER.getCode())).findAny().ifPresent(e -> {
+
+ Set inJurisdictionPersonIds = nodeUsers.stream().map(NodeUserDTO::getPersonId).collect(Collectors.toSet());
+ for (Long reqPersonIds : req.getPersonIds()) {
+ if (!inJurisdictionPersonIds.contains(reqPersonIds)) {
+ BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
+ checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
+ addFailInfo(failInfoMap, reqPersonIds, checkFailInfo);
+ }
+ }
+
+ // 检查节点权限
+ boolean noTInJurisdiction = checkUserOperate(CheckUserOperateParam.builder()
+ .operatorId(req.getOperatorId())
+ .personIds(req.getPersonIds())
+ .workspaceId(req.getWorkspaceId())
+ .isWorkspace(true)
+ .topNodeIds(nodeIds)
+ .build(), failInfoMap);
+
+ if (!noTInJurisdiction) {
+ req.getPersonIds().forEach(e -> {
+ BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
+ checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
+ addFailInfo(failInfoMap, e, checkFailInfo);
+ });
+ transformFailMap(failInfoMap, resultList);
+ return resultList;
+ }
+
+ Set teamLeadPersonSet = new HashSet<>();
+ nodeUsers.stream().filter(e -> e.getIdentityType().equals(IdentityType.WORKER_LEADER.getCode())).forEach(e -> {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.TEAM_LEADER);
addFailInfo(failInfoMap, e.getPersonId(), checkFailInfo);
+ teamLeadPersonSet.add(e.getPersonId());
});
// 判断小组长,小组长不允许删除
@@ -241,10 +259,15 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
roleUserParam.setWorkspaceOuPairs(workspaceOuPairList);
roleUserParam.setPersonIds(req.getPersonIds());
roleUserParam.setNeedRole(true);
+ roleUserParam.setPageSize(1000);
List saasRoleUserInfo = roleUserGateway.pageAll(roleUserParam);
saasRoleUserInfo = saasRoleUserInfo.stream().filter(e -> Objects.nonNull(e.getRole())).collect(Collectors.toList());
saasRoleUserInfo.forEach(e -> {
+ // 班组长不用校验,因为班组长也会有管理员角色
+ if (teamLeadPersonSet.contains(e.getPersonId())) {
+ return;
+ }
Optional roleTypeEnumOptional = RoleTypeEnum.fromValue(e.getRole().getRoleType());
RoleTypeEnum roleTypeEnum = RoleTypeEnum.AUTO_OWN;
if (roleTypeEnumOptional.isPresent()) {
@@ -257,13 +280,7 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
addFailInfo(failInfoMap, e.getPersonId(), checkFailInfo);
}
});
- // 检查节点权限
- checkUserOperate(CheckUserOperateParam.builder()
- .operatorId(req.getOperatorId())
- .personIds(req.getPersonIds())
- .workspaceId(req.getWorkspaceId())
- .isWorkspace(true)
- .build(), failInfoMap);
+
// 三方阻断校验
thirdApiCheckPerson(req.getWorkspaceId(), req.getPersonIds(), failInfoMap);
transformFailMap(failInfoMap, resultList);
@@ -271,10 +288,11 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
}
private List transformWorkspaceOuPair(List nodeUsers) {
- return nodeUsers.stream().map(e -> {
+ Map worspaceOuPairMap = nodeUsers.stream().collect(Collectors.toMap(NodeUserDTO::getWorkspaceId, NodeUserDTO::getOrganizationalUnitId, (e1, e2) -> e1));
+ return worspaceOuPairMap.entrySet().stream().map(e -> {
PageRoleUserReq.WorkspaceOuPair ouPair = new PageRoleUserReq.WorkspaceOuPair();
- ouPair.setWorkspaceId(e.getWorkspaceId());
- ouPair.setOuId(e.getOrganizationalUnitId());
+ ouPair.setWorkspaceId(e.getKey());
+ ouPair.setOuId(e.getValue());
return ouPair;
}).collect(Collectors.toList());
}
@@ -319,6 +337,9 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
return;
}
for (NodeUserDTO u : nodeUsers) {
+ if (Objects.isNull(u.getJob())) {
+ continue;
+ }
if (projectTeamGPLeader.equals(u.getJob().getCode())) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.PROJECT_GROUP_LEADER);
@@ -327,9 +348,11 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
}
}
- private void checkPermission(List nodeUsers) {
+ private void checkPermission(List nodeUsers, Long personId, Set nodePersonIds) {
if (CollUtil.isEmpty(nodeUsers)) {
- throw ResultCode.INVALID_PARAMS.toException("你已被移除当前项目,请刷新后重试当前操作!");
+ if (nodePersonIds.size() == 1 && nodePersonIds.contains(personId)) {
+ throw ResultCode.INVALID_PARAMS.toException("你已被移除当前项目,请刷新后重试当前操作!");
+ }
}
}
@@ -341,9 +364,9 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
}
}
- public void checkUserOperate(CheckUserOperateParam param, Map> failInfoMap) {
+ public boolean checkUserOperate(CheckUserOperateParam param, Map> failInfoMap) {
if (NumberUtil.isNotPositiveNumber(param.getOperatorId())) {
- return;
+ return false;
}
param.check();
List nodePersonIds = Lists.newArrayList(param.getPersonIds());
@@ -352,9 +375,12 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
.personIds(nodePersonIds)
.workspaceId(param.getWorkspaceId())
.needs(ListNodeUserReq.Needs.builder().job(true).node(true).build())
+ .topNodeIds(param.getTopNodeIds())
+ .findByTopNodeId(true)
.build();
List nodeUsers = nodeUserService.list(nodeUserReq);
NodeUserDTO operator = nodeUsers.stream().filter(nu -> Objects.equals(nu.getPersonId(), param.getOperatorId()))
+ .filter(nu -> Objects.nonNull(nu.getJob()))
.filter(nu -> StrUtil.isNotBlank(nu.getJob().getCode()))
.min(Comparator.comparingInt(NODE_USER_PRIORITY_RESOLVER)).orElse(null);
List targets = param.getPersonIds().stream()
@@ -367,6 +393,14 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
log.info("## checkUserOperate, param = {}, operator = {}, targets = {}, nodeUsers = {} "
, JSON.toJSONString(param), JSON.toJSONString(operator), JSON.toJSONString(targets), JSON.toJSONString(nodeUsers));
if (operator == null) {
+ if (CollUtil.isNotEmpty(targets)) {
+ targets.forEach(target -> {
+ BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
+ checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
+ addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
+ });
+ return false;
+ }
throw ResultCode.INVALID_PARAMS.toException("你已经被移出该企业/项目,请及时联系管理员;你可以退出登录或切换到其他企业/项目使用");
}
if (CollUtil.isEmpty(targets)) {
@@ -378,11 +412,11 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
throw ResultCode.INVALID_PARAMS.toException("操作失败,您暂无权限!");
}
if (param.getPersonIds().size() == 1 && param.getPersonIds().contains(param.getOperatorId())) {
- return;
+ return true;
}
// 如果 操作人是 从业人员 直接返回
if (isPractitioner(operator)) {
- return;
+ return true;
}
// 操作人是 班组长或者带班长, 则被操作人,只能是 自己,或者自己班组 及 小组的工人
if (isProjectTeamLeader(operator) || isProjectTeamManager(operator)) {
@@ -391,15 +425,10 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
if (isProjectGroupManager(operator)) {
targets.forEach(target -> groupManagerCheck(target, operator, nodeUsers, failInfoMap));
}
+ return true;
}
private void groupManagerCheck(NodeUserDTO target, NodeUserDTO operator, List nodeUsers, Map> failInfoMap) {
- if (isPractitioner(target)) {
- BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
- checkFailInfo.setType(CheckInfoTypeEnum.ANY_ADMIN);
- addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
- return;
- }
// 工人必须仅在自己小组
boolean isSameGroup = nodeUsers.stream()
.filter(nu -> Objects.equals(nu.getPersonId(), target.getPersonId()))
@@ -408,10 +437,19 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
+ return;
+ }
+ if (isPractitioner(target)) {
+ BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
+ checkFailInfo.setType(CheckInfoTypeEnum.ANY_ADMIN);
+ addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
}
}
private void teamManagerCheck(NodeUserDTO target, NodeUserDTO operator, Map> failInfoMap) {
+ // 否则,自己下级小组,也可以。
+ boolean isGroup = target.getNode() != null
+ && Objects.equals(target.getNode().getNodeType(), NodeTypeEnum.PROJECT_GROUP.getCode());
if (isPractitioner(target)) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.ANY_ADMIN);
@@ -422,15 +460,13 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
if (isSameTeam) {
return;
}
- // 否则,自己下级小组,也可以。
- boolean isGroup = target.getNode() != null
- && Objects.equals(target.getNode().getNodeType(), NodeTypeEnum.PROJECT_GROUP.getCode());
if (!isGroup) {
BatchDeleteNodeUserCheckResp.CheckFailInfo checkFailInfo = new BatchDeleteNodeUserCheckResp.CheckFailInfo();
checkFailInfo.setType(CheckInfoTypeEnum.NOT_IN_JURISDICTION);
addFailInfo(failInfoMap, target.getPersonId(), checkFailInfo);
return;
}
+
Long belongProjectTeamNodeId = resolveProjectTeamNodeId(target.getOrganizationalNodeId());
if (Objects.equals(belongProjectTeamNodeId, operator.getOrganizationalNodeId())) {
return;
@@ -441,35 +477,35 @@ public class NodeUserCheckServiceImpl implements NodeUserCheckService {
}
private boolean isPractitioner(NodeUserDTO nodeUser) {
- if (nodeUser == null) {
+ if (nodeUser == null || Objects.isNull(nodeUser.getJob())) {
return false;
}
return Objects.equals(nodeUser.getIdentityType(), IdentityType.PRACTITIONER.getCode());
}
private boolean isProjectWorker(NodeUserDTO nodeUser) {
- if (nodeUser == null) {
+ if (nodeUser == null || Objects.isNull(nodeUser.getJob())) {
return false;
}
return Objects.equals(nodeUser.getJob().getCode(), JobCodeConstants.PROJECT_TEAM_WORKER);
}
private boolean isProjectTeamLeader(NodeUserDTO nodeUser) {
- if (nodeUser == null) {
+ if (nodeUser == null || Objects.isNull(nodeUser.getJob())) {
return false;
}
return Objects.equals(nodeUser.getJob().getCode(), JobCodeConstants.PROJ_TEAM_LEADER);
}
private boolean isProjectTeamManager(NodeUserDTO nodeUser) {
- if (nodeUser == null) {
+ if (nodeUser == null || Objects.isNull(nodeUser.getJob())) {
return false;
}
return Objects.equals(nodeUser.getJob().getCode(), JobCodeConstants.PROJ_TEAM_MANAGER);
}
private boolean isProjectGroupManager(NodeUserDTO nodeUser) {
- if (nodeUser == null) {
+ if (nodeUser == null || Objects.isNull(nodeUser.getJob())) {
return false;
}
return Objects.equals(nodeUser.getJob().getCode(), JobCodeConstants.PROJECT_TEAM_GROUP_LEADER);
diff --git a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/orguser/foundation/impl/OrgUserFoundationServiceImpl.java b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/orguser/foundation/impl/OrgUserFoundationServiceImpl.java
index 921f729..7d0d49a 100644
--- a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/orguser/foundation/impl/OrgUserFoundationServiceImpl.java
+++ b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/orguser/foundation/impl/OrgUserFoundationServiceImpl.java
@@ -15,6 +15,7 @@ import cn.axzo.orgmanax.infra.dao.orguser.repository.OrgUserUpsertRepository;
import cn.axzo.orgmanax.server.mq.producer.OrgUserChangedEventProducer;
import cn.axzo.orgmanax.server.orguser.foundation.OrgUserFoundationService;
import cn.axzo.orgmanax.server.orguser.foundation.req.OrgUserWithdrawOrQuitReq;
+import cn.axzo.orgmanax.server.util.RedisLockUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import lombok.RequiredArgsConstructor;
@@ -35,6 +36,13 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class OrgUserFoundationServiceImpl implements OrgUserFoundationService {
+ private static final String LOG_PREFIX = "[ORG_USER_OP] ";
+
+ private static final long OP_LOCK_TIMEOUT = 1000 * 5;
+ private static final String OP_LOCK_PREFIX = "ORG_USER";
+ private static final String OP_SINGLETON_UPSERT = "SINGLETON_UPSERT";
+ private static final String OP_BATCH_UPSERT = "BATCH_UPSERT";
+
private final WorkspaceGateway workspaceGateway;
private final OrgUserQueryRepository orgUserQueryRepository;
private final OrgUserUpsertRepository orgUserUpsertRepository;
@@ -42,10 +50,16 @@ public class OrgUserFoundationServiceImpl implements OrgUserFoundationService {
@Override
public void batchWithdrawOrQuit(OrgUserWithdrawOrQuitReq req) {
- OrgUserStatusEnum status;
if (NumberUtil.isNotPositiveNumber(req.getWorkspaceId())) {
return;
}
+ // 优先获取批量写操作的锁,成功获取后再执行单个的写操作
+ String redisKey = generateBatchOperationKey(req.getOuId(), req.getWorkspaceId());
+ RedisLockUtil.tryLock(redisKey, OP_LOCK_TIMEOUT, () -> dealUpdate(req));
+ }
+
+ private void dealUpdate(OrgUserWithdrawOrQuitReq req) {
+ OrgUserStatusEnum status;
if (req.isUnitUpdate()) {
WorkspaceDetailReq workspaceDetailReq = new WorkspaceDetailReq();
workspaceDetailReq.setId(req.getWorkspaceId());
@@ -123,4 +137,8 @@ public class OrgUserFoundationServiceImpl implements OrgUserFoundationService {
return dto;
}
+ private static String generateBatchOperationKey(Long ouId, Long workspaceId) {
+ return RedisLockUtil.formatKey(OP_LOCK_PREFIX, OP_BATCH_UPSERT, ouId, workspaceId);
+ }
+
}
\ No newline at end of file
diff --git a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/project/worker/foundation/impl/OrgProjectWorkerFoundationServiceImpl.java b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/project/worker/foundation/impl/OrgProjectWorkerFoundationServiceImpl.java
index 60e7b0a..85c6807 100644
--- a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/project/worker/foundation/impl/OrgProjectWorkerFoundationServiceImpl.java
+++ b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/project/worker/foundation/impl/OrgProjectWorkerFoundationServiceImpl.java
@@ -43,9 +43,9 @@ public class OrgProjectWorkerFoundationServiceImpl implements OrgProjectWorkerFo
Date now = new Date();
List orgProjectWorkers = projectWorkerResps.stream().map(e -> {
OrgProjectWorker orgProjectWorker = BeanUtil.toBean(e, OrgProjectWorker.class);
- e.setStatus(ProjectWorkerStatusEnum.WITHDRAW.getValue());
- e.setResignAt(now);
- e.setUpdateAt(now);
+ orgProjectWorker.setStatus(ProjectWorkerStatusEnum.WITHDRAW.getValue());
+ orgProjectWorker.setResignAt(now);
+ orgProjectWorker.setUpdateAt(now);
return orgProjectWorker;
}).collect(Collectors.toList());
orgProjectWorkerUpsertRepository.batchUpdate(orgProjectWorkers);
diff --git a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/util/RedisLockUtil.java b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/util/RedisLockUtil.java
new file mode 100644
index 0000000..b0df1f4
--- /dev/null
+++ b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/util/RedisLockUtil.java
@@ -0,0 +1,87 @@
+package cn.axzo.orgmanax.server.util;
+
+import cn.axzo.basics.common.util.AssertUtil;
+import cn.axzo.maokai.common.enums.ErrorCodeEnum;
+import cn.axzo.pokonyan.config.redis.RedisClient;
+import cn.hutool.core.lang.UUID;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/**
+ * @author luofu
+ * @version 1.0
+ * @date 2024/6/3
+ */
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class RedisLockUtil {
+
+ /**
+ * redis key format
+ *
+ * @param prefix 前缀
+ * @param params 参数
+ * @return 格式化后的字符串
+ */
+ public static String formatKey(String prefix, Object... params) {
+ AssertUtil.notEmpty(prefix, "prefix can not be empty");
+ if (Objects.isNull(params) || 0 == params.length) {
+ return prefix;
+ }
+ String strParams = Arrays.stream(params).map(Object::toString)
+ .collect(Collectors.joining(REDIS_LOCK_SPLITER));
+ return APP_NAME + ":" + prefix + REDIS_LOCK_SPLITER + strParams;
+ }
+
+ /**
+ * do some thing while successfully fetch lock
+ *
+ * @param key 锁
+ * @param tryTimeoutMills 超时时间,单位毫秒
+ * @param executor 执行器
+ */
+ public static void tryLock(String key, long tryTimeoutMills, Runnable executor) {
+ AssertUtil.notEmpty(key, "key can not be empty");
+ AssertUtil.notNull(executor, "executor can not be null");
+ String requestId = UUID.randomUUID().toString();
+ try {
+ long keyTimeoutMills = tryTimeoutMills * 2;
+ Boolean lockResult = RedisClient.LockOps.getLockUntilTimeout(key, requestId, keyTimeoutMills, TimeUnit.MILLISECONDS, tryTimeoutMills);
+ AssertUtil.isTrue(Boolean.TRUE.equals(lockResult), ErrorCodeEnum.SYSTEM_BUSY.getMessage());
+ executor.run();
+ } finally {
+ RedisClient.LockOps.releaseLock(key, requestId);
+ }
+ }
+
+ /**
+ * do some thing while successfully fetch lock
+ *
+ * @param key 锁
+ * @param tryTimeoutMills 超时时间,单位毫秒
+ * @param executor 执行器
+ */
+ public static T tryLock(String key, long tryTimeoutMills, Supplier executor) {
+ AssertUtil.notEmpty(key, "key can not be empty");
+ AssertUtil.notNull(executor, "executor can not be null");
+ String requestId = UUID.randomUUID().toString();
+ try {
+ long keyTimeoutMills = tryTimeoutMills * 2;
+ Boolean lockResult = RedisClient.LockOps.getLockUntilTimeout(key, requestId, keyTimeoutMills, TimeUnit.MILLISECONDS, tryTimeoutMills);
+ AssertUtil.isTrue(Boolean.TRUE.equals(lockResult), ErrorCodeEnum.SYSTEM_BUSY.getMessage());
+ return executor.get();
+ } finally {
+ RedisClient.LockOps.releaseLock(key, requestId);
+ }
+ }
+
+ private static final String REDIS_LOCK_SPLITER = ":";
+ private static final String APP_NAME = "[maokai]";
+}