diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/RoleEntity.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/RoleEntity.java index b21401b5..3c193115 100644 --- a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/RoleEntity.java +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/RoleEntity.java @@ -15,6 +15,7 @@ import org.hswebframework.web.authorization.Dimension; import org.hswebframework.web.authorization.simple.SimpleDimension; import org.hswebframework.web.crud.generator.Generators; import org.jetlinks.community.auth.enums.RoleState; +import org.jetlinks.community.auth.service.RoleGroupService; import javax.persistence.Column; import javax.persistence.Table; @@ -42,6 +43,11 @@ public class RoleEntity extends GenericEntity implements RecordCreationE @DefaultValue("enabled") private RoleState state; + @Column(length = 64) + @Schema(description = "所属分组") + @DefaultValue(RoleGroupService.DEFAULT_GROUP_ID) + private String groupId; + @Column(updatable = false) @Schema( description = "创建者ID(只读)" diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/RoleGroupEntity.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/RoleGroupEntity.java new file mode 100644 index 00000000..76b59e33 --- /dev/null +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/RoleGroupEntity.java @@ -0,0 +1,50 @@ +package org.jetlinks.community.auth.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.validator.constraints.Length; +import org.hswebframework.ezorm.rdb.mapping.annotation.Comment; +import org.hswebframework.ezorm.rdb.mapping.annotation.DefaultValue; +import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity; +import org.hswebframework.web.api.crud.entity.RecordCreationEntity; +import org.hswebframework.web.crud.annotation.EnableEntityEvent; +import org.hswebframework.web.crud.generator.Generators; + +import javax.persistence.Column; +import javax.persistence.Table; +import java.util.List; + +@Getter +@Setter +@Table(name = "s_role_group") +@Comment("角色分组表") +@EnableEntityEvent +public class RoleGroupEntity extends GenericTreeSortSupportEntity implements RecordCreationEntity { + + @Column(length = 64) + @Length(min = 1, max = 64) + @Schema(description = "名称") + private String name; + + @Column + @Length(max = 255) + @Schema(description = "说明") + private String description; + + @Column(updatable = false) + @Schema( + description = "创建者ID(只读)" + , accessMode = Schema.AccessMode.READ_ONLY + ) + private String creatorId; + + @Column(updatable = false) + @DefaultValue(generator = Generators.CURRENT_TIME) + @Schema(description = "创建时间" + , accessMode = Schema.AccessMode.READ_ONLY + ) + private Long createTime; + + private List children; +} diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/service/RoleGroupService.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/service/RoleGroupService.java new file mode 100644 index 00000000..e69e567f --- /dev/null +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/service/RoleGroupService.java @@ -0,0 +1,101 @@ +package org.jetlinks.community.auth.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.crud.events.EntityDeletedEvent; +import org.hswebframework.web.crud.query.QueryHelper; +import org.hswebframework.web.crud.service.GenericReactiveTreeSupportCrudService; +import org.hswebframework.web.exception.I18nSupportException; +import org.hswebframework.web.id.IDGenerator; + +import org.jetlinks.community.auth.entity.RoleGroupEntity; +import org.jetlinks.community.auth.entity.RoleEntity; +import org.jetlinks.community.auth.web.response.RoleGroupDetailTree; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; + +@Service +@Slf4j +@AllArgsConstructor +public class RoleGroupService extends GenericReactiveTreeSupportCrudService implements CommandLineRunner { + + public static final String DEFAULT_GROUP_ID = "default_group"; + + private final RoleService roleService; + + + /** + * 分组下存在角色时不可删除 + */ + @EventListener + public void handleEvent(EntityDeletedEvent event) { + event.async( + Flux.fromIterable(event.getEntity()) + .map(RoleGroupEntity::getId) + //默认分组不可删除 + .filter(id -> !DEFAULT_GROUP_ID.equals(id)) + .collectList() + .filter(CollectionUtils::isNotEmpty) + .flatMapMany(ids -> roleService + .createQuery() + .in(RoleEntity::getGroupId, ids) + .count() + .filter(i -> i <= 0) + .switchIfEmpty(Mono.error(() -> new I18nSupportException("error.group_role_exists")))) + ); + } + + + public Flux queryDetailTree(QueryParamEntity groupParam, QueryParamEntity roleParam) { + groupParam.setPaging(false); + roleParam.setPaging(false); + Flux groupDetails = this + .query(groupParam) + .map(RoleGroupDetailTree::of); + return QueryHelper + .combineOneToMany( + groupDetails, + RoleGroupDetailTree::getGroupId, + roleService.createQuery().setParam(roleParam), + RoleEntity::getGroupId, + RoleGroupDetailTree::setRoles + ); + } + + + @Override + public IDGenerator getIDGenerator() { + return IDGenerator.SNOW_FLAKE_STRING; + } + + @Override + public void setChildren(RoleGroupEntity entity, List children) { + entity.setChildren(children); + } + + + /** + * 兼容旧数据 + */ + @Override + public void run(String... args) { + //兼容旧数据,空分组即为默认分组 + roleService + .createUpdate() + .set(RoleEntity::getGroupId, DEFAULT_GROUP_ID) + .isNull(RoleEntity::getGroupId) + .execute() + .subscribe(ignore -> { + }, + err -> log.error("init role groupId error", err)); + + } + +} diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/RoleGroupController.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/RoleGroupController.java new file mode 100644 index 00000000..5c3e8200 --- /dev/null +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/RoleGroupController.java @@ -0,0 +1,48 @@ +package org.jetlinks.community.auth.web; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hswebframework.web.api.crud.entity.QueryParamEntity; +import org.hswebframework.web.authorization.annotation.Resource; +import org.hswebframework.web.authorization.annotation.SaveAction; +import org.hswebframework.web.crud.service.ReactiveCrudService; +import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController; +import org.jetlinks.community.auth.entity.RoleGroupEntity; +import org.jetlinks.community.auth.service.RoleGroupService; +import org.jetlinks.community.auth.web.response.RoleGroupDetailTree; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping("/role/group") +@Resource(id = "role-group", name = "角色组管理") +@AllArgsConstructor +@Getter +@Tag(name = "角色组管理") +public class RoleGroupController implements ReactiveServiceCrudController { + + private final RoleGroupService roleGroupService; + + @PostMapping("/detail/_query/tree") + @Operation(summary = "查询分组及角色(树状)") + @SaveAction + public Flux queryDetailTree(@RequestParam(defaultValue = "false") @Parameter(description = "true:query为角色条件,false:query为分组条件") boolean queryByRole, + @RequestBody Mono query) { + + return Mono + .zip(queryByRole ? query : Mono.just(new QueryParamEntity()), + queryByRole ? Mono.just(new QueryParamEntity()) : query) + .flatMapMany(tp2 -> roleGroupService.queryDetailTree(tp2.getT2(), tp2.getT1())); + + + } + + @Override + public ReactiveCrudService getService() { + return roleGroupService; + } +} diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/response/RoleGroupDetailTree.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/response/RoleGroupDetailTree.java new file mode 100644 index 00000000..ac9f9f9d --- /dev/null +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/response/RoleGroupDetailTree.java @@ -0,0 +1,35 @@ +package org.jetlinks.community.auth.web.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.jetlinks.community.auth.entity.RoleEntity; +import org.jetlinks.community.auth.entity.RoleGroupEntity; + +import java.util.List; + +/** + * @author gyl + * @since 2.1 + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor(staticName = "of") +public class RoleGroupDetailTree { + + private String groupId; + private String groupName; + private List roles; + + + public static RoleGroupDetailTree of(RoleGroupEntity group) { + RoleGroupDetailTree roleGroupDetailTree = new RoleGroupDetailTree(); + roleGroupDetailTree.setGroupId(group.getId()); + roleGroupDetailTree.setGroupName(group.getName()); + return roleGroupDetailTree; + } + + +}