You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2022/06/15 08:30:26 UTC
[incubator-shenyu] branch master updated: [ISSUE #3221] record role management logging (#3560)
This is an automated email from the ASF dual-hosted git repository.
xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new ac0a1342f [ISSUE #3221] record role management logging (#3560)
ac0a1342f is described below
commit ac0a1342fd4625de8f986a9d3d2f03242bfcee8e
Author: likeguo <33...@users.noreply.github.com>
AuthorDate: Wed Jun 15 16:30:21 2022 +0800
[ISSUE #3221] record role management logging (#3560)
* fixbug/pg script error
* feature/record log in role
* feature/record log in role
* feature/record log in role
* feature/record log in role
* feature/record log in role
* feature/record log in role
---
.../org/apache/shenyu/admin/mapper/RoleMapper.java | 8 +
.../shenyu/admin/model/enums/EventTypeEnum.java | 18 +-
.../model/event/role/BatchRoleDeletedEvent.java | 80 +++++++++
.../admin/model/event/role/RoleChangedEvent.java | 76 +++++++++
.../admin/model/event/role/RoleCreatedEvent.java | 48 ++++++
.../admin/model/event/role/RoleUpdatedEvent.java | 62 +++++++
.../apache/shenyu/admin/service/RoleService.java | 33 +++-
.../admin/service/impl/PermissionServiceImpl.java | 95 +++++++++++
.../shenyu/admin/service/impl/RoleServiceImpl.java | 183 ++++++++-------------
.../admin/service/publish/RoleEventPublisher.java | 88 ++++++++++
.../src/main/resources/mappers/role-sqlmap.xml | 9 +
.../shenyu/admin/service/RoleServiceTest.java | 36 ++--
12 files changed, 594 insertions(+), 142 deletions(-)
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/RoleMapper.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/RoleMapper.java
index 8d4b14829..2a2da629d 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/RoleMapper.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/RoleMapper.java
@@ -119,4 +119,12 @@ public interface RoleMapper extends ExistProvider {
* @return {@linkplain List}
*/
List<RoleDO> selectAll();
+
+ /**
+ * select by ids.
+ *
+ * @param ids ids.
+ * @return list
+ */
+ List<RoleDO> selectByIds(@Param("ids") List<String> ids);
}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/enums/EventTypeEnum.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/enums/EventTypeEnum.java
index ce756ecad..e1026e2d4 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/enums/EventTypeEnum.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/enums/EventTypeEnum.java
@@ -70,6 +70,12 @@ public enum EventTypeEnum {
*/
DICT_CREATE("CREATE:DICT", DataEventTypeEnum.CREATE, Color.CREATE_COLOR),
+
+ /**
+ * role created event.
+ */
+ ROLE_CREATE("CREATE:ROLE", DataEventTypeEnum.CREATE, Color.CREATE_COLOR),
+
// ============== delete ===================
/**
* deleted event.
@@ -117,6 +123,11 @@ public enum EventTypeEnum {
*/
DICT_DELETE("DELETE:DICT", DataEventTypeEnum.DELETE, Color.DELETE_COLOR),
+ /**
+ * role deleted event.
+ */
+ ROLE_DELETE("DELETE:ROLE", DataEventTypeEnum.DELETE, Color.DELETE_COLOR),
+
// ============== update ===================
/**
@@ -157,7 +168,12 @@ public enum EventTypeEnum {
/**
* dict update.
*/
- DICT_UPDATE("UPDATE:DICT", DataEventTypeEnum.UPDATE, Color.UPDATE_COLOR);
+ DICT_UPDATE("UPDATE:DICT", DataEventTypeEnum.UPDATE, Color.UPDATE_COLOR),
+
+ /**
+ * role update.
+ */
+ ROLE_UPDATE("UPDATE:ROLE", DataEventTypeEnum.UPDATE, Color.UPDATE_COLOR);
/**
* type name.
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/BatchRoleDeletedEvent.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/BatchRoleDeletedEvent.java
new file mode 100644
index 000000000..41aa51ece
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/BatchRoleDeletedEvent.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.model.event.role;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.admin.model.entity.BaseDO;
+import org.apache.shenyu.admin.model.entity.RoleDO;
+import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.BatchChangedEvent;
+import org.apache.shenyu.admin.utils.ListUtil;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * BatchRuleDeletedEvent.
+ */
+public class BatchRoleDeletedEvent extends BatchChangedEvent {
+
+ private final List<String> deletedIds;
+
+ /**
+ * Create a new {@code BatchChangedEvent}.operator is unknown.
+ *
+ * @param source Current plugin state
+ * @param operator operator
+ */
+ public BatchRoleDeletedEvent(final Collection<RoleDO> source, final String operator) {
+ super(source, null, EventTypeEnum.ROLE_DELETE, operator);
+ this.deletedIds = ListUtil.map(source, BaseDO::getId);
+ }
+
+ @Override
+ public String buildContext() {
+ final String selector = ((Collection<?>) getSource())
+ .stream()
+ .map(s -> ((RoleDO) s).getRoleName())
+ .collect(Collectors.joining(","));
+ return String.format("the role[%s] is %s", selector, StringUtils.lowerCase(getType().getType().toString()));
+ }
+
+ /**
+ * get roles.
+ *
+ * @return list
+ */
+ public List<RoleDO> getRoles() {
+ return ((Collection<?>) getSource())
+ .stream()
+ .map(RoleDO.class::cast)
+ .collect(Collectors.toList());
+ }
+
+
+
+ /**
+ * get deleted ids.
+ *
+ * @return ids.
+ */
+ public List<String> getDeletedIds() {
+ return deletedIds;
+ }
+}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleChangedEvent.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleChangedEvent.java
new file mode 100644
index 000000000..965b1ad84
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleChangedEvent.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.model.event.role;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.admin.model.entity.RoleDO;
+import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+import org.apache.shenyu.admin.model.event.AdminDataModelChangedEvent;
+
+import java.util.Objects;
+
+/**
+ * RoleChangedEvent.
+ */
+public class RoleChangedEvent extends AdminDataModelChangedEvent {
+
+
+ /**
+ * Create a new {@code RoleChangedEvent}.operator is unknown.
+ *
+ * @param source Current role state
+ * @param before Before the change role state
+ * @param type event type
+ */
+ public RoleChangedEvent(final RoleDO source, final RoleDO before, final EventTypeEnum type, final String operator) {
+ super(source, before, type, operator);
+ }
+
+ @Override
+ public String buildContext() {
+ final RoleDO after = (RoleDO) getAfter();
+ if (Objects.isNull(getBefore())) {
+ return String.format("the role [%s] is %s", after.getRoleName(), StringUtils.lowerCase(getType().getType().toString()));
+ }
+ return String.format("the role [%s] is %s : %s", after.getRoleName(), StringUtils.lowerCase(getType().getType().toString()), contrast());
+
+ }
+
+ private String contrast() {
+ final RoleDO before = (RoleDO) getBefore();
+ Objects.requireNonNull(before);
+ final RoleDO after = (RoleDO) getAfter();
+ Objects.requireNonNull(after);
+ if (Objects.equals(before, after)) {
+ return "it no change";
+ }
+ final StringBuilder builder = new StringBuilder();
+ if (!Objects.equals(before.getRoleName(), after.getRoleName())) {
+ builder.append(String.format("name[%s => %s] ", before.getRoleName(), after.getRoleName()));
+ }
+ if (!Objects.equals(before.getDescription(), after.getDescription())) {
+ builder.append(String.format("disc[%s => %s] ", before.getDescription(), after.getDescription()));
+ }
+ return builder.toString();
+ }
+
+ @Override
+ public String eventName() {
+ return "role";
+ }
+}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleCreatedEvent.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleCreatedEvent.java
new file mode 100644
index 000000000..a5ed2727b
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleCreatedEvent.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.model.event.role;
+
+import org.apache.shenyu.admin.model.entity.RoleDO;
+import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+
+/**
+ * RuleCreatedEvent.
+ */
+public class RoleCreatedEvent extends RoleChangedEvent {
+
+
+ /**
+ * Create a new {@code RoleCreatedEvent}.operator is unknown.
+ *
+ * @param source Current plugin state
+ * @param operator operator
+ */
+ public RoleCreatedEvent(final RoleDO source, final String operator) {
+ super(source, null, EventTypeEnum.ROLE_CREATE, operator);
+ }
+
+ /**
+ * the created role.
+ *
+ * @return role
+ */
+ public RoleDO getRole() {
+ return (RoleDO) getSource();
+ }
+
+}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleUpdatedEvent.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleUpdatedEvent.java
new file mode 100644
index 000000000..76ab10d05
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/event/role/RoleUpdatedEvent.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.model.event.role;
+
+import org.apache.shenyu.admin.model.entity.RoleDO;
+import org.apache.shenyu.admin.model.enums.EventTypeEnum;
+
+import java.util.List;
+
+/**
+ * RoleUpdatedEvent.
+ */
+public class RoleUpdatedEvent extends RoleChangedEvent {
+
+ private final List<String> newPermission;
+
+ /**
+ * Create a new {@code RoleUpdatedEvent}.operator is unknown.
+ *
+ * @param source Current role state
+ * @param before before role state
+ * @param operator operator
+ */
+ public RoleUpdatedEvent(final RoleDO source, final RoleDO before, final String operator, final List<String> newPermission) {
+ super(source, before, EventTypeEnum.ROLE_UPDATE, operator);
+ this.newPermission = newPermission;
+ }
+
+ /**
+ * the created role.
+ *
+ * @return role
+ */
+ public RoleDO getRole() {
+ return (RoleDO) getSource();
+ }
+
+ /**
+ * get new permission.
+ *
+ * @return permission.
+ */
+ public List<String> getNewPermission() {
+ return newPermission;
+ }
+
+}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/RoleService.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/RoleService.java
index b4b434f4a..cdc33640e 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/RoleService.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/RoleService.java
@@ -17,6 +17,7 @@
package org.apache.shenyu.admin.service;
+import org.apache.commons.lang3.StringUtils;
import org.apache.shenyu.admin.model.dto.RoleDTO;
import org.apache.shenyu.admin.model.page.CommonPager;
import org.apache.shenyu.admin.model.query.RoleQuery;
@@ -29,15 +30,33 @@ import java.util.List;
* this is role service.
*/
public interface RoleService {
-
+
/**
* create or update rule.
*
* @param roleDTO {@linkplain RoleDTO}
* @return rows int
*/
- int createOrUpdate(RoleDTO roleDTO);
-
+ default int createOrUpdate(RoleDTO roleDTO) {
+ return StringUtils.isBlank(roleDTO.getId()) ? create(roleDTO) : update(roleDTO);
+ }
+
+ /**
+ * create or update rule.
+ *
+ * @param roleDTO {@linkplain RoleDTO}
+ * @return rows int
+ */
+ int create(RoleDTO roleDTO);
+
+ /**
+ * create or update rule.
+ *
+ * @param roleDTO {@linkplain RoleDTO}
+ * @return rows int
+ */
+ int update(RoleDTO roleDTO);
+
/**
* delete roles.
*
@@ -45,7 +64,7 @@ public interface RoleService {
* @return rows int
*/
int delete(List<String> ids);
-
+
/**
* find role by id.
*
@@ -53,7 +72,7 @@ public interface RoleService {
* @return {@linkplain RoleEditVO}
*/
RoleEditVO findById(String id);
-
+
/**
* find role by roleName.
*
@@ -61,7 +80,7 @@ public interface RoleService {
* @return {@linkplain RoleVO}
*/
RoleVO findByQuery(String roleName);
-
+
/**
* find page of role by query.
*
@@ -69,7 +88,7 @@ public interface RoleService {
* @return {@linkplain CommonPager}
*/
CommonPager<RoleVO> listByPage(RoleQuery roleQuery);
-
+
/**
* select all roles not super.
*
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PermissionServiceImpl.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PermissionServiceImpl.java
index 04fb530f7..c6e4fad6d 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PermissionServiceImpl.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/PermissionServiceImpl.java
@@ -30,6 +30,9 @@ import org.apache.shenyu.admin.model.entity.UserRoleDO;
import org.apache.shenyu.admin.model.event.resource.BatchResourceCreatedEvent;
import org.apache.shenyu.admin.model.event.resource.BatchResourceDeletedEvent;
import org.apache.shenyu.admin.model.event.resource.ResourceCreatedEvent;
+import org.apache.shenyu.admin.model.event.role.BatchRoleDeletedEvent;
+import org.apache.shenyu.admin.model.event.role.RoleUpdatedEvent;
+import org.apache.shenyu.admin.model.query.PermissionQuery;
import org.apache.shenyu.admin.model.vo.PermissionMenuVO;
import org.apache.shenyu.admin.model.vo.PermissionMenuVO.AuthPerm;
import org.apache.shenyu.admin.model.vo.ResourceVO;
@@ -44,6 +47,7 @@ import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -139,6 +143,26 @@ public class PermissionServiceImpl implements PermissionService {
permissionMapper.deleteByResourceId(event.getDeletedIds());
}
+ /**
+ * listen {@link BatchRoleDeletedEvent} delete permission.
+ *
+ * @param event event
+ */
+ @EventListener(BatchRoleDeletedEvent.class)
+ public void onRoleDeleted(final BatchRoleDeletedEvent event) {
+ permissionMapper.deleteByObjectIds(event.getDeletedIds());
+ }
+
+ /**
+ * listen {@link RoleUpdatedEvent} delete permission.
+ *
+ * @param event event
+ */
+ @EventListener(RoleUpdatedEvent.class)
+ public void onRoleUpdated(final RoleUpdatedEvent event) {
+ manageRolePermission(event.getRole().getId(), event.getNewPermission());
+ }
+
/**
* get resource by username.
*
@@ -191,4 +215,75 @@ public class PermissionServiceImpl implements PermissionService {
.map(item -> AuthPerm.buildAuthPerm(ResourceVO.buildResourceVO(item)))
.collect(Collectors.toList());
}
+
+
+ /**
+ * manger role permission.
+ *
+ * @param roleId role id.
+ * @param currentPermissionList {@linkplain List} current role permission ids
+ */
+ private void manageRolePermission(final String roleId, final List<String> currentPermissionList) {
+ List<String> lastPermissionList = permissionMapper.findByObjectId(roleId)
+ .stream()
+ .map(PermissionDO::getResourceId)
+ .collect(Collectors.toList());
+ List<String> addPermission = getListDiff(lastPermissionList, currentPermissionList);
+ if (CollectionUtils.isNotEmpty(addPermission)) {
+ batchSavePermission(addPermission.stream()
+ .map(node -> PermissionDO.buildPermissionDO(PermissionDTO
+ .builder()
+ .objectId(roleId)
+ .resourceId(node)
+ .build()))
+ .collect(Collectors.toList()));
+ }
+
+ List<String> deletePermission = getListDiff(currentPermissionList, lastPermissionList);
+ if (CollectionUtils.isNotEmpty(deletePermission)) {
+ deletePermission.forEach(node -> deleteByObjectIdAndResourceId(new PermissionQuery(roleId, node)));
+ }
+ }
+
+ /**
+ * get two list different.
+ *
+ * @param preList {@linkplain List}
+ * @param lastList {@linkplain List}
+ * @return {@linkplain List}
+ */
+ private List<String> getListDiff(final List<String> preList, final List<String> lastList) {
+ if (CollectionUtils.isEmpty(lastList)) {
+ return null;
+ }
+
+ if (CollectionUtils.isEmpty(preList)) {
+ return lastList;
+ }
+
+ Map<String, Integer> map = preList.stream()
+ .distinct()
+ .collect(Collectors.toMap(source -> source, source -> 1));
+ return lastList.stream()
+ .filter(item -> !map.containsKey(item))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * batch save permission.
+ *
+ * @param permissionDOList {@linkplain List}
+ */
+ private void batchSavePermission(final List<PermissionDO> permissionDOList) {
+ permissionDOList.forEach(permissionMapper::insertSelective);
+ }
+
+ /**
+ * delete by object and resource id.
+ *
+ * @param permissionQuery permission query
+ */
+ private void deleteByObjectIdAndResourceId(final PermissionQuery permissionQuery) {
+ permissionMapper.deleteByObjectIdAndResourceId(permissionQuery);
+ }
}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RoleServiceImpl.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RoleServiceImpl.java
index 8b2cf5350..768bf2774 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RoleServiceImpl.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RoleServiceImpl.java
@@ -23,14 +23,12 @@ import org.apache.shenyu.admin.aspect.annotation.Pageable;
import org.apache.shenyu.admin.mapper.PermissionMapper;
import org.apache.shenyu.admin.mapper.ResourceMapper;
import org.apache.shenyu.admin.mapper.RoleMapper;
-import org.apache.shenyu.admin.model.dto.PermissionDTO;
import org.apache.shenyu.admin.model.dto.ResourceDTO;
import org.apache.shenyu.admin.model.dto.RoleDTO;
import org.apache.shenyu.admin.model.entity.PermissionDO;
import org.apache.shenyu.admin.model.entity.RoleDO;
import org.apache.shenyu.admin.model.page.CommonPager;
import org.apache.shenyu.admin.model.page.PageResultUtils;
-import org.apache.shenyu.admin.model.query.PermissionQuery;
import org.apache.shenyu.admin.model.query.RoleQuery;
import org.apache.shenyu.admin.model.vo.ResourceVO;
import org.apache.shenyu.admin.model.vo.RoleEditVO;
@@ -38,10 +36,13 @@ import org.apache.shenyu.admin.model.vo.RoleEditVO.PermissionInfo;
import org.apache.shenyu.admin.model.vo.RoleEditVO.ResourceInfo;
import org.apache.shenyu.admin.model.vo.RoleVO;
import org.apache.shenyu.admin.service.RoleService;
+import org.apache.shenyu.admin.service.publish.RoleEventPublisher;
+import org.apache.shenyu.admin.utils.ListUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -57,21 +58,25 @@ import java.util.stream.Collectors;
*/
@Service
public class RoleServiceImpl implements RoleService {
-
+
private final RoleMapper roleMapper;
-
+
private final PermissionMapper permissionMapper;
-
+
private final ResourceMapper resourceMapper;
-
+
+ private final RoleEventPublisher roleEventPublisher;
+
public RoleServiceImpl(final RoleMapper roleMapper,
final PermissionMapper permissionMapper,
- final ResourceMapper resourceMapper) {
+ final ResourceMapper resourceMapper,
+ final RoleEventPublisher roleEventPublisher) {
this.roleMapper = roleMapper;
this.permissionMapper = permissionMapper;
this.resourceMapper = resourceMapper;
+ this.roleEventPublisher = roleEventPublisher;
}
-
+
/**
* create or update role info.
*
@@ -81,15 +86,31 @@ public class RoleServiceImpl implements RoleService {
@Override
@Transactional(rollbackFor = Exception.class)
public int createOrUpdate(final RoleDTO roleDTO) {
- RoleDO roleDO = RoleDO.buildRoleDO(roleDTO);
- if (StringUtils.isEmpty(roleDTO.getId())) {
- return roleMapper.insertSelective(roleDO);
- } else {
- manageRolePermission(roleDTO.getId(), roleDTO.getCurrentPermissionIds());
- return roleMapper.updateSelective(roleDO);
+ return RoleService.super.createOrUpdate(roleDTO);
+ }
+
+ @Override
+ public int create(final RoleDTO roleDTO) {
+ final RoleDO role = RoleDO.buildRoleDO(roleDTO);
+ final int insertCount = roleMapper.insertSelective(role);
+ if (insertCount > 0) {
+ roleEventPublisher.onCreated(role);
}
+ return insertCount;
}
-
+
+ @Override
+ public int update(final RoleDTO roleDTO) {
+ final RoleDO before = roleMapper.selectById(roleDTO.getId());
+ final RoleDO role = RoleDO.buildRoleDO(roleDTO);
+ final int updateCount = roleMapper.updateSelective(role);
+ if (updateCount > 0) {
+ // add new permission
+ roleEventPublisher.onUpdated(role, before, roleDTO.getCurrentPermissionIds());
+ }
+ return updateCount;
+ }
+
/**
* delete role info.
*
@@ -98,10 +119,14 @@ public class RoleServiceImpl implements RoleService {
*/
@Override
public int delete(final List<String> ids) {
- permissionMapper.deleteByObjectIds(ids);
- return roleMapper.delete(ids);
+ final List<RoleDO> roles = roleMapper.selectByIds(ids);
+ final int deleteCount = roleMapper.delete(ids);
+ if (deleteCount > 0) {
+ roleEventPublisher.onDeleted(roles);
+ }
+ return deleteCount;
}
-
+
/**
* find role info by id.
*
@@ -115,7 +140,7 @@ public class RoleServiceImpl implements RoleService {
.map(item -> new RoleEditVO(getPermissionIdsByRoleId(item.getId()), item, getAllPermissions()))
.orElse(null);
}
-
+
/**
* find role by query.
*
@@ -126,7 +151,7 @@ public class RoleServiceImpl implements RoleService {
public RoleVO findByQuery(final String roleName) {
return RoleVO.buildRoleVO(roleMapper.findByRoleName(roleName));
}
-
+
/**
* find page of role by query.
*
@@ -141,7 +166,7 @@ public class RoleServiceImpl implements RoleService {
.map(RoleVO::buildRoleVO)
.collect(Collectors.toList()));
}
-
+
/**
* select all roles.
*
@@ -149,28 +174,22 @@ public class RoleServiceImpl implements RoleService {
*/
@Override
public List<RoleVO> selectAll() {
- return roleMapper.selectAll()
- .stream()
- .map(RoleVO::buildRoleVO)
- .collect(Collectors.toList());
+ return ListUtil.map(roleMapper.selectAll(), RoleVO::buildRoleVO);
}
-
+
/**
* get all permissions.
*
* @return {@linkplain PermissionInfo}
*/
private PermissionInfo getAllPermissions() {
- List<ResourceVO> resourceVOList = resourceMapper.selectAll()
- .stream()
- .map(ResourceVO::buildResourceVO)
- .collect(Collectors.toList());
- List<String> permissionIds = resourceVOList.stream().map(ResourceVO::getId).collect(Collectors.toList());
-
- List<ResourceInfo> treeList = getTreeModelList(resourceVOList);
- return PermissionInfo.builder().treeList(treeList).permissionIds(permissionIds).build();
+ final List<ResourceVO> resourceVOList = ListUtil.map(resourceMapper.selectAll(), ResourceVO::buildResourceVO);
+ return PermissionInfo.builder()
+ .treeList(getTreeModelList(resourceVOList))
+ .permissionIds(ListUtil.map(resourceVOList, ResourceVO::getId))
+ .build();
}
-
+
/**
* get permission ids by role id.
*
@@ -178,12 +197,9 @@ public class RoleServiceImpl implements RoleService {
* @return {@linkplain List}
*/
private List<String> getPermissionIdsByRoleId(final String roleId) {
- return permissionMapper.findByObjectId(roleId)
- .stream()
- .map(PermissionDO::getResourceId)
- .collect(Collectors.toList());
+ return ListUtil.map(permissionMapper.findByObjectId(roleId), PermissionDO::getResourceId);
}
-
+
/**
* get menu list.
*
@@ -191,33 +207,21 @@ public class RoleServiceImpl implements RoleService {
* @return list of {@linkplain ResourceInfo}
*/
private List<ResourceInfo> getTreeModelList(final List<ResourceVO> metaList) {
-
- List<ResourceInfo> retList = new ArrayList<>();
+ final List<ResourceInfo> retList = new ArrayList<>();
if (CollectionUtils.isEmpty(metaList)) {
return retList;
}
- Map<String, ResourceInfo> resourceInfoMap = metaList.stream().map(ResourceInfo::buildResourceInfo)
+ final Map<String, ResourceInfo> resourceInfoMap = metaList.stream()
+ .map(ResourceInfo::buildResourceInfo)
.filter(resourceInfo -> Objects.nonNull(resourceInfo) && StringUtils.isNotEmpty(resourceInfo.getId()))
.collect(Collectors.toMap(ResourceInfo::getId, Function.identity(), (value1, value2) -> value1));
- Map<String, Set<String>> metaChildrenMap = metaList.stream().filter(meta -> Objects.nonNull(meta) && StringUtils.isNotEmpty(meta.getId()))
- .collect(Collectors.toMap(ResourceVO::getParentId,
- resourceVO -> {
- Set<String> idSet = new LinkedHashSet<>();
- idSet.add(resourceVO.getId());
- return idSet;
- }, (set1, set2) -> {
- set1.addAll(set2);
- return set1;
- }, LinkedHashMap::new));
+ final Map<String, Set<String>> metaChildrenMap = metaList.stream()
+ .filter(meta -> Objects.nonNull(meta) && StringUtils.isNotEmpty(meta.getId()))
+ .collect(Collectors.toMap(ResourceVO::getParentId, resourceVO -> new LinkedHashSet<>(Collections.singletonList(resourceVO.getId())), ListUtil::mergeSet, LinkedHashMap::new));
metaChildrenMap.forEach((parent, children) -> {
- ResourceInfo resourceInfo = resourceInfoMap.get(parent);
if (CollectionUtils.isNotEmpty(children)) {
- List<ResourceInfo> targetList;
- if (Objects.isNull(resourceInfo)) {
- targetList = retList;
- } else {
- targetList = resourceInfo.getChildren();
- }
+ ResourceInfo resourceInfo = resourceInfoMap.get(parent);
+ List<ResourceInfo> targetList = Objects.isNull(resourceInfo) ? retList : resourceInfo.getChildren();
children.forEach(child -> {
ResourceInfo data = resourceInfoMap.get(child);
if (Objects.nonNull(data)) {
@@ -228,62 +232,5 @@ public class RoleServiceImpl implements RoleService {
});
return retList;
}
-
- /**
- * get two list different.
- *
- * @param preList {@linkplain List}
- * @param lastList {@linkplain List}
- * @return {@linkplain List}
- */
- private List<String> getListDiff(final List<String> preList, final List<String> lastList) {
- if (CollectionUtils.isEmpty(lastList)) {
- return null;
- }
-
- if (CollectionUtils.isEmpty(preList)) {
- return lastList;
- }
-
- Map<String, Integer> map = preList.stream().distinct()
- .collect(Collectors.toMap(source -> source, source -> 1));
- return lastList.stream().filter(item -> !map.containsKey(item)).collect(Collectors.toList());
- }
-
- /**
- * batch save permission.
- *
- * @param permissionDOList {@linkplain List}
- */
- private void batchSavePermission(final List<PermissionDO> permissionDOList) {
- permissionDOList.forEach(permissionMapper::insertSelective);
- }
-
- /**
- * delete by object and resource id.
- *
- * @param permissionQuery permission query
- */
- private void deleteByObjectIdAndResourceId(final PermissionQuery permissionQuery) {
- permissionMapper.deleteByObjectIdAndResourceId(permissionQuery);
- }
-
- /**
- * manger role permission.
- *
- * @param roleId role id.
- * @param currentPermissionList {@linkplain List} current role permission ids
- */
- private void manageRolePermission(final String roleId, final List<String> currentPermissionList) {
- List<String> lastPermissionList = permissionMapper.findByObjectId(roleId).stream().map(PermissionDO::getResourceId).collect(Collectors.toList());
- List<String> addPermission = getListDiff(lastPermissionList, currentPermissionList);
- if (CollectionUtils.isNotEmpty(addPermission)) {
- batchSavePermission(addPermission.stream().map(node -> PermissionDO.buildPermissionDO(PermissionDTO.builder().objectId(roleId).resourceId(node).build())).collect(Collectors.toList()));
- }
-
- List<String> deletePermission = getListDiff(currentPermissionList, lastPermissionList);
- if (CollectionUtils.isNotEmpty(deletePermission)) {
- deletePermission.forEach(node -> deleteByObjectIdAndResourceId(new PermissionQuery(roleId, node)));
- }
- }
+
}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/RoleEventPublisher.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/RoleEventPublisher.java
new file mode 100644
index 000000000..62b4c4bba
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/RoleEventPublisher.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.service.publish;
+
+import org.apache.shenyu.admin.model.entity.RoleDO;
+import org.apache.shenyu.admin.model.event.AdminDataModelChangedEvent;
+import org.apache.shenyu.admin.model.event.role.BatchRoleDeletedEvent;
+import org.apache.shenyu.admin.model.event.role.RoleCreatedEvent;
+import org.apache.shenyu.admin.model.event.role.RoleUpdatedEvent;
+import org.apache.shenyu.admin.utils.SessionUtil;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * RoleEventPublisher.
+ */
+@Component
+public class RoleEventPublisher implements AdminDataModelChangedEventPublisher<RoleDO> {
+
+ private final ApplicationEventPublisher publisher;
+
+ public RoleEventPublisher(final ApplicationEventPublisher publisher) {
+ this.publisher = publisher;
+ }
+
+ /**
+ * on rule created.
+ *
+ * @param rule rule
+ */
+ @Override
+ public void onCreated(final RoleDO rule) {
+ publish(new RoleCreatedEvent(rule, SessionUtil.visitorName()));
+ }
+
+
+ /**
+ * on rule updated.
+ *
+ * @param rule rule
+ * @param before before rule
+ * @param permission new permission
+ */
+ public void onUpdated(final RoleDO rule, final RoleDO before, final List<String> permission) {
+ publish(new RoleUpdatedEvent(rule, before, SessionUtil.visitorName(), permission));
+ }
+
+
+ /**
+ * role delete.
+ *
+ * @param roles data
+ */
+ @Override
+ public void onDeleted(final Collection<RoleDO> roles) {
+ publish(new BatchRoleDeletedEvent(roles, SessionUtil.visitorName()));
+ }
+
+
+ /**
+ * event.
+ *
+ * @param event event.
+ */
+ @Override
+ public void publish(final AdminDataModelChangedEvent event) {
+ publisher.publishEvent(event);
+ }
+
+}
diff --git a/shenyu-admin/src/main/resources/mappers/role-sqlmap.xml b/shenyu-admin/src/main/resources/mappers/role-sqlmap.xml
index c80bc2d49..15187f547 100644
--- a/shenyu-admin/src/main/resources/mappers/role-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/role-sqlmap.xml
@@ -82,6 +82,15 @@
WHERE id = #{id}
LIMIT 1
</select>
+ <select id="selectByIds" resultType="org.apache.shenyu.admin.model.entity.RoleDO">
+ select
+ <include refid="Base_Column_List"/>
+ FROM role
+ WHERE id IN
+ <foreach item="id" collection="ids" open="(" separator="," close=")">
+ #{id, jdbcType=VARCHAR}
+ </foreach>
+ </select>
<insert id="insert" parameterType="org.apache.shenyu.admin.model.entity.RoleDO">
INSERT INTO role
diff --git a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/RoleServiceTest.java b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/RoleServiceTest.java
index bf2fe7c98..169a5239d 100644
--- a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/RoleServiceTest.java
+++ b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/RoleServiceTest.java
@@ -29,6 +29,7 @@ import org.apache.shenyu.admin.model.query.RoleQuery;
import org.apache.shenyu.admin.model.vo.RoleEditVO;
import org.apache.shenyu.admin.model.vo.RoleVO;
import org.apache.shenyu.admin.service.impl.RoleServiceImpl;
+import org.apache.shenyu.admin.service.publish.RoleEventPublisher;
import org.apache.shenyu.common.utils.UUIDUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -51,7 +52,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -71,6 +71,9 @@ public class RoleServiceTest {
@Mock
private PermissionMapper permissionMapper;
+
+ @Mock
+ private RoleEventPublisher publisher;
@Mock
private ResourceMapper resourceMapper;
@@ -79,6 +82,7 @@ public class RoleServiceTest {
public void testCreateOrUpdate() {
//test save
given(this.roleMapper.insertSelective(any())).willReturn(1);
+ given(this.roleMapper.insertSelective(any())).willReturn(1);
RoleDTO roleDTO = buildRoleDTOWithoutId();
int count = roleService.createOrUpdate(roleDTO);
assertThat(count, equalTo(1));
@@ -90,18 +94,19 @@ public class RoleServiceTest {
roleDTO = buildRoleDTO();
count = roleService.createOrUpdate(roleDTO);
assertThat(count, equalTo(1));
- verify(permissionMapper, times(1)).findByObjectId(anyString());
- verify(permissionMapper, times(0)).deleteByObjectIdAndResourceId(any());
- verify(permissionMapper, times(0)).insertSelective(any());
+// verify(permissionMapper, times(1)).findByObjectId(anyString());
+// verify(permissionMapper, times(0)).deleteByObjectIdAndResourceId(any());
+// verify(permissionMapper, times(0)).insertSelective(any());
//test update with delete permissions
reset(permissionMapper, roleMapper);
given(this.roleMapper.updateSelective(any())).willReturn(1);
- given(this.permissionMapper.findByObjectId(anyString())).willReturn(Arrays.asList(PermissionDO.builder().resourceId("1").build()));
+ given(this.permissionMapper.findByObjectId(anyString())).willReturn(Collections.singletonList(PermissionDO.builder().resourceId("1").build()));
count = roleService.createOrUpdate(roleDTO);
- verify(permissionMapper, times(1)).findByObjectId(anyString());
- verify(permissionMapper, atLeastOnce()).deleteByObjectIdAndResourceId(any());
- verify(permissionMapper, times(0)).insertSelective(any());
+ assertThat(count, equalTo(1));
+// verify(permissionMapper, times(1)).findByObjectId(anyString());
+// verify(permissionMapper, atLeastOnce()).deleteByObjectIdAndResourceId(any());
+// verify(permissionMapper, times(0)).insertSelective(any());
//test update with insert permissions
reset(permissionMapper, roleMapper);
@@ -109,26 +114,25 @@ public class RoleServiceTest {
roleDTO.setCurrentPermissionIds(Arrays.asList("1", "2"));
count = roleService.createOrUpdate(roleDTO);
assertThat(count, equalTo(1));
- verify(permissionMapper, times(1)).findByObjectId(anyString());
- verify(permissionMapper, times(0)).deleteByObjectIdAndResourceId(any());
- verify(permissionMapper, atLeastOnce()).insertSelective(any());
+// verify(permissionMapper, times(1)).findByObjectId(anyString());
+// verify(permissionMapper, times(0)).deleteByObjectIdAndResourceId(any());
+// verify(permissionMapper, atLeastOnce()).insertSelective(any());
//test update with exist difference between existing and current permissions
reset(permissionMapper, roleMapper);
given(this.roleMapper.updateSelective(any())).willReturn(1);
- given(this.permissionMapper.findByObjectId(anyString())).willReturn(Arrays.asList(PermissionDO.builder().resourceId("3").build()));
+ given(this.permissionMapper.findByObjectId(anyString())).willReturn(Collections.singletonList(PermissionDO.builder().resourceId("3").build()));
count = roleService.createOrUpdate(roleDTO);
assertThat(count, equalTo(1));
- verify(permissionMapper, times(1)).findByObjectId(anyString());
- verify(permissionMapper, atLeastOnce()).deleteByObjectIdAndResourceId(any());
- verify(permissionMapper, atLeastOnce()).insertSelective(any());
+// verify(permissionMapper, times(1)).findByObjectId(anyString());
+// verify(permissionMapper, atLeastOnce()).deleteByObjectIdAndResourceId(any());
+// verify(permissionMapper, atLeastOnce()).insertSelective(any());
}
@Test
public void testDelete() {
List<String> ids = Arrays.asList("1", "2");
roleService.delete(ids);
- verify(permissionMapper, times(1)).deleteByObjectIds(ids);
verify(roleMapper, times(1)).delete(ids);
}