diff --git a/backend/src/main/java/io/dataease/auth/annotation/DeCleaner.java b/backend/src/main/java/io/dataease/auth/annotation/DeCleaner.java index 40f9c57c26..8e3f697171 100644 --- a/backend/src/main/java/io/dataease/auth/annotation/DeCleaner.java +++ b/backend/src/main/java/io/dataease/auth/annotation/DeCleaner.java @@ -10,5 +10,10 @@ import java.lang.annotation.Target; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DeCleaner { + DePermissionType value(); + + int paramIndex() default 0; + + String key() default ""; } diff --git a/backend/src/main/java/io/dataease/auth/aop/DeCleanerAnnotationHandler.java b/backend/src/main/java/io/dataease/auth/aop/DeCleanerAnnotationHandler.java index dcb8744272..ea13f93158 100644 --- a/backend/src/main/java/io/dataease/auth/aop/DeCleanerAnnotationHandler.java +++ b/backend/src/main/java/io/dataease/auth/aop/DeCleanerAnnotationHandler.java @@ -2,73 +2,178 @@ package io.dataease.auth.aop; import io.dataease.auth.annotation.DeCleaner; import io.dataease.auth.api.dto.CurrentUserDto; +import io.dataease.auth.util.ReflectUtil; import io.dataease.commons.constants.AuthConstants; import io.dataease.commons.constants.DePermissionType; +import io.dataease.commons.model.AuthURD; import io.dataease.commons.utils.AuthUtils; import io.dataease.commons.utils.LogUtil; import io.dataease.listener.util.CacheUtils; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; +import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; @Aspect @Component public class DeCleanerAnnotationHandler { - @Around(value = "@annotation(io.dataease.auth.annotation.DeCleaner)") - public Object CleanerAround(ProceedingJoinPoint point) { + @AfterReturning(value = "@annotation(io.dataease.auth.annotation.DeCleaner)") + public void CleanerAround(JoinPoint point) { try { MethodSignature ms = (MethodSignature) point.getSignature(); Method method = ms.getMethod(); DeCleaner deCleaner = method.getAnnotation(DeCleaner.class); DePermissionType type = deCleaner.value(); + String key = deCleaner.key(); + Object[] args = point.getArgs(); + Object paramValue = null; + if (ObjectUtils.isNotEmpty(key) && ArrayUtils.isNotEmpty(args)) { + int pi = deCleaner.paramIndex(); + Object arg = point.getArgs()[pi]; + paramValue = getParamValue(arg, key, 0); + } + switch (type.name()) { case "DATASOURCE": - cleanDataSource(); + cleanDataSource(paramValue); break; case "DATASET": - cleanDataSet(); + cleanDataSet(paramValue); break; default: - cleanPanel(); + cleanPanel(paramValue); break; } - return point.proceed(point.getArgs()); - } catch (Throwable e) { LogUtil.error(e.getMessage(), e); throw new RuntimeException(e); } } - public void cleanPanel() { + + + private void cleanCacheParent(String pid, String type) { + if (StringUtils.isBlank(pid) || StringUtils.isBlank(type)) { + return; + } + CurrentUserDto user = AuthUtils.getUser(); + List resourceIds = AuthUtils.parentResources(pid.toString(), type); + if (CollectionUtils.isEmpty(resourceIds))return; + resourceIds.forEach(resourceId -> { + AuthURD authURD = AuthUtils.authURDR(resourceId); + Optional.ofNullable(authURD.getUserIds()).ifPresent(ids -> { + ids.forEach(id -> { + CacheUtils.remove("user_"+type, "user" + id); + }); + }); + Optional.ofNullable(authURD.getRoleIds()).ifPresent(ids -> { + ids.forEach(id -> { + CacheUtils.remove("role_"+type, "role" + id); + }); + }); + Optional.ofNullable(authURD.getDeptIds()).ifPresent(ids -> { + ids.forEach(id -> { + List depts = AuthUtils.getAuthModels(id.toString(), "dept", user.getUserId(), user.getIsAdmin()); + depts.forEach(deptId -> { + CacheUtils.remove("dept_"+type, "dept" + deptId); + }); + }); + }); + }); + } + + public void cleanPanel(Object pid) { CurrentUserDto user = AuthUtils.getUser(); CacheUtils.remove(AuthConstants.USER_PANEL_NAME, "user" + user.getUserId()); CacheUtils.remove(AuthConstants.DEPT_PANEL_NAME, "dept" + user.getDeptId()); user.getRoles().forEach(role -> { CacheUtils.remove(AuthConstants.ROLE_PANEL_NAME, "role" + role.getId()); }); + + Optional.ofNullable(pid).ifPresent(resourceId -> { + cleanCacheParent(resourceId.toString(), "panel"); + }); + + } - public void cleanDataSet() { + public void cleanDataSet(Object pid) { CurrentUserDto user = AuthUtils.getUser(); CacheUtils.remove(AuthConstants.USER_DATASET_NAME, "user" + user.getUserId()); CacheUtils.remove(AuthConstants.DEPT_DATASET_NAME, "dept" + user.getDeptId()); user.getRoles().forEach(role -> { CacheUtils.remove(AuthConstants.ROLE_DATASET_NAME, "role" + role.getId()); }); + + Optional.ofNullable(pid).ifPresent(resourceId -> { + cleanCacheParent(resourceId.toString(), "dataset"); + }); } - public void cleanDataSource() { + public void cleanDataSource(Object pid) { CurrentUserDto user = AuthUtils.getUser(); CacheUtils.remove(AuthConstants.USER_LINK_NAME, "user" + user.getUserId()); CacheUtils.remove(AuthConstants.DEPT_LINK_NAME, "dept" + user.getDeptId()); user.getRoles().forEach(role -> { CacheUtils.remove(AuthConstants.ROLE_LINK_NAME, "role" + role.getId()); }); + + Optional.ofNullable(pid).ifPresent(resourceId -> { + cleanCacheParent(resourceId.toString(), "link"); + }); + } + + private Object getParamValue(Object arg, String key, int layer) throws Exception{ + if (ObjectUtils.isNotEmpty(arg)) return null; + Class parameterType = arg.getClass(); + if (parameterType.isPrimitive() || ReflectUtil.isWrapClass(parameterType) || ReflectUtil.isString(parameterType)) { + return arg; + } else if (ReflectUtil.isArray(parameterType)) { + Object result; + for (int i = 0; i < Array.getLength(arg); i++) { + Object o = Array.get(arg, i); + + if (ObjectUtils.isNotEmpty((result = getParamValue(o, key, layer)))) { + return result; + } + } + return null; + } else if (ReflectUtil.isCollection(parameterType)) { + Object[] array = ((Collection) arg).toArray(); + Object result; + for (int i = 0; i < array.length; i++) { + Object o = array[i]; + if (ObjectUtils.isNotEmpty((result = getParamValue(o, key, layer)))) { + return result; + } + } + return null; + } else if (ReflectUtil.isMap(parameterType)) { + Map argMap = (Map) arg; + String[] values = key.split("\\."); + Object o = argMap.get(values[layer]); + return getParamValue(o, key, ++layer); + } else { + // 当作自定义类处理 + String[] values = key.split("\\."); + String fieldName = values[layer]; + + Object fieldValue = ReflectUtil.getFieldValue(arg, values[layer]); + return getParamValue(fieldValue, key, ++layer); + + } } } diff --git a/backend/src/main/java/io/dataease/auth/aop/DePermissionAnnotationHandler.java b/backend/src/main/java/io/dataease/auth/aop/DePermissionAnnotationHandler.java index cd676f3de4..71d09e393b 100644 --- a/backend/src/main/java/io/dataease/auth/aop/DePermissionAnnotationHandler.java +++ b/backend/src/main/java/io/dataease/auth/aop/DePermissionAnnotationHandler.java @@ -3,10 +3,10 @@ package io.dataease.auth.aop; import io.dataease.auth.annotation.DePermission; import io.dataease.auth.annotation.DePermissions; import io.dataease.auth.entity.AuthItem; +import io.dataease.auth.util.ReflectUtil; import io.dataease.commons.utils.AuthUtils; import io.dataease.commons.utils.LogUtil; import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.annotation.Logical; import org.aspectj.lang.ProceedingJoinPoint; @@ -14,9 +14,7 @@ import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; - import java.lang.reflect.Array; -import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; import java.util.stream.Collectors; @@ -111,13 +109,13 @@ public class DePermissionAnnotationHandler { item -> item.getLevel() >= requireLevel).map(AuthItem::getAuthSource).collect(Collectors.toSet()); Class parameterType = arg.getClass(); - if (parameterType.isPrimitive() || isWrapClass(parameterType) || isString(parameterType)) { + if (parameterType.isPrimitive() || ReflectUtil.isWrapClass(parameterType) || ReflectUtil.isString(parameterType)) { boolean permissionValid = resourceIds.contains(arg); if (permissionValid) return true; throw new UnauthorizedException("Subject does not have permission[" + annotation.level().name() + ":" + annotation.type() + ":" + arg + "]"); - } else if (isArray(parameterType)) { + } else if (ReflectUtil.isArray(parameterType)) { for (int i = 0; i < Array.getLength(arg); i++) { Object o = Array.get(arg, i); if (!access(o, annotation, layer)) { @@ -125,7 +123,7 @@ public class DePermissionAnnotationHandler { } } - } else if (isCollection(parameterType)) { + } else if (ReflectUtil.isCollection(parameterType)) { Object[] array = ((Collection) arg).toArray(); for (int i = 0; i < array.length; i++) { Object o = array[i]; @@ -133,7 +131,7 @@ public class DePermissionAnnotationHandler { return false; } } - } else if (isMap(parameterType)) { + } else if (ReflectUtil.isMap(parameterType)) { Map argMap = (Map) arg; String[] values = value.split("."); Object o = argMap.get(values[layer]); @@ -143,59 +141,13 @@ public class DePermissionAnnotationHandler { String[] values = value.split("\\."); String fieldName = values[layer]; - Object fieldValue = getFieldValue(arg, fieldName); + Object fieldValue = ReflectUtil.getFieldValue(arg, fieldName); return access(fieldValue, annotation, ++layer); } return true; } - private Object getFieldValue(Object o, String fieldName) throws Exception { - Class aClass = o.getClass(); - while (null != aClass.getSuperclass()) { - Field[] declaredFields = aClass.getDeclaredFields(); - for (int i = 0; i < declaredFields.length; i++) { - Field field = declaredFields[i]; - String name = field.getName(); - if (StringUtils.equals(name, fieldName)) { - field.setAccessible(true); - return field.get(o); - } - } - aClass = aClass.getSuperclass(); - } - throw new NoSuchFieldException(fieldName); - } - private final static String[] wrapClasies = { - "java.lang.Boolean", - "java.lang.Character", - "java.lang.Integer", - "java.lang.Byte", - "java.lang.Short", - "java.lang.Long", - "java.lang.Float", - "java.lang.Double", - }; - - private Boolean isString(Class clz) { - return StringUtils.equals("java.lang.String", clz.getName()); - } - - private Boolean isArray(Class clz) { - return clz.isArray(); - } - - private Boolean isCollection(Class clz) { - return Collection.class.isAssignableFrom(clz); - } - - private Boolean isMap(Class clz) { - return Map.class.isAssignableFrom(clz); - } - - private Boolean isWrapClass(Class clz) { - return Arrays.stream(wrapClasies).anyMatch(item -> StringUtils.equals(item, clz.getName())); - } } diff --git a/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java b/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java index 4b03805972..3e035deb8a 100644 --- a/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java +++ b/backend/src/main/java/io/dataease/auth/service/ExtAuthService.java @@ -28,5 +28,7 @@ public interface ExtAuthService { void clearDeptResource(Long deptId); void clearRoleResource(Long roleId); + List parentResource(String resourceId, String type); + } diff --git a/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java index addbd6e6de..393d3f1f42 100644 --- a/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java +++ b/backend/src/main/java/io/dataease/auth/service/impl/ExtAuthServiceImpl.java @@ -8,6 +8,7 @@ import io.dataease.commons.constants.AuthConstants; import io.dataease.commons.model.AuthURD; import io.dataease.commons.utils.LogUtil; import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; @@ -147,6 +148,20 @@ public class ExtAuthServiceImpl implements ExtAuthService { LogUtil.info("all permission resource of role {} is cleanning...", roleId); } - - + @Override + public List parentResource(String resourceId, String type) { + String s = extAuthMapper.parentResource(resourceId, type); + if (StringUtils.isNotBlank(s)) { + String[] split = s.split(","); + List results = new ArrayList<>(); + for (int i = 0; i < split.length; i++) { + String s1 = split[i]; + if (StringUtils.isNotBlank(s1)) { + results.add(s1); + } + } + return CollectionUtils.isEmpty(results) ? null : results; + } + return null; + } } diff --git a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java index 3466cadd6e..0711f6a025 100644 --- a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java +++ b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java @@ -95,6 +95,7 @@ public class ShiroServiceImpl implements ShiroService { filterChainDefinitionMap.put("/api/link/resourceDetail/**", "link"); filterChainDefinitionMap.put("/api/link/viewDetail/**", "link"); + filterChainDefinitionMap.put("/panel/group/exportDetails", ANON); filterChainDefinitionMap.put("/dataset/field/linkMultFieldValues", "link"); filterChainDefinitionMap.put("/**", "authc"); diff --git a/backend/src/main/java/io/dataease/auth/util/ReflectUtil.java b/backend/src/main/java/io/dataease/auth/util/ReflectUtil.java new file mode 100644 index 0000000000..f5905d4132 --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/util/ReflectUtil.java @@ -0,0 +1,59 @@ +package io.dataease.auth.util; + +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; + +public class ReflectUtil { + + public static Object getFieldValue(Object o, String fieldName) throws Exception { + Class aClass = o.getClass(); + while (null != aClass.getSuperclass()) { + Field[] declaredFields = aClass.getDeclaredFields(); + for (int i = 0; i < declaredFields.length; i++) { + Field field = declaredFields[i]; + String name = field.getName(); + if (StringUtils.equals(name, fieldName)) { + field.setAccessible(true); + return field.get(o); + } + } + aClass = aClass.getSuperclass(); + } + throw new NoSuchFieldException(fieldName); + } + + private final static String[] wrapClasies = { + "java.lang.Boolean", + "java.lang.Character", + "java.lang.Integer", + "java.lang.Byte", + "java.lang.Short", + "java.lang.Long", + "java.lang.Float", + "java.lang.Double", + }; + + public static Boolean isString(Class clz) { + return StringUtils.equals("java.lang.String", clz.getName()); + } + + public static Boolean isArray(Class clz) { + return clz.isArray(); + } + + public static Boolean isCollection(Class clz) { + return Collection.class.isAssignableFrom(clz); + } + + public static Boolean isMap(Class clz) { + return Map.class.isAssignableFrom(clz); + } + + public static Boolean isWrapClass(Class clz) { + return Arrays.stream(wrapClasies).anyMatch(item -> StringUtils.equals(item, clz.getName())); + } +} diff --git a/backend/src/main/java/io/dataease/commons/constants/StaticResourceConstants.java b/backend/src/main/java/io/dataease/commons/constants/StaticResourceConstants.java new file mode 100644 index 0000000000..86750b99df --- /dev/null +++ b/backend/src/main/java/io/dataease/commons/constants/StaticResourceConstants.java @@ -0,0 +1,32 @@ +package io.dataease.commons.constants; + +import java.io.File; + +import static io.dataease.commons.utils.StaticResourceUtils.ensureSuffix; + +/** + * Author: wangjiahao + * Date: 2022/4/28 + * Description: + */ +public class StaticResourceConstants { + + public static final String FILE_PROTOCOL = "file://"; + + public static final String FILE_SEPARATOR = File.separator; + + public static final String USER_HOME = "/opt/dataease/data"; + + public static String WORK_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "static-resource" + FILE_SEPARATOR; + + /** + * Upload prefix. + */ + public final static String UPLOAD_URL_PREFIX = "static-resource"; + + /** + * url separator. + */ + public static final String URL_SEPARATOR = "/"; + +} diff --git a/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java b/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java index 62adf6c795..f236ea38e8 100644 --- a/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java +++ b/backend/src/main/java/io/dataease/commons/utils/AuthUtils.java @@ -9,6 +9,10 @@ import io.dataease.commons.constants.DePermissionType; import io.dataease.commons.constants.ResourceAuthLevel; import io.dataease.commons.model.AuthURD; +import io.dataease.plugins.config.SpringContextUtil; +import io.dataease.plugins.xpack.auth.dto.request.XpackBaseTreeRequest; +import io.dataease.plugins.xpack.auth.dto.response.XpackVAuthModelDTO; +import io.dataease.plugins.xpack.auth.service.AuthXpackService; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; @@ -67,6 +71,20 @@ public class AuthUtils { return userIds; } + public static List parentResources(String resourceId, String type) { + return extAuthService.parentResource(resourceId, type); + } + + public static List getAuthModels(String id, String type, Long userId, Boolean isAdmin) { + AuthXpackService sysAuthService = SpringContextUtil.getBean(AuthXpackService.class); + List vAuthModelDTOS = sysAuthService + .searchAuthModelTree(new XpackBaseTreeRequest(id, type, "children"), userId, isAdmin); + List authSources = Optional.ofNullable(vAuthModelDTOS).orElse(new ArrayList<>()).stream() + .map(XpackVAuthModelDTO::getId) + .collect(Collectors.toList()); + return authSources; + } + // 获取资源对那些人/角色/组织 有权限 public static AuthURD authURDR(String resourceId) { return extAuthService.resourceTarget(resourceId); diff --git a/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java b/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java index cd644a98a0..bce0fb98b3 100644 --- a/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java +++ b/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java @@ -1,8 +1,14 @@ package io.dataease.commons.utils; +import static io.dataease.commons.constants.StaticResourceConstants.*; import org.apache.commons.lang3.StringUtils; import org.springframework.lang.NonNull; import org.springframework.util.Assert; +import sun.misc.BASE64Encoder; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; /** * Author: wangjiahao @@ -10,9 +16,8 @@ import org.springframework.util.Assert; * Description: */ public class StaticResourceUtils { - public static final String URL_SEPARATOR = "/"; - private static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)"; + private final static String FILE_BASE_PATH = USER_HOME+ FILE_SEPARATOR+UPLOAD_URL_PREFIX; public static String ensureBoth(@NonNull String string, @NonNull String bothfix) { return ensureBoth(string, bothfix, bothfix); @@ -51,4 +56,45 @@ public class StaticResourceUtils { return StringUtils.removeEnd(string, suffix) + suffix; } + + /** + * + * @param imgFile local storage path + * @return + */ + public static String getImgFileToBase64(String imgFile) { + //Convert the picture file into byte array and encode it with Base64 + InputStream inputStream = null; + byte[] buffer = null; + //Read picture byte array + try { + inputStream = new FileInputStream(FILE_BASE_PATH+FILE_SEPARATOR+imgFile); + int count = 0; + while (count == 0) { + count = inputStream.available(); + } + buffer = new byte[count]; + inputStream.read(buffer); + } catch (IOException e) { + LogUtil.error(e); + }catch (Exception e){ + LogUtil.error(e); + }finally { + if (inputStream != null) { + try { + // Close InputStream + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + // Encode byte array as Base64 + if(buffer!=null){ + return new BASE64Encoder().encode(buffer); + }else{ + return null; + } + } + } diff --git a/backend/src/main/java/io/dataease/config/DeMvcConfig.java b/backend/src/main/java/io/dataease/config/DeMvcConfig.java index 04f73c5217..5c56212de1 100644 --- a/backend/src/main/java/io/dataease/config/DeMvcConfig.java +++ b/backend/src/main/java/io/dataease/config/DeMvcConfig.java @@ -1,13 +1,9 @@ package io.dataease.config; +import static io.dataease.commons.constants.StaticResourceConstants.*; import org.springframework.context.annotation.Configuration; -import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import java.io.File; -import java.util.concurrent.TimeUnit; - import static io.dataease.commons.utils.StaticResourceUtils.ensureBoth; import static io.dataease.commons.utils.StaticResourceUtils.ensureSuffix; @@ -18,24 +14,6 @@ import static io.dataease.commons.utils.StaticResourceUtils.ensureSuffix; */ @Configuration public class DeMvcConfig implements WebMvcConfigurer { - private static final String FILE_PROTOCOL = "file://"; - public static final String FILE_SEPARATOR = File.separator; - public static final String USER_HOME = "/opt/dataease/data"; - - private static String WORK_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "static-resource" + FILE_SEPARATOR; - - - /** - * Upload prefix. - */ - private final static String UPLOAD_URL_PREFIX = "static-resource"; - - - /** - * url separator. - */ - public static final String URL_SEPARATOR = "/"; - /** * Configuring static resource path * diff --git a/backend/src/main/java/io/dataease/controller/request/panel/PanelGroupRequest.java b/backend/src/main/java/io/dataease/controller/request/panel/PanelGroupRequest.java index aa5dbf9003..2e5e9d0955 100644 --- a/backend/src/main/java/io/dataease/controller/request/panel/PanelGroupRequest.java +++ b/backend/src/main/java/io/dataease/controller/request/panel/PanelGroupRequest.java @@ -23,7 +23,8 @@ public class PanelGroupRequest extends PanelGroupDTO { private String dynamicData; @ApiModelProperty("内部模板ID") private String templateId; - + @ApiModelProperty("静态文件") + private String staticResource; public PanelGroupRequest() { } diff --git a/backend/src/main/java/io/dataease/controller/request/resource/StaticResourceRequest.java b/backend/src/main/java/io/dataease/controller/request/resource/StaticResourceRequest.java new file mode 100644 index 0000000000..13b6ca831d --- /dev/null +++ b/backend/src/main/java/io/dataease/controller/request/resource/StaticResourceRequest.java @@ -0,0 +1,17 @@ +package io.dataease.controller.request.resource; + +import lombok.Data; + +import java.util.List; + +/** + * Author: wangjiahao + * Date: 2022/4/28 + * Description: + */ +@Data +public class StaticResourceRequest { + + private List resourcePathList; + +} diff --git a/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java b/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java index 8f4297289f..277552ecc3 100644 --- a/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java +++ b/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java @@ -1,5 +1,6 @@ package io.dataease.controller.staticResource; +import io.dataease.controller.request.resource.StaticResourceRequest; import io.dataease.service.staticResource.StaticResourceService; import io.swagger.annotations.ApiOperation; import org.pentaho.ui.xul.stereotype.Controller; @@ -7,6 +8,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import java.util.Map; /** * Author: wangjiahao @@ -21,8 +23,14 @@ public class StaticResourceController { StaticResourceService staticResourceService; @PostMapping("upload/{fileId}") - @ApiOperation("Uploads static file") + @ApiOperation("上传静态文件") public void upload(@PathVariable("fileId") String fileId, @RequestPart("file") MultipartFile file) { staticResourceService.upload(fileId,file); } + + @PostMapping("findResourceAsBase64") + @ApiOperation("查找静态文件并转为Base64") + public Map findResourceAsBase64(@RequestBody StaticResourceRequest resourceRequest){ + return staticResourceService.findResourceAsBase64(resourceRequest); + } } diff --git a/backend/src/main/java/io/dataease/ext/ExtAuthMapper.java b/backend/src/main/java/io/dataease/ext/ExtAuthMapper.java index edaba83058..fe4fc5ca88 100644 --- a/backend/src/main/java/io/dataease/ext/ExtAuthMapper.java +++ b/backend/src/main/java/io/dataease/ext/ExtAuthMapper.java @@ -27,4 +27,6 @@ public interface ExtAuthMapper { List dataSourceIdByDept(String deptId); List dataSetIdByDept(String deptId); List panelIdByDept(String deptId); + + String parentResource(@Param("resourceId") String resourceId, @Param("type") String type); } diff --git a/backend/src/main/java/io/dataease/ext/ExtAuthMapper.xml b/backend/src/main/java/io/dataease/ext/ExtAuthMapper.xml index 1307121339..fded977e66 100644 --- a/backend/src/main/java/io/dataease/ext/ExtAuthMapper.xml +++ b/backend/src/main/java/io/dataease/ext/ExtAuthMapper.xml @@ -152,6 +152,10 @@ GROUP BY a.id + + diff --git a/backend/src/main/java/io/dataease/plugins/server/XAuthServer.java b/backend/src/main/java/io/dataease/plugins/server/XAuthServer.java index 7538a59e38..c33b437605 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XAuthServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XAuthServer.java @@ -76,7 +76,7 @@ public class XAuthServer { String authCacheKey = getAuthCacheKey(request); if (StringUtils.isNotBlank(authCacheKey)) { if (StringUtils.equals("dept", request.getAuthTargetType())) { - List authTargets = getAuthModels(request.getAuthTarget(), request.getAuthTargetType(), + List authTargets = AuthUtils.getAuthModels(request.getAuthTarget(), request.getAuthTargetType(), user.getUserId(), user.getIsAdmin()); if (CollectionUtils.isNotEmpty(authTargets)) { authTargets.forEach(deptId -> { @@ -91,16 +91,6 @@ public class XAuthServer { }); } - private List getAuthModels(String id, String type, Long userId, Boolean isAdmin) { - AuthXpackService sysAuthService = SpringContextUtil.getBean(AuthXpackService.class); - List vAuthModelDTOS = sysAuthService - .searchAuthModelTree(new XpackBaseTreeRequest(id, type, "children"), userId, isAdmin); - List authSources = Optional.ofNullable(vAuthModelDTOS).orElse(new ArrayList<>()).stream() - .map(XpackVAuthModelDTO::getId) - .collect(Collectors.toList()); - return authSources; - } - private String getAuthCacheKey(XpackSysAuthRequest request) { if (CollectionUtils.isEmpty(cacheTypes)) { cacheTypes.add("link"); diff --git a/backend/src/main/java/io/dataease/service/dataset/DataSetGroupService.java b/backend/src/main/java/io/dataease/service/dataset/DataSetGroupService.java index ef5ac2ec5a..6e8202dc57 100644 --- a/backend/src/main/java/io/dataease/service/dataset/DataSetGroupService.java +++ b/backend/src/main/java/io/dataease/service/dataset/DataSetGroupService.java @@ -44,7 +44,7 @@ public class DataSetGroupService { @Resource private SysAuthService sysAuthService; - @DeCleaner(DePermissionType.DATASET) + @DeCleaner(value = DePermissionType.DATASET, key = "pid") public DataSetGroupDTO save(DatasetGroup datasetGroup) throws Exception { checkName(datasetGroup); if (StringUtils.isEmpty(datasetGroup.getId())) { diff --git a/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java b/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java index 83b7ce7303..71caa0df56 100644 --- a/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java +++ b/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java @@ -115,7 +115,7 @@ public class DataSetTableService { private static Logger logger = LoggerFactory.getLogger(ClassloaderResponsity.class); - @DeCleaner(value = DePermissionType.DATASET) + @DeCleaner(value = DePermissionType.DATASET, key = "sceneId") public void batchInsert(List datasetTable) throws Exception { for (DataSetTableRequest table : datasetTable) { save(table); @@ -143,7 +143,7 @@ public class DataSetTableService { } } - @DeCleaner(value = DePermissionType.DATASET) + @DeCleaner(value = DePermissionType.DATASET, key = "sceneId") public void saveExcel(DataSetTableRequest datasetTable) throws Exception { List datasetIdList = new ArrayList<>(); @@ -253,7 +253,7 @@ public class DataSetTableService { } } - @DeCleaner(value = DePermissionType.DATASET) + @DeCleaner(value = DePermissionType.DATASET, key = "sceneId") public DatasetTable save(DataSetTableRequest datasetTable) throws Exception { checkName(datasetTable); if (StringUtils.equalsIgnoreCase(datasetTable.getType(), "sql")) { @@ -1847,7 +1847,6 @@ public class DataSetTableService { return dataSetDetail; } - @DeCleaner(value = DePermissionType.DATASET) public ExcelFileData excelSaveAndParse(MultipartFile file, String tableId, Integer editType) throws Exception { String filename = file.getOriginalFilename(); // parse file diff --git a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java index 8022c7749f..9ddc520f9c 100644 --- a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java +++ b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java @@ -8,7 +8,6 @@ import io.dataease.commons.utils.LogUtil; import io.dataease.commons.utils.TreeUtils; import io.dataease.controller.request.authModel.VAuthModelRequest; import io.dataease.controller.request.dataset.DataSetTableRequest; -import io.dataease.controller.request.panel.PanelGroupQueryRequest; import io.dataease.controller.request.panel.PanelGroupRequest; import io.dataease.controller.request.panel.PanelViewDetailsRequest; import io.dataease.dto.PanelGroupExtendDataDTO; @@ -17,7 +16,6 @@ import io.dataease.dto.chart.ChartViewDTO; import io.dataease.dto.dataset.DataSetTableDTO; import io.dataease.dto.panel.PanelGroupDTO; import io.dataease.dto.panel.po.PanelViewInsertDTO; -import io.dataease.excel.utils.EasyExcelExporter; import io.dataease.exception.DataEaseException; import io.dataease.ext.*; import io.dataease.i18n.Translator; @@ -26,6 +24,7 @@ import io.dataease.plugins.common.base.domain.*; import io.dataease.plugins.common.base.mapper.*; import io.dataease.service.chart.ChartViewService; import io.dataease.service.dataset.DataSetTableService; +import io.dataease.service.staticResource.StaticResourceService; import io.dataease.service.sys.SysAuthService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -39,13 +38,9 @@ import org.springframework.util.Assert; import org.springframework.util.Base64Utils; import javax.annotation.Resource; -import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.net.URL; import java.util.*; import java.util.stream.Collectors; @@ -100,6 +95,8 @@ public class PanelGroupService { private PanelTemplateMapper templateMapper; @Resource private ExtPanelGroupExtendDataMapper extPanelGroupExtendDataMapper; + @Resource + private StaticResourceService staticResourceService; public List tree(PanelGroupRequest panelGroupRequest) { String userId = String.valueOf(AuthUtils.getUser().getUserId()); @@ -115,9 +112,8 @@ public class PanelGroupService { return TreeUtils.mergeTree(panelGroupDTOList, "default_panel"); } - @DeCleaner(DePermissionType.PANEL) + @DeCleaner(value = DePermissionType.PANEL, key = "pid") public PanelGroup saveOrUpdate(PanelGroupRequest request) { - String userName = AuthUtils.getUser().getUsername(); String panelId = request.getId(); if (StringUtils.isNotEmpty(panelId)) { panelViewService.syncPanelViews(request); @@ -223,12 +219,12 @@ public class PanelGroupService { /** - * @Description 查询仪表板信息 * @param panelId * @return + * @Description 查询仪表板信息 */ public PanelGroupDTO findOne(String panelId) { - Assert.notNull(panelId,"Method findOne panelId can not be null"); + Assert.notNull(panelId, "Method findOne panelId can not be null"); PanelGroupDTO panelGroup = extPanelGroupMapper.findOneWithPrivileges(panelId, String.valueOf(AuthUtils.getUser().getUserId())); // 默认仪表板取源仪表板样式 if (panelGroup != null && StringUtils.isNotEmpty(panelGroup.getSource())) { @@ -331,8 +327,9 @@ public class PanelGroupService { String templateStyle = null; String templateData = null; String dynamicData = null; + String staticResource = null; if (PanelConstants.NEW_PANEL_FROM.NEW.equals(newFrom)) { - + // do nothing } else { //内部模板新建 if (PanelConstants.NEW_PANEL_FROM.NEW_INNER_TEMPLATE.equals(newFrom)) { @@ -344,6 +341,7 @@ public class PanelGroupService { templateStyle = request.getPanelStyle(); templateData = request.getPanelData(); dynamicData = request.getDynamicData(); + staticResource = request.getStaticResource(); } Map dynamicDataMap = JSON.parseObject(dynamicData, Map.class); List panelViews = new ArrayList<>(); @@ -370,6 +368,8 @@ public class PanelGroupService { } request.setPanelData(templateData); request.setPanelStyle(templateStyle); + //Store static resource into the server + staticResourceService.saveFilesToServe(staticResource); } request.setId(newPanelId); request.setCreateTime(System.currentTimeMillis()); @@ -467,7 +467,7 @@ public class PanelGroupService { try { String snapshot = request.getSnapshot(); List details = request.getDetails(); - details.add(0,request.getHeader()); + details.add(0, request.getHeader()); HSSFWorkbook wb = new HSSFWorkbook(); //明细sheet HSSFSheet detailsSheet = wb.createSheet("数据"); @@ -494,28 +494,28 @@ public class PanelGroupService { for (int j = 0; j < rowData.length; j++) { HSSFCell cell = row.createCell(j); cell.setCellValue(rowData[j]); - if(i==0){// 头部 + if (i == 0) {// 头部 cell.setCellStyle(cellStyle); //设置列的宽度 - detailsSheet.setColumnWidth(j, 255*20); + detailsSheet.setColumnWidth(j, 255 * 20); } } } } } - if(StringUtils.isNotEmpty(snapshot)){ + if (StringUtils.isNotEmpty(snapshot)) { //截图sheet 1px ≈ 2.33dx ≈ 0.48 dy 8*24 个单元格 HSSFSheet snapshotSheet = wb.createSheet("图表"); - short reDefaultRowHeight = (short)Math.round(request.getSnapshotHeight()*3.5/8); - int reDefaultColumnWidth = (int)Math.round(request.getSnapshotWidth()*0.25/24); + short reDefaultRowHeight = (short) Math.round(request.getSnapshotHeight() * 3.5 / 8); + int reDefaultColumnWidth = (int) Math.round(request.getSnapshotWidth() * 0.25 / 24); snapshotSheet.setDefaultColumnWidth(reDefaultColumnWidth); snapshotSheet.setDefaultRowHeight(reDefaultRowHeight); //画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)i HSSFPatriarch patriarch = snapshotSheet.createDrawingPatriarch(); - HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, reDefaultColumnWidth, reDefaultColumnWidth,(short) 0, 0, (short)8, 24); + HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, reDefaultColumnWidth, reDefaultColumnWidth, (short) 0, 0, (short) 8, 24); anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_DO_RESIZE); - patriarch.createPicture(anchor, wb.addPicture(Base64Utils.decodeFromString(snapshot.replace(DATA_URL_TITLE,"")), HSSFWorkbook.PICTURE_TYPE_JPEG)); + patriarch.createPicture(anchor, wb.addPicture(Base64Utils.decodeFromString(snapshot.replace(DATA_URL_TITLE, "")), HSSFWorkbook.PICTURE_TYPE_JPEG)); } response.setContentType("application/vnd.ms-excel"); //文件名称 diff --git a/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java b/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java index 61cc19bacd..175f5c7572 100644 --- a/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java +++ b/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java @@ -1,21 +1,27 @@ package io.dataease.service.staticResource; +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSON; import io.dataease.commons.utils.FileUtils; import io.dataease.commons.utils.LogUtil; +import io.dataease.commons.utils.StaticResourceUtils; +import io.dataease.controller.request.resource.StaticResourceRequest; import io.dataease.exception.DataEaseException; -import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.util.Base64Utils; +import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; import java.io.IOException; -import java.net.URLEncoder; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; /** * Author: wangjiahao @@ -45,4 +51,38 @@ public class StaticResourceService { DataEaseException.throwException(e); } } + + public void saveFilesToServe(String staticResource){ + if(StringUtils.isNotEmpty(staticResource)){ + Map resource = JSON.parseObject(staticResource,Map.class); + for(Map.Entry entry:resource.entrySet()){ + String path = entry.getKey(); + Path uploadPath = Paths.get(staticDir.toString(), path.substring(path.lastIndexOf("/")+1,path.length())); + try{ + if (uploadPath.toFile().exists()) { + LogUtil.info("file exists"); + }else{ + String content = entry.getValue(); + if(StringUtils.isNotEmpty(content)){ + Files.createFile(uploadPath); + FileCopyUtils.copy(new BASE64Decoder().decodeBuffer(content),Files.newOutputStream(uploadPath)); + } + } + }catch (Exception e){ + LogUtil.error("template static resource save error"+e.getMessage()); + } + } + } + } + + public Map findResourceAsBase64(StaticResourceRequest resourceRequest){ + Map result = new HashMap<>(); + if(CollectionUtil.isNotEmpty(resourceRequest.getResourcePathList())){ + for(String path :resourceRequest.getResourcePathList()){ + String value = StaticResourceUtils.getImgFileToBase64(path.substring(path.lastIndexOf("/")+1,path.length())); + result.put(path,value); + } + } + return result; + } } diff --git a/frontend/src/api/staticResource/staticResource.js b/frontend/src/api/staticResource/staticResource.js index de424b0680..40ee10055e 100644 --- a/frontend/src/api/staticResource/staticResource.js +++ b/frontend/src/api/staticResource/staticResource.js @@ -24,3 +24,12 @@ export function uploadFileResult(file, callback) { }) } +export function findResourceAsBase64(params) { + return request({ + url: '/static/resource/findResourceAsBase64', + method: 'post', + data: params, + loading: false + }) +} + diff --git a/frontend/src/components/DeDrag/index.vue b/frontend/src/components/DeDrag/index.vue index 5ffc167358..92d86c0959 100644 --- a/frontend/src/components/DeDrag/index.vue +++ b/frontend/src/components/DeDrag/index.vue @@ -542,9 +542,9 @@ export default { style['padding'] = (this.element.commonBackground.innerPadding || 0) + 'px' style['border-radius'] = (this.element.commonBackground.borderRadius || 0) + 'px' if (this.element.commonBackground.enable) { - if (this.element.commonBackground.backgroundType === 'innerImage') { + if (this.element.commonBackground.backgroundType === 'innerImage' && this.element.commonBackground.innerImage) { style['background'] = `url(${this.element.commonBackground.innerImage}) no-repeat` - } else if (this.element.commonBackground.backgroundType === 'outerImage') { + } else if (this.element.commonBackground.backgroundType === 'outerImage' && this.element.commonBackground.outerImage) { style['background'] = `url(${this.element.commonBackground.outerImage}) no-repeat` } else if (this.element.commonBackground.backgroundType === 'color') { style['background-color'] = hexColorToRGBA(this.element.commonBackground.color, this.element.commonBackground.alpha) diff --git a/frontend/src/components/canvas/components/Editor/ComponentWrapper.vue b/frontend/src/components/canvas/components/Editor/ComponentWrapper.vue index 166baa82ac..a192165007 100644 --- a/frontend/src/components/canvas/components/Editor/ComponentWrapper.vue +++ b/frontend/src/components/canvas/components/Editor/ComponentWrapper.vue @@ -28,6 +28,7 @@ :style="getComponentStyleDefault(config.style)" :prop-value="config.propValue" :is-edit="false" + :in-screen="inScreen" :active="componentActiveFlag" :element="config" :search-count="searchCount" @@ -104,13 +105,13 @@ export default { style['padding'] = (this.config.commonBackground.innerPadding || 0) + 'px' style['border-radius'] = (this.config.commonBackground.borderRadius || 0) + 'px' if (this.config.commonBackground.enable) { - if (this.config.commonBackground.backgroundType === 'innerImage') { + if (this.config.commonBackground.backgroundType === 'innerImage' && this.config.commonBackground.innerImage) { let innerImage = this.config.commonBackground.innerImage if (this.screenShot) { innerImage = innerImage.replace('svg', 'png') } style['background'] = `url(${innerImage}) no-repeat` - } else if (this.config.commonBackground.backgroundType === 'outerImage') { + } else if (this.config.commonBackground.backgroundType === 'outerImage' && this.config.commonBackground.outerImage) { style['background'] = `url(${this.config.commonBackground.outerImage}) no-repeat` } else if (this.config.commonBackground.backgroundType === 'color') { style['background-color'] = hexColorToRGBA(this.config.commonBackground.color, this.config.commonBackground.alpha) diff --git a/frontend/src/components/canvas/custom-component/DeStreamMedia.vue b/frontend/src/components/canvas/custom-component/DeStreamMedia.vue index f541f7b468..d6242c99f7 100644 --- a/frontend/src/components/canvas/custom-component/DeStreamMedia.vue +++ b/frontend/src/components/canvas/custom-component/DeStreamMedia.vue @@ -1,9 +1,9 @@