diff --git a/README.md b/README.md index 7340f116f4..23b8992d1b 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ curl -sSL https://dataease.oss-cn-hangzhou.aliyuncs.com/quick_start.sh | sh **加入微信交流群** - + ## DataEase 的技术栈 @@ -107,7 +107,7 @@ curl -sSL https://dataease.oss-cn-hangzhou.aliyuncs.com/quick_start.sh | sh ## License -Copyright (c) 2014-2023 飞致云 FIT2CLOUD, All rights reserved. +Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved. Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/backend/pom.xml b/backend/pom.xml index 26483f8851..a4dfbe8c94 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -185,7 +185,7 @@ org.testng testng - 6.8 + 7.7.0 test diff --git a/backend/src/main/java/io/dataease/auth/annotation/SqlInjectValidator.java b/backend/src/main/java/io/dataease/auth/annotation/SqlInjectValidator.java new file mode 100644 index 0000000000..176183d353 --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/annotation/SqlInjectValidator.java @@ -0,0 +1,17 @@ +package io.dataease.auth.annotation; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Target(ElementType.METHOD) +@Retention(RUNTIME) +public @interface SqlInjectValidator { + + String[] value() default {}; +} diff --git a/backend/src/main/java/io/dataease/auth/aop/SqlInjectAop.java b/backend/src/main/java/io/dataease/auth/aop/SqlInjectAop.java new file mode 100644 index 0000000000..add12ab202 --- /dev/null +++ b/backend/src/main/java/io/dataease/auth/aop/SqlInjectAop.java @@ -0,0 +1,68 @@ +package io.dataease.auth.aop; + +import cn.hutool.core.util.ArrayUtil; +import io.dataease.auth.annotation.SqlInjectValidator; +import io.dataease.commons.exception.DEException; +import io.dataease.controller.sys.base.BaseGridRequest; +import org.apache.commons.collections4.CollectionUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Component +@Aspect +public class SqlInjectAop { + + @Around(value = "@annotation(io.dataease.auth.annotation.SqlInjectValidator)") + public Object around(ProceedingJoinPoint point) { + + try { + Signature signature = point.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + Object[] args = point.getArgs(); + if (args == null || args.length == 0) { + return point.proceed(); + } + BaseGridRequest request = null; + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof BaseGridRequest) { + request = (BaseGridRequest) args[i]; + break; + } + } + if (request == null) return point.proceed(args); + SqlInjectValidator annotation = AnnotationUtils.findAnnotation(method, SqlInjectValidator.class); + String[] value = annotation.value(); + boolean illegal = isIllegal(value, request.getOrders()); + if (illegal) { + DEException.throwException("Illegal sort exp"); + } + return point.proceed(args); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + private boolean isIllegal(String[] value, List orderList) { + if (CollectionUtils.isEmpty(orderList) || ArrayUtil.isEmpty(value)) return false; + Set wordList = Arrays.stream(value).collect(Collectors.toSet()); + wordList.add("asc"); + wordList.add("desc"); + + return orderList.stream().anyMatch(exp -> + Arrays.stream(exp.toLowerCase().split(",")).anyMatch(word -> + Arrays.stream(word.split(" ")).anyMatch(item -> + !wordList.contains(item)))); + } +} diff --git a/backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java b/backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java index 23236e1f44..672f89d46a 100644 --- a/backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java +++ b/backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java @@ -225,7 +225,7 @@ public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrappe if (Arrays.stream(whiteLists.split(",")).anyMatch(item -> url.indexOf(item) != -1)) return false; } Pattern pattern= Pattern.compile("(.*\\=.*\\-\\-.*)|(.*(\\+).*)|(.*\\w+(%|\\$|#|&)\\w+.*)|(.*\\|\\|.*)|(.*\\s+(and|or)\\s+.*)" + - "|(.*\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|sleep|extractvalue|updatexml|substring|database|concat|rand)\\b.*)"); + "|(.*\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|sleep|extractvalue|updatexml|substring|database|concat|rand|gtid_subset)\\b.*)"); Matcher matcher=pattern.matcher(orders.toLowerCase()); return matcher.find(); } diff --git a/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java b/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java index 3fd116cee9..de76fb86ac 100644 --- a/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java +++ b/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java @@ -170,7 +170,7 @@ public class DataSetTableController { @DePermission(type = DePermissionType.DATASOURCE, value = "dataSourceId", level = ResourceAuthLevel.DATASOURCE_LEVEL_USE) }, logical = Logical.AND) public ResultHolder getSQLPreview(@RequestBody DataSetTableRequest dataSetTableRequest) throws Exception { - return dataSetTableService.getSQLPreview(dataSetTableRequest); + return dataSetTableService.getSQLPreview(dataSetTableRequest, true); } @ApiOperation("根据sql查询预览数据") diff --git a/backend/src/main/java/io/dataease/controller/panel/api/ShareApi.java b/backend/src/main/java/io/dataease/controller/panel/api/ShareApi.java index 39e7f8a441..f1c81f851c 100644 --- a/backend/src/main/java/io/dataease/controller/panel/api/ShareApi.java +++ b/backend/src/main/java/io/dataease/controller/panel/api/ShareApi.java @@ -2,6 +2,7 @@ package io.dataease.controller.panel.api; import com.github.xiaoymin.knife4j.annotations.ApiSupport; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.plugins.common.base.domain.PanelShare; import io.dataease.commons.constants.DePermissionType; import io.dataease.controller.request.panel.PanelShareFineDto; @@ -30,6 +31,7 @@ public interface ShareApi { @ApiOperation("查询分享给我") @PostMapping("/treeList") + @SqlInjectValidator(value = {"s.create_time"}) List treeList(BaseGridRequest request); @ApiOperation("查询我分享的") diff --git a/backend/src/main/java/io/dataease/controller/panel/api/StoreApi.java b/backend/src/main/java/io/dataease/controller/panel/api/StoreApi.java index f0e8efd983..5d63d3b88c 100644 --- a/backend/src/main/java/io/dataease/controller/panel/api/StoreApi.java +++ b/backend/src/main/java/io/dataease/controller/panel/api/StoreApi.java @@ -2,6 +2,7 @@ package io.dataease.controller.panel.api; import com.github.xiaoymin.knife4j.annotations.ApiSupport; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.commons.constants.DePermissionType; import io.dataease.controller.sys.base.BaseGridRequest; import io.dataease.dto.panel.PanelStoreDto; @@ -31,6 +32,7 @@ public interface StoreApi { @ApiOperation("查询收藏") @PostMapping("/list") + @SqlInjectValidator(value = {"s.create_time"}) List list(@RequestBody BaseGridRequest request); diff --git a/backend/src/main/java/io/dataease/controller/request/panel/PanelAppTemplateApplyRequest.java b/backend/src/main/java/io/dataease/controller/request/panel/PanelAppTemplateApplyRequest.java index c627cde1af..3399e41112 100644 --- a/backend/src/main/java/io/dataease/controller/request/panel/PanelAppTemplateApplyRequest.java +++ b/backend/src/main/java/io/dataease/controller/request/panel/PanelAppTemplateApplyRequest.java @@ -33,5 +33,13 @@ public class PanelAppTemplateApplyRequest { private String datasourceHistoryId; + private String linkJumps; + + private String linkJumpInfos; + + private String linkages; + + private String linkageFields; + private List datasourceList; } 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 277552ecc3..1d2e5368bf 100644 --- a/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java +++ b/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java @@ -16,7 +16,7 @@ import java.util.Map; * Description: */ @RestController -@RequestMapping("/static/resource") +@RequestMapping("/staticResource") public class StaticResourceController { @Resource diff --git a/backend/src/main/java/io/dataease/controller/sys/MsgController.java b/backend/src/main/java/io/dataease/controller/sys/MsgController.java index 2fb50323a3..9870df1a87 100644 --- a/backend/src/main/java/io/dataease/controller/sys/MsgController.java +++ b/backend/src/main/java/io/dataease/controller/sys/MsgController.java @@ -3,6 +3,7 @@ package io.dataease.controller.sys; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.service.AuthUserService; import io.dataease.plugins.common.base.domain.SysMsgChannel; import io.dataease.plugins.common.base.domain.SysMsgSetting; @@ -47,6 +48,7 @@ public class MsgController { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "msgRequest", value = "查询条件", required = true) }) + @SqlInjectValidator(value = {"create_time", "type_id"}) public Pager> messages(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody MsgRequest msgRequest) { Long userId = AuthUtils.getUser().getUserId(); List typeIds = null; diff --git a/backend/src/main/java/io/dataease/controller/sys/SysDeptController.java b/backend/src/main/java/io/dataease/controller/sys/SysDeptController.java index 84fc00ef34..ff73c6d280 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysDeptController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysDeptController.java @@ -1,5 +1,6 @@ package io.dataease.controller.sys; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.commons.utils.BeanUtils; import io.dataease.controller.ResultHolder; import io.dataease.controller.sys.base.BaseGridRequest; @@ -40,6 +41,7 @@ public class SysDeptController extends ResultHolder { } @PostMapping("/search") + @SqlInjectValidator({"name"}) public List search(@RequestBody BaseGridRequest request){ List nodes = deptService.nodesTreeByCondition(request); List nodeResponses = nodes.stream().map(node -> { diff --git a/backend/src/main/java/io/dataease/controller/sys/SysLogController.java b/backend/src/main/java/io/dataease/controller/sys/SysLogController.java index bf1e01140b..5c58bcb57c 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysLogController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysLogController.java @@ -3,6 +3,7 @@ package io.dataease.controller.sys; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.commons.utils.PageUtils; import io.dataease.commons.utils.Pager; import io.dataease.controller.handler.annotation.I18n; @@ -36,6 +37,7 @@ public class SysLogController { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) + @SqlInjectValidator(value = {"time"}) public Pager> logGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody KeyGridRequest request) { request = logService.logRetentionProxy(request); diff --git a/backend/src/main/java/io/dataease/controller/sys/SysPluginController.java b/backend/src/main/java/io/dataease/controller/sys/SysPluginController.java index d3ca2bc85d..7f3b3e669f 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysPluginController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysPluginController.java @@ -2,6 +2,7 @@ package io.dataease.controller.sys; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.plugins.common.base.domain.MyPlugin; import io.dataease.commons.utils.PageUtils; import io.dataease.commons.utils.Pager; @@ -30,6 +31,7 @@ public class SysPluginController { @ApiOperation("查询已安装插件") @PostMapping("/pluginGrid/{goPage}/{pageSize}") @RequiresPermissions("plugin:read") + @SqlInjectValidator(value = {"install_time"}) public Pager> pluginGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody BaseGridRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); return PageUtils.setPageInfo(page, pluginService.query(request)); diff --git a/backend/src/main/java/io/dataease/controller/sys/SysUserController.java b/backend/src/main/java/io/dataease/controller/sys/SysUserController.java index c43a59ceca..8d0b3736ce 100644 --- a/backend/src/main/java/io/dataease/controller/sys/SysUserController.java +++ b/backend/src/main/java/io/dataease/controller/sys/SysUserController.java @@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper; import com.github.xiaoymin.knife4j.annotations.ApiSupport; import io.dataease.auth.annotation.DeLog; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.api.dto.CurrentUserDto; import io.dataease.auth.entity.AccountLockStatus; import io.dataease.auth.service.AuthUserService; @@ -78,6 +79,7 @@ public class SysUserController { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) + @SqlInjectValidator(value = {"create_time", "u.enabled", "nick_name", "u.dept_id"}) public Pager> userGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody KeyGridRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); @@ -102,6 +104,7 @@ public class SysUserController { @ApiIgnore @PostMapping("/userLists") + @SqlInjectValidator({"nick_name", "create_time"}) public List userLists(@RequestBody BaseGridRequest request) { KeyGridRequest keyGridRequest = BeanUtils.copyBean(new KeyGridRequest(), request); return sysUserService.query(keyGridRequest); @@ -224,6 +227,7 @@ public class SysUserController { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) + @SqlInjectValidator({"create_time", "update_time"}) public Pager> roleGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody BaseGridRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); diff --git a/backend/src/main/java/io/dataease/controller/sys/request/MsgRequest.java b/backend/src/main/java/io/dataease/controller/sys/request/MsgRequest.java index 3e5ac7f497..a06787bd9e 100644 --- a/backend/src/main/java/io/dataease/controller/sys/request/MsgRequest.java +++ b/backend/src/main/java/io/dataease/controller/sys/request/MsgRequest.java @@ -1,15 +1,15 @@ package io.dataease.controller.sys.request; +import io.dataease.controller.sys.base.BaseGridRequest; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; -import java.util.List; @Data @ApiModel("消息条件") -public class MsgRequest implements Serializable { +public class MsgRequest extends BaseGridRequest implements Serializable { private static final long serialVersionUID = 1920091635946508658L; @@ -19,6 +19,4 @@ public class MsgRequest implements Serializable { @ApiModelProperty("是否订阅") private Boolean status; - @ApiModelProperty("排序描述") - private List orders; } diff --git a/backend/src/main/java/io/dataease/dto/panel/PanelExport2App.java b/backend/src/main/java/io/dataease/dto/panel/PanelExport2App.java index c8061ef634..d663b77687 100644 --- a/backend/src/main/java/io/dataease/dto/panel/PanelExport2App.java +++ b/backend/src/main/java/io/dataease/dto/panel/PanelExport2App.java @@ -37,6 +37,14 @@ public class PanelExport2App { private String datasourceInfo; + private String linkJumps; + + private String linkJumpInfos; + + private String linkages; + + private String linkageFields; + public PanelExport2App() { } @@ -45,7 +53,11 @@ public class PanelExport2App { this.checkMes = checkMes; } - public PanelExport2App(List chartViewsInfo, List chartViewFieldsInfo, List datasetTablesInfo, List datasetTableFieldsInfo, List datasetTasksInfo, List datasourceInfo, List panelViewsInfo) { + public PanelExport2App(List chartViewsInfo, List chartViewFieldsInfo, + List datasetTablesInfo, List datasetTableFieldsInfo, + List datasetTasksInfo, List datasourceInfo, + List panelViewsInfo,List linkJumps,List linkJumpInfos, + List linkages, List linkageFields) { List empty = new ArrayList(); this.checkStatus = true; this.checkMes = "success"; @@ -56,5 +68,9 @@ public class PanelExport2App { this.datasetTasksInfo = JSON.toJSONString(datasetTasksInfo!=null?datasetTasksInfo:empty); this.datasourceInfo = JSON.toJSONString(datasourceInfo!=null?datasourceInfo:empty); this.panelViewsInfo = JSON.toJSONString(panelViewsInfo!=null?panelViewsInfo:empty); + this.linkJumps = JSON.toJSONString(linkJumps!=null?linkJumps:empty); + this.linkJumpInfos = JSON.toJSONString(linkJumpInfos!=null?linkJumpInfos:empty); + this.linkages = JSON.toJSONString(linkages!=null?linkages:empty); + this.linkageFields = JSON.toJSONString(linkJumpInfos!=null?linkageFields:empty); } } diff --git a/backend/src/main/java/io/dataease/ext/ExtChartViewMapper.xml b/backend/src/main/java/io/dataease/ext/ExtChartViewMapper.xml index a532fb0fd0..d7ab36aeab 100644 --- a/backend/src/main/java/io/dataease/ext/ExtChartViewMapper.xml +++ b/backend/src/main/java/io/dataease/ext/ExtChartViewMapper.xml @@ -645,7 +645,7 @@ last_sync_time) SELECT uuid() AS id, chart_view_field.table_id, - chart_view_field.pv_copy.chart_view_id AS chart_id, + pv_copy.chart_view_id AS chart_id, chart_view_field.origin_name, chart_view_field.`name`, chart_view_field.dataease_name, diff --git a/backend/src/main/java/io/dataease/ext/ExtPanelLinkJumpMapper.java b/backend/src/main/java/io/dataease/ext/ExtPanelLinkJumpMapper.java index e030e1f52a..e969e51137 100644 --- a/backend/src/main/java/io/dataease/ext/ExtPanelLinkJumpMapper.java +++ b/backend/src/main/java/io/dataease/ext/ExtPanelLinkJumpMapper.java @@ -2,6 +2,8 @@ package io.dataease.ext; import io.dataease.dto.panel.linkJump.PanelLinkJumpBaseRequest; import io.dataease.dto.panel.linkJump.PanelLinkJumpDTO; +import io.dataease.plugins.common.base.domain.PanelLinkJump; +import io.dataease.plugins.common.base.domain.PanelLinkJumpInfo; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -30,4 +32,7 @@ public interface ExtPanelLinkJumpMapper { void copyLinkJumpInfo(@Param("copyId")String copyId); void copyLinkJumpTarget(@Param("copyId")String copyId); + + List findLinkJumpWithPanelId(@Param("panelId")String panelId); + List findLinkJumpInfoWithPanelId(@Param("panelId")String panelId); } diff --git a/backend/src/main/java/io/dataease/ext/ExtPanelLinkJumpMapper.xml b/backend/src/main/java/io/dataease/ext/ExtPanelLinkJumpMapper.xml index a0e492ad34..978e9fe38f 100644 --- a/backend/src/main/java/io/dataease/ext/ExtPanelLinkJumpMapper.xml +++ b/backend/src/main/java/io/dataease/ext/ExtPanelLinkJumpMapper.xml @@ -269,4 +269,29 @@ WHERE copy_id = #{copyId}) plji_copy ON panel_link_jump_target_view_info.link_jump_info_id = plji_copy.s_id + + + + diff --git a/backend/src/main/java/io/dataease/ext/ExtPanelViewLinkageMapper.java b/backend/src/main/java/io/dataease/ext/ExtPanelViewLinkageMapper.java index 053e0fa03a..41ee8b1441 100644 --- a/backend/src/main/java/io/dataease/ext/ExtPanelViewLinkageMapper.java +++ b/backend/src/main/java/io/dataease/ext/ExtPanelViewLinkageMapper.java @@ -3,6 +3,8 @@ package io.dataease.ext; import io.dataease.dto.LinkageInfoDTO; import io.dataease.dto.PanelViewLinkageDTO; import io.dataease.plugins.common.base.domain.DatasetTableField; +import io.dataease.plugins.common.base.domain.PanelViewLinkage; +import io.dataease.plugins.common.base.domain.PanelViewLinkageField; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -24,4 +26,8 @@ public interface ExtPanelViewLinkageMapper { void copyViewLinkage(@Param("copyId") String copyId); void copyViewLinkageField(@Param("copyId") String copyId); + + List findLinkageWithPanelId(@Param("panelId") String panelId); + + List findLinkageFieldWithPanelId(@Param("panelId") String panelId); } diff --git a/backend/src/main/java/io/dataease/ext/ExtPanelViewLinkageMapper.xml b/backend/src/main/java/io/dataease/ext/ExtPanelViewLinkageMapper.xml index 84f727954c..55772f2697 100644 --- a/backend/src/main/java/io/dataease/ext/ExtPanelViewLinkageMapper.xml +++ b/backend/src/main/java/io/dataease/ext/ExtPanelViewLinkageMapper.xml @@ -195,4 +195,18 @@ ) pvlf_copy ON panel_view_linkage_field.linkage_id = pvlf_copy.s_id + + + + + diff --git a/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java b/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java index 3ae19f3e62..772fafdaef 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XDeptServer.java @@ -6,6 +6,7 @@ import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.dataease.auth.annotation.DeLog; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.service.ExtAuthService; import io.dataease.commons.constants.AuthConstants; import io.dataease.commons.constants.DePermissionType; @@ -155,6 +156,7 @@ public class XDeptServer { @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) @PostMapping("/userGrid/{goPage}/{pageSize}") + @SqlInjectValidator(value = {"dept_name", "nick_name"}) public Pager> userGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody XpackDeptUserRequest request) { DeptXpackService deptService = SpringContextUtil.getBean(DeptXpackService.class); Page page = PageHelper.startPage(goPage, pageSize, true); diff --git a/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java b/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java index 9919decbf4..3f38ea5a4f 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XEmailTaskServer.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ArrayUtil; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.dataease.auth.annotation.DeRateLimiter; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.api.dto.CurrentUserDto; import io.dataease.commons.exception.DEException; import io.dataease.commons.model.excel.ExcelSheetModel; @@ -59,6 +60,7 @@ public class XEmailTaskServer { @RequiresPermissions("task-email:read") @PostMapping("/queryTasks/{goPage}/{pageSize}") + @SqlInjectValidator(value = {"create_time"}) public Pager> queryTask(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody XpackGridRequest request) { EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class); diff --git a/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java b/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java index 661a9e9012..4b60d4c3a7 100644 --- a/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java +++ b/backend/src/main/java/io/dataease/plugins/server/XRoleServer.java @@ -5,6 +5,7 @@ import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.dataease.auth.annotation.DeLog; import io.dataease.auth.annotation.DePermission; +import io.dataease.auth.annotation.SqlInjectValidator; import io.dataease.auth.service.ExtAuthService; import io.dataease.commons.constants.AuthConstants; import io.dataease.commons.constants.DePermissionType; @@ -93,6 +94,7 @@ public class XRoleServer { @ApiImplicitParam(paramType = "path", name = "pageSize", value = "页容量", required = true, dataType = "Integer"), @ApiImplicitParam(name = "request", value = "查询条件", required = true) }) + @SqlInjectValidator(value = {"create_time", "name"}) public Pager> roleGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody XpackGridRequest request) { RoleXpackService roleXpackService = SpringContextUtil.getBean(RoleXpackService.class); Page page = PageHelper.startPage(goPage, pageSize, true); diff --git a/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlDDLProvider.java b/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlDDLProvider.java index 259169b614..cd9ff9f1b8 100644 --- a/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlDDLProvider.java +++ b/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlDDLProvider.java @@ -4,9 +4,12 @@ import io.dataease.plugins.common.base.domain.DatasetTableField; import io.dataease.plugins.common.base.domain.Datasource; import io.dataease.commons.utils.TableUtils; import io.dataease.provider.DDLProviderImpl; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import java.util.Arrays; import java.util.List; +import java.util.UUID; /** * @Author gin @@ -25,6 +28,30 @@ public class MysqlDDLProvider extends DDLProviderImpl { return "CREATE or replace view " + name + " AS (" + viewSQL + ")"; } + @Override + public String insertSql(String name, List dataList, int page, int pageNumber) { + String insertSql = "INSERT INTO TABLE_NAME VALUES ".replace("TABLE_NAME", name); + StringBuffer values = new StringBuffer(); + + Integer realSize = page * pageNumber < dataList.size() ? page * pageNumber : dataList.size(); + for (String[] strings : dataList.subList((page - 1) * pageNumber, realSize)) { + String[] strings1 = new String[strings.length]; + for (int i = 0; i < strings.length; i++) { + if (StringUtils.isEmpty(strings[i])) { + strings1[i] = null; + } else { + strings1[i] = strings[i].replace("'", "\\'"); + } + } + values.append("('").append(UUID.randomUUID()) + .append("','").append(String.join("','", Arrays.asList(strings1))) + .append("'),"); + } + return (insertSql + values.substring(0, values.length() - 1)).replaceAll(",'null'", ",null"); + } + + + @Override public String dropTable(String name) { return "DROP TABLE IF EXISTS " + name; @@ -67,7 +94,7 @@ public class MysqlDDLProvider extends DDLProviderImpl { } break; case 2: - Column_Fields.append("varchar(100)").append(",`"); + Column_Fields.append("bigint(20)").append(",`"); break; case 3: Column_Fields.append("varchar(100)").append(",`"); diff --git a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java index e56116cbad..1af4e7036a 100644 --- a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java +++ b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java @@ -879,10 +879,11 @@ public class ChartViewService { fieldsToFilter.addAll(xAxisBase); } ChartDrillRequest head = drillRequestList.get(0); - Map dimValMap = head.getDimensionList().stream().collect(Collectors.toMap(ChartDimensionDTO::getId, ChartDimensionDTO::getValue)); - Map fieldMap = Stream.of(xAxisBase, xAxisExt, extStack). - flatMap(Collection::stream). - collect(Collectors.toMap(ChartViewFieldDTO::getId, o -> o)); + Map dimValMap = new HashMap<>(); + head.getDimensionList().forEach(item -> dimValMap.put(item.getId(), item.getValue())); + Map fieldMap = Stream.of(xAxisBase, xAxisExt, extStack) + .flatMap(Collection::stream) + .collect(Collectors.toMap(ChartViewFieldDTO::getId, o -> o, ((p, n) -> p))); for (int i = 0; i < drillRequestList.size(); i++) { ChartDrillRequest request = drillRequestList.get(i); ChartViewFieldDTO chartViewFieldDTO = drill.get(i); @@ -893,6 +894,7 @@ public class ChartViewService { fieldsToFilter.add(chartViewFieldDTO); dimValMap.put(requestDimension.getId(), requestDimension.getValue()); if (!checkDrillExist(xAxis, extStack, requestDimension.getId(), view)) { + fieldMap.put(chartViewFieldDTO.getId(), chartViewFieldDTO); xAxis.add(chartViewFieldDTO); } if (i == drillRequestList.size() - 1) { 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 aab9f1367e..e54774e2e6 100644 --- a/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java +++ b/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java @@ -147,6 +147,7 @@ public class DataSetTableService { public static final String regex = "\\$\\{(.*?)\\}"; private static final String SubstitutedParams = "DATAEASE_PATAMS_BI"; private static final String SubstitutedSql = " 'BI' = 'BI' "; + private static final String SubstitutedSqlVirtualData = " 1 < 2 "; @Value("${upload.file.path}") private String path; @@ -323,7 +324,7 @@ public class DataSetTableService { if (StringUtils.equalsIgnoreCase(datasetTable.getType(), DatasetType.SQL.name()) && !"appApply".equalsIgnoreCase(datasetTable.getOptFrom())) { DataSetTableRequest dataSetTableRequest = new DataSetTableRequest(); BeanUtils.copyBean(dataSetTableRequest, datasetTable); - getSQLPreview(dataSetTableRequest); + getSQLPreview(dataSetTableRequest, false); } if (StringUtils.isEmpty(datasetTable.getId())) { datasetTable.setId(UUID.randomUUID().toString()); @@ -1058,7 +1059,8 @@ public class DataSetTableService { Matcher matcher = pattern.matcher(sql); while (matcher.find()) { SqlVariableDetails defaultsSqlVariableDetail = null; - List defaultsSqlVariableDetails = new Gson().fromJson(sqlVariableDetails, new TypeToken>() {}.getType()); + List defaultsSqlVariableDetails = new Gson().fromJson(sqlVariableDetails, new TypeToken>() { + }.getType()); for (SqlVariableDetails sqlVariableDetail : defaultsSqlVariableDetails) { if (matcher.group().substring(2, matcher.group().length() - 1).equalsIgnoreCase(sqlVariableDetail.getVariableName())) { defaultsSqlVariableDetail = sqlVariableDetail; @@ -1069,8 +1071,7 @@ public class DataSetTableService { defaultsSqlVariableDetail.getDefaultValueScope().equals(SqlVariableDetails.DefaultValueScope.ALLSCOPE) && StringUtils.isNotEmpty(defaultsSqlVariableDetail.getDefaultValue())) { sql = sql.replace(matcher.group(), defaultsSqlVariableDetail.getDefaultValue()); } - if (isEdit && defaultsSqlVariableDetail != null && defaultsSqlVariableDetail.getDefaultValueScope() != null && - defaultsSqlVariableDetail.getDefaultValueScope().equals(SqlVariableDetails.DefaultValueScope.EDIT) && StringUtils.isNotEmpty(defaultsSqlVariableDetail.getDefaultValue())) { + if (isEdit && defaultsSqlVariableDetail != null && StringUtils.isNotEmpty(defaultsSqlVariableDetail.getDefaultValue())){ sql = sql.replace(matcher.group(), defaultsSqlVariableDetail.getDefaultValue()); } } @@ -1168,8 +1169,12 @@ public class DataSetTableService { binaryExpression = (BinaryExpression) expr; } catch (Exception e) { } - if (binaryExpression != null && !(binaryExpression.getLeftExpression() instanceof BinaryExpression) && !(binaryExpression.getRightExpression() instanceof BinaryExpression) && hasVariable(binaryExpression.toString())) { - stringBuilder.append(SubstitutedSql); + if (binaryExpression != null) { + if (!(binaryExpression.getLeftExpression() instanceof BinaryExpression) && !(binaryExpression.getLeftExpression() instanceof InExpression) && hasVariable(binaryExpression.getRightExpression().toString())) { + stringBuilder.append(SubstitutedSql); + }else { + expr.accept(getExpressionDeParser(stringBuilder)); + } } else { expr.accept(getExpressionDeParser(stringBuilder)); } @@ -1243,7 +1248,7 @@ public class DataSetTableService { return datasetSqlLogMapper.selectByExample(example); } - public ResultHolder getSQLPreview(DataSetTableRequest dataSetTableRequest) throws Exception { + public ResultHolder getSQLPreview(DataSetTableRequest dataSetTableRequest, boolean realData) throws Exception { DatasetSqlLog datasetSqlLog = new DatasetSqlLog(); DataTableInfoDTO dataTableInfo = new Gson().fromJson(dataSetTableRequest.getInfo(), DataTableInfoDTO.class); @@ -1254,6 +1259,9 @@ public class DataSetTableService { throw new Exception(Translator.get("i18n_invalid_ds")); } String tmpSql = removeVariables(sql, ds.getType()); + if(!realData){ + tmpSql.replaceAll(SubstitutedSql, SubstitutedSqlVirtualData); + } if (dataSetTableRequest.getMode() == 1 && (tmpSql.contains(SubstitutedParams) || tmpSql.contains(SubstitutedSql.trim()))) { throw new Exception(Translator.get("I18N_SQL_variable_direct_limit")); } @@ -1264,8 +1272,7 @@ public class DataSetTableService { DatasourceRequest datasourceRequest = new DatasourceRequest(); datasourceRequest.setDatasource(ds); - - sql = handleVariableDefaultValue(sql, dataSetTableRequest.getSqlVariableDetails(), ds.getType(), true); + sql = realData ? handleVariableDefaultValue(sql, dataSetTableRequest.getSqlVariableDetails(), ds.getType(), true) : removeVariables(sql, ds.getType()).replaceAll(SubstitutedSql, SubstitutedSqlVirtualData); if (StringUtils.isEmpty(sql)) { DataEaseException.throwException(Translator.get("i18n_sql_not_empty")); } @@ -1641,7 +1648,9 @@ public class DataSetTableService { // field StringBuilder field = new StringBuilder(); for (Map.Entry next : checkedInfo.entrySet()) { - field.append(StringUtils.join(next.getValue(), ",")).append(","); + if (next.getValue().length > 0) { + field.append(StringUtils.join(next.getValue(), ",")).append(","); + } } String f = subPrefixSuffixChar(field.toString()); // join @@ -1789,7 +1798,9 @@ public class DataSetTableService { // field StringBuilder field = new StringBuilder(); for (Map.Entry next : checkedInfo.entrySet()) { - field.append(StringUtils.join(next.getValue(), ",")).append(","); + if (next.getValue().length > 0) { + field.append(StringUtils.join(next.getValue(), ",")).append(","); + } } String f = subPrefixSuffixChar(field.toString()); // join @@ -1931,7 +1942,7 @@ public class DataSetTableService { QueryProvider qp = ProviderFactory.getQueryProvider(ds.getType()); DataTableInfoDTO dataTableInfo = new Gson().fromJson(datasetTable.getInfo(), DataTableInfoDTO.class); String sql = dataTableInfo.isBase64Encryption() ? new String(java.util.Base64.getDecoder().decode(dataTableInfo.getSql())) : dataTableInfo.getSql(); - sql = handleVariableDefaultValue(sql, null, ds.getType(), false); + sql = removeVariables(sql, ds.getType()).replaceAll(SubstitutedSql, SubstitutedSqlVirtualData); String sqlAsTable = qp.createSQLPreview(sql, null); datasourceRequest.setQuery(sqlAsTable); fields = datasourceProvider.fetchResultField(datasourceRequest); @@ -2268,7 +2279,7 @@ public class DataSetTableService { } Set nameSet = new HashSet<>(); for (DataSetTableRequest table : datasetTable) { - if(StringUtils.isEmpty(table.getName())){ + if (StringUtils.isEmpty(table.getName())) { throw new RuntimeException(Translator.get("I18n_name_cant_empty")); } nameSet.add(table.getName()); diff --git a/backend/src/main/java/io/dataease/service/panel/PanelAppTemplateService.java b/backend/src/main/java/io/dataease/service/panel/PanelAppTemplateService.java index 8311ea5a7d..9799a6b54d 100644 --- a/backend/src/main/java/io/dataease/service/panel/PanelAppTemplateService.java +++ b/backend/src/main/java/io/dataease/service/panel/PanelAppTemplateService.java @@ -14,7 +14,7 @@ import io.dataease.controller.request.panel.PanelGroupRequest; import io.dataease.dto.DatasourceDTO; import io.dataease.ext.ExtPanelAppTemplateMapper; import io.dataease.plugins.common.base.domain.*; -import io.dataease.plugins.common.base.mapper.PanelAppTemplateMapper; +import io.dataease.plugins.common.base.mapper.*; import io.dataease.plugins.common.constants.DatasetType; import io.dataease.service.chart.ChartViewFieldService; import io.dataease.service.chart.ChartViewService; @@ -72,6 +72,14 @@ public class PanelAppTemplateService { private StaticResourceService staticResourceService; @Resource private ExtractDataService extractDataService; + @Resource + private PanelLinkJumpMapper panelLinkJumpMapper; + @Resource + private PanelLinkJumpInfoMapper panelLinkJumpInfoMapper; + @Resource + private PanelViewLinkageMapper panelViewLinkageMapper; + @Resource + private PanelViewLinkageFieldMapper panelViewLinkageFieldMapper; public List list(PanelAppTemplateRequest request) { return extPanelAppTemplateMapper.queryBaseInfo(request.getNodeType(), request.getPid()); @@ -411,4 +419,67 @@ public class PanelAppTemplateService { } } + + @Transactional(rollbackFor = Exception.class) + public Map applyLinkJumps(List linkJumps, Map chartViewsRealMap, String newPanelId) { + Map linkJumpIdMap = new HashMap<>(); + if(!CollectionUtils.isEmpty(linkJumps)){ + for(PanelLinkJump linkJump :linkJumps){ + String newLinkJumpId = UUIDUtil.getUUIDAsString(); + linkJumpIdMap.put(linkJump.getId(),newLinkJumpId); + linkJump.setId(newLinkJumpId); + linkJump.setSourcePanelId(newPanelId); + linkJump.setSourceViewId(chartViewsRealMap.get(linkJump.getSourceViewId())); + panelLinkJumpMapper.insertSelective(linkJump); + } + } + return linkJumpIdMap; + } + + @Transactional(rollbackFor = Exception.class) + public void applyLinkJumpInfos(List linkJumpInfos, Map linkJumpIdMap, Map datasetFieldsRealMap) { + if(!CollectionUtils.isEmpty(linkJumpInfos)){ + for(PanelLinkJumpInfo linkJumpInfo :linkJumpInfos){ + String newLinkJumpInfoId = UUIDUtil.getUUIDAsString(); + linkJumpInfo.setId(newLinkJumpInfoId); + linkJumpInfo.setLinkJumpId(linkJumpIdMap.get(linkJumpInfo.getLinkJumpId())); + linkJumpInfo.setSourceFieldId(datasetFieldsRealMap.get(linkJumpInfo.getSourceFieldId())); + datasetFieldsRealMap.forEach((k, v) -> { + linkJumpInfo.setContent(linkJumpInfo.getContent().replaceAll(k, v)); + }); + panelLinkJumpInfoMapper.insertSelective(linkJumpInfo); + } + } + } + + @Transactional(rollbackFor = Exception.class) + public Map applyLinkages(List linkages, Map chartViewsRealMap, String newPanelId) { + Map linkageIdMap = new HashMap<>(); + if(!CollectionUtils.isEmpty(linkages)){ + for(PanelViewLinkage linkage :linkages){ + String newId = UUIDUtil.getUUIDAsString(); + linkageIdMap.put(linkage.getId(),newId); + linkage.setId(newId); + linkage.setPanelId(newPanelId); + linkage.setSourceViewId(chartViewsRealMap.get(linkage.getSourceViewId())); + linkage.setTargetViewId(chartViewsRealMap.get(linkage.getTargetViewId())); + panelViewLinkageMapper.insertSelective(linkage); + } + } + return linkageIdMap; + } + + @Transactional(rollbackFor = Exception.class) + public void applyLinkageFields(List linkageFields, Map linkageIdMap, Map datasetFieldsRealMap) { + if(!CollectionUtils.isEmpty(linkageFields)){ + for(PanelViewLinkageField linkageField :linkageFields){ + String newId = UUIDUtil.getUUIDAsString(); + linkageField.setId(newId); + linkageField.setLinkageId(linkageIdMap.get(linkageField.getLinkageId())); + linkageField.setSourceField(datasetFieldsRealMap.get(linkageField.getSourceField())); + linkageField.setTargetField(datasetFieldsRealMap.get(linkageField.getTargetField())); + panelViewLinkageFieldMapper.insertSelective(linkageField); + } + } + } } 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 52f8af9321..4d54ff13cd 100644 --- a/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java +++ b/backend/src/main/java/io/dataease/service/panel/PanelGroupService.java @@ -964,6 +964,14 @@ public class PanelGroupService { List datasourceDTOS = extDataSourceMapper.findByTableIds(allTableIds); List panelViews = panelViewService.findPanelViewsByPanelId(panelId); + //获取所有跳转信息 + List linkJumps = extPanelLinkJumpMapper.findLinkJumpWithPanelId(panelId); + //获取所有跳转关联信息 + List linkJumpInfos = extPanelLinkJumpMapper.findLinkJumpInfoWithPanelId(panelId); + //获取所有联动信息 + List linkages = extPanelViewLinkageMapper.findLinkageWithPanelId(panelId); + //获取所有联动关联信息 + List LinkageFields = extPanelViewLinkageMapper.findLinkageFieldWithPanelId(panelId); //校验标准 1.存在视图且所有视图的数据来源必须是dataset 2.存在数据集且没有excel数据集 3.存在数据源且是单数据源 //1.view check @@ -979,7 +987,8 @@ public class PanelGroupService { } else if (datasourceDTOS.size() > 1) { return new PanelExport2App(Translator.get("I18N_APP_ONE_DATASOURCE_TIPS")); } - return new PanelExport2App(chartViewsInfo, chartViewFieldsInfo, datasetTablesInfo, datasetTableFieldsInfo, dataSetTasksInfo, datasourceDTOS, panelViews); + return new PanelExport2App(chartViewsInfo, chartViewFieldsInfo, datasetTablesInfo, datasetTableFieldsInfo, + dataSetTasksInfo, datasourceDTOS, panelViews, linkJumps, linkJumpInfos, linkages, LinkageFields); } @Transactional(rollbackFor = Exception.class) @@ -1016,11 +1025,32 @@ public class PanelGroupService { //6.获取所有数据源信息 List oldDatasourceInfo = gson.fromJson(appInfo.getDatasourceInfo(), new TypeToken>() { }.getType()); - //获取仪表板信息 + //7.获取仪表板信息 PanelGroupRequest panelInfo = gson.fromJson(appInfo.getPanelInfo(), PanelGroupRequest.class); - //获取仪表板视图信息 + //8.获取仪表板视图信息 List panelViewsInfo = gson.fromJson(appInfo.getPanelViewsInfo(), new TypeToken>() { }.getType()); + //9.获取跳转信息 + List linkJumps = null; + if(StringUtils.isNotEmpty(appInfo.getLinkJumps())){ + linkJumps = gson.fromJson(appInfo.getLinkJumps(), new TypeToken>() {}.getType()); + } + //10.获取跳转关联信息 + List linkJumpInfos = null; + if(StringUtils.isNotEmpty(appInfo.getLinkJumpInfos())){ + linkJumpInfos = gson.fromJson(appInfo.getLinkJumpInfos(), new TypeToken>() {}.getType()); + } + //11.获取联动信息 + List linkages = null; + if(StringUtils.isNotEmpty(appInfo.getLinkages())){ + linkages = gson.fromJson(appInfo.getLinkages(), new TypeToken>() {}.getType()); + } + + //12.获取联动关联信息 + List linkageFields = null; + if(StringUtils.isNotEmpty(appInfo.getLinkageFields())){ + linkageFields = gson.fromJson(appInfo.getLinkageFields(), new TypeToken>() {}.getType()); + } Map datasourceRealMap = panelAppTemplateService.applyDatasource(oldDatasourceInfo, request); @@ -1044,8 +1074,15 @@ public class PanelGroupService { panelAppTemplateService.applyPanelView(panelViewsInfo, chartViewsRealMap, newPanelId); - String newDatasourceId = datasourceRealMap.entrySet().stream().findFirst().get().getValue(); + Map linkageIdMap = panelAppTemplateService.applyLinkages(linkages,chartViewsRealMap,newPanelId); + panelAppTemplateService.applyLinkageFields(linkageFields,linkageIdMap,datasetFieldsRealMap); + + Map linkJumpIdMap = panelAppTemplateService.applyLinkJumps(linkJumps,chartViewsRealMap,newPanelId); + + panelAppTemplateService.applyLinkJumpInfos(linkJumpInfos,linkJumpIdMap,datasetFieldsRealMap); + + String newDatasourceId = datasourceRealMap.entrySet().stream().findFirst().get().getValue(); PanelAppTemplateLog templateLog = new PanelAppTemplateLog(); templateLog.setPanelId(newPanelId); 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 309f0d6f3b..19a8c5a04d 100644 --- a/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java +++ b/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java @@ -3,6 +3,7 @@ package io.dataease.service.staticResource; import cn.hutool.core.codec.Base64Decoder; import cn.hutool.core.collection.CollectionUtil; import com.google.gson.Gson; +import io.dataease.commons.exception.DEException; import io.dataease.commons.utils.FileUtils; import io.dataease.commons.utils.LogUtil; import io.dataease.commons.utils.StaticResourceUtils; @@ -14,7 +15,10 @@ import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -31,61 +35,78 @@ public class StaticResourceService { private final Path staticDir = Paths.get("/opt/dataease/data/static-resource/"); - public void upload(String fileId,MultipartFile file) { + public void upload(String fileId, MultipartFile file) { // check if the path is valid (not outside staticDir) Assert.notNull(file, "Multipart file must not be null"); try { + if (!isImage(file)) { + DEException.throwException("Multipart file must be image"); + } String originName = file.getOriginalFilename(); - String newFileName = fileId+originName.substring(originName.lastIndexOf("."),originName.length()); + String newFileName = fileId + originName.substring(originName.lastIndexOf("."), originName.length()); Path uploadPath = Paths.get(staticDir.toString(), newFileName); // create dir is absent FileUtils.createIfAbsent(Paths.get(staticDir.toString())); Files.createFile(uploadPath); file.transferTo(uploadPath); } catch (IOException e) { - LogUtil.error("文件上传失败",e); + LogUtil.error("文件上传失败", e); DataEaseException.throwException("文件上传失败"); - } catch (Exception e){ + } catch (Exception e) { DataEaseException.throwException(e); } } - public void saveFilesToServe(String staticResource){ + private boolean isImage(MultipartFile file) { + BufferedImage image = null; + try (InputStream input = file.getInputStream()) { + image = ImageIO.read(input); + } catch (IOException e) { + LogUtil.error(e.getMessage(), e); + return false; + } + if (image == null || image.getWidth() <= 0 || image.getHeight() <= 0) { + return false; + } + return true; + } + + public void saveFilesToServe(String staticResource) { Gson gson = new Gson(); - if(StringUtils.isNotEmpty(staticResource)){ - Map resource = gson.fromJson(staticResource,Map.class); - for(Map.Entry entry:resource.entrySet()){ + if (StringUtils.isNotEmpty(staticResource)) { + Map resource = gson.fromJson(staticResource, Map.class); + for (Map.Entry entry : resource.entrySet()) { String path = entry.getKey(); - String fileName = path.substring(path.lastIndexOf("/")+1,path.length()); - saveSingleFileToServe(fileName,entry.getValue()); + String fileName = path.substring(path.lastIndexOf("/") + 1, path.length()); + saveSingleFileToServe(fileName, entry.getValue()); } } } - public void saveSingleFileToServe(String fileName,String content){ + public void saveSingleFileToServe(String fileName, String content) { Path uploadPath = Paths.get(staticDir.toString(), fileName); - try{ + try { if (uploadPath.toFile().exists()) { LogUtil.info("file exists"); - }else{ - if(StringUtils.isNotEmpty(content)){ + } else { + if (StringUtils.isNotEmpty(content)) { Files.createFile(uploadPath); - FileCopyUtils.copy(Base64Decoder.decode(content),Files.newOutputStream(uploadPath)); + FileCopyUtils.copy(Base64Decoder.decode(content), Files.newOutputStream(uploadPath)); } } - }catch (Exception e){ - LogUtil.error("template static resource save error"+e.getMessage()); + } 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); + 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; + return result; } } diff --git a/backend/src/main/resources/db/migration/V52__1.18.5.sql b/backend/src/main/resources/db/migration/V52__1.18.5.sql index b44d1a9529..747a7fcbd8 100644 --- a/backend/src/main/resources/db/migration/V52__1.18.5.sql +++ b/backend/src/main/resources/db/migration/V52__1.18.5.sql @@ -54,4 +54,10 @@ END ;; delimiter ; -INSERT INTO `system_parameter` (`param_key`, `param_value`, `type`, `sort`) VALUES ('loginlimit.multiLogin', '0', 'text', '3'); \ No newline at end of file +INSERT INTO `system_parameter` (`param_key`, `param_value`, `type`, `sort`) VALUES ('loginlimit.multiLogin', '0', 'text', '3'); + +ALTER TABLE `panel_app_template` + ADD COLUMN `link_jumps` longtext NULL AFTER `datasource_info`, +ADD COLUMN `link_jump_infos` longtext NULL AFTER `link_jumps`, +ADD COLUMN `linkages` longtext NULL AFTER `link_jump_infos`, +ADD COLUMN `linkage_fields` longtext NULL AFTER `linkages`; \ No newline at end of file diff --git a/frontend/src/api/staticResource/staticResource.js b/frontend/src/api/staticResource/staticResource.js index 9af311c16d..3affe2c95a 100644 --- a/frontend/src/api/staticResource/staticResource.js +++ b/frontend/src/api/staticResource/staticResource.js @@ -4,7 +4,7 @@ import store from '@/store' export function uploadFile(fileId, param) { return request({ - url: '/static/resource/upload/' + fileId, + url: '/staticResource/upload/' + fileId, method: 'post', headers: { 'Content-Type': 'multipart/form-data' }, data: param, @@ -26,7 +26,7 @@ export function uploadFileResult(file, callback) { export function findResourceAsBase64(params) { return request({ - url: '/static/resource/findResourceAsBase64', + url: '/staticResource/findResourceAsBase64', method: 'post', data: params, loading: false diff --git a/frontend/src/assets/wizard_wechat-group.png b/frontend/src/assets/wizard_wechat-group.png index c0fff00fb9..0e20eda6dd 100644 Binary files a/frontend/src/assets/wizard_wechat-group.png and b/frontend/src/assets/wizard_wechat-group.png differ diff --git a/frontend/src/components/canvas/components/editor/ComponentWrapper.vue b/frontend/src/components/canvas/components/editor/ComponentWrapper.vue index 005c2e2d74..fab2e19b7c 100644 --- a/frontend/src/components/canvas/components/editor/ComponentWrapper.vue +++ b/frontend/src/components/canvas/components/editor/ComponentWrapper.vue @@ -1,7 +1,7 @@