feat:自定义样式,email

This commit is contained in:
wangjiahao 2021-02-25 16:04:04 +08:00
parent 0afbbf3174
commit 5b1ec9b151
41 changed files with 1872 additions and 126 deletions

View File

@ -372,27 +372,27 @@
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>src/main/resources/static</directory>
<includes>
<include>**</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
<fileset>
<directory>src/main/resources/templates</directory>
<includes>
<include>**</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
<!-- <plugin>-->
<!-- <artifactId>maven-clean-plugin</artifactId>-->
<!-- <configuration>-->
<!-- <filesets>-->
<!-- <fileset>-->
<!-- <directory>src/main/resources/static</directory>-->
<!-- <includes>-->
<!-- <include>**</include>-->
<!-- </includes>-->
<!-- <followSymlinks>false</followSymlinks>-->
<!-- </fileset>-->
<!-- <fileset>-->
<!-- <directory>src/main/resources/templates</directory>-->
<!-- <includes>-->
<!-- <include>**</include>-->
<!-- </includes>-->
<!-- <followSymlinks>false</followSymlinks>-->
<!-- </fileset>-->
<!-- </filesets>-->
<!-- </configuration>-->
<!-- </plugin>-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>

View File

@ -2,6 +2,7 @@ package io.dataease.base.mapper.ext;
import io.dataease.base.domain.User;
import io.dataease.controller.request.UserRequest;
import io.dataease.notice.domain.UserDetail;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
@ -18,6 +19,8 @@ public interface ExtUserMapper {
List<User> searchUser(String condition);
List<UserDetail> queryTypeByIds(List<String> userIds);
@MapKey("id")
Map<String, User> queryNameByIds(List<String> userIds);
}

View File

@ -16,6 +16,18 @@
<result column="phone" jdbcType="VARCHAR" property="phone"/>
</resultMap>
<select id="queryTypeByIds" parameterType="java.lang.String" resultType="io.dataease.notice.domain.UserDetail">
SELECT
email,phone
from user
WHERE id IN
<foreach collection="list" item="id" index="index"
open="(" close=")" separator=",">
#{id}
</foreach>
</select>
<select id="getUserList" resultMap="BaseResultMap">
select u.id, u.name, u.email, u.phone, u.language, u.status, u.source,
u.last_organization_id, u.last_workspace_id, u.language, u.create_time, u.update_time

View File

@ -31,6 +31,7 @@ public interface ParamConstants {
MAIL("smtp"),
BASE("base"),
LDAP("ldap"),
UI("ui"),
REGISTRY("registry");
private String value;

View File

@ -0,0 +1,69 @@
package io.dataease.controller;
import io.dataease.base.domain.SystemParameter;
import io.dataease.commons.constants.ParamConstants;
import io.dataease.commons.constants.RoleConstants;
import io.dataease.dto.BaseSystemConfigDTO;
import io.dataease.dto.SystemParameterDTO;
import io.dataease.notice.domain.MailInfo;
import io.dataease.service.system.SystemParameterService;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping(value = "/system")
public class SystemParameterController {
@Resource
private SystemParameterService systemParameterService;
@PostMapping("/edit/email")
@RequiresRoles(value = {RoleConstants.ADMIN})
public void editMail(@RequestBody List<SystemParameter> systemParameter) {
systemParameterService.editMail(systemParameter);
}
@PostMapping("/testConnection")
@RequiresRoles(value = {RoleConstants.ADMIN})
public void testConnection(@RequestBody HashMap<String, String> hashMap) {
systemParameterService.testConnection(hashMap);
}
@GetMapping("/version")
public String getVersion() {
return systemParameterService.getVersion();
}
@GetMapping("/mail/info")
@RequiresRoles(value = {RoleConstants.ADMIN})
public MailInfo mailInfo() {
return systemParameterService.mailInfo(ParamConstants.Classify.MAIL.getValue());
}
@GetMapping("/base/info")
@RequiresRoles(value = {RoleConstants.ADMIN})
public List<SystemParameterDTO> getBaseInfo () {
return systemParameterService.getSystemParameterInfo(ParamConstants.Classify.BASE.getValue());
}
@GetMapping("/ui/info")
@RequiresRoles(value = {RoleConstants.ADMIN})
public List<SystemParameterDTO> getDisplayInfo () {
return systemParameterService.getSystemParameterInfo(ParamConstants.Classify.UI.getValue());
}
@PostMapping(value="/save/ui", consumes = {"multipart/form-data"})
@RequiresRoles(value = {RoleConstants.ADMIN})
public void saveUIInfo (@RequestPart("request") Map<String,List<SystemParameterDTO>> systemParameterMap,@RequestPart(value = "files") List<MultipartFile> bodyFiles) throws IOException {
systemParameterService.saveUIInfo(systemParameterMap,bodyFiles);
}
}

View File

@ -0,0 +1,28 @@
package io.dataease.dto;
import io.dataease.base.domain.SystemParameter;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.web.multipart.MultipartFile;
public class SystemParameterDTO extends SystemParameter {
@ApiModelProperty("文件")
private MultipartFile file;
@ApiModelProperty("文件名称")
private String fileName;
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}

View File

@ -0,0 +1,36 @@
package io.dataease.notice.controller;
import io.dataease.notice.domain.MessageDetail;
import io.dataease.notice.service.NoticeService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("notice")
public class NoticeController {
@Resource
private NoticeService noticeService;
@PostMapping("save/message/task")
public void saveMessage(@RequestBody MessageDetail messageDetail) {
noticeService.saveMessageTask(messageDetail);
}
@GetMapping("/search/message/type/{type}")
public List<MessageDetail> searchMessage(@PathVariable String type) {
return noticeService.searchMessageByType(type);
}
@GetMapping("/search/message/{testId}")
public List<MessageDetail> searchMessageSchedule(@PathVariable String testId) {
return noticeService.searchMessageByTestId(testId);
}
@GetMapping("/delete/message/{identification}")
public int deleteMessage(@PathVariable String identification) {
return noticeService.delMessage(identification);
}
}

View File

@ -0,0 +1,11 @@
package io.dataease.notice.controller.request;
import io.dataease.notice.domain.MessageDetail;
import lombok.Data;
import java.util.List;
@Data
public class MessageRequest {
private List<MessageDetail> messageDetail;
}

View File

@ -0,0 +1,18 @@
package io.dataease.notice.domain;
import lombok.Data;
@Data
public class Mail {
// 发送给谁
private String to;
// 发送主题
private String subject;
// 发送内容
private String content;
// 附件地址
private String filePath;
}

View File

@ -0,0 +1,15 @@
package io.dataease.notice.domain;
import lombok.Data;
@Data
public class MailInfo {
private String host;
private String port;
private String account;
private String password;
private String ssl;
private String tls;
private String recipient;
}

View File

@ -0,0 +1,21 @@
package io.dataease.notice.domain;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class MessageDetail {
private List<String> userIds = new ArrayList<>();
private String event;
private String taskType;
private String webhook;
private String type;
private String identification;
private String organizationId;
private Boolean isSet;
private String testId;
private Long createTime;
private String template;
}

View File

@ -0,0 +1,13 @@
package io.dataease.notice.domain;
import lombok.Data;
import java.util.List;
@Data
public class MessageSettingDetail {
private List<MessageDetail> jenkinsTask;
private List<MessageDetail> testCasePlanTask;
private List<MessageDetail> reviewTask;
private List<MessageDetail> defectTask;
}

View File

@ -0,0 +1,9 @@
package io.dataease.notice.domain;
import lombok.Data;
@Data
public class UserDetail {
private String email;
private String phone;
}

View File

@ -0,0 +1,45 @@
package io.dataease.notice.message;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
public class LinkMessage implements Message {
private String title;
private String text;
private String picUrl;
private String messageUrl;
public String toJsonString() {
Map<String, Object> items = new HashMap<String, Object>();
items.put("msgtype", "link");
Map<String, String> linkContent = new HashMap<String, String>();
if (StringUtils.isBlank(title)) {
throw new IllegalArgumentException("title should not be blank");
}
linkContent.put("title", title);
if (StringUtils.isBlank(messageUrl)) {
throw new IllegalArgumentException("messageUrl should not be blank");
}
linkContent.put("messageUrl", messageUrl);
if (StringUtils.isBlank(text)) {
throw new IllegalArgumentException("text should not be blank");
}
linkContent.put("text", text);
if (StringUtils.isNotBlank(picUrl)) {
linkContent.put("picUrl", picUrl);
}
items.put("link", linkContent);
return JSON.toJSONString(items);
}
}

View File

@ -0,0 +1,5 @@
package io.dataease.notice.message;
public interface Message {
String toJsonString();
}

View File

@ -0,0 +1,64 @@
package io.dataease.notice.message;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TextMessage implements Message {
private String text;
private List<String> mentionedMobileList;
private boolean isAtAll;
public TextMessage(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public boolean isAtAll() {
return isAtAll;
}
public void setIsAtAll(boolean isAtAll) {
this.isAtAll = isAtAll;
}
public List<String> getMentionedMobileList() {
return mentionedMobileList;
}
public void setMentionedMobileList(List<String> mentionedMobileList) {
this.mentionedMobileList = mentionedMobileList;
}
public String toJsonString() {
Map<String, Object> items = new HashMap<String, Object>();
items.put("msgtype", "text");
Map<String, Object> textContent = new HashMap<String, Object>();
if (StringUtils.isBlank(text)) {
throw new IllegalArgumentException("text should not be blank");
}
textContent.put("content", text);
if (isAtAll) {
if (mentionedMobileList == null) mentionedMobileList = new ArrayList<String>();
mentionedMobileList.add("@all");
}
if (mentionedMobileList != null && !mentionedMobileList.isEmpty()) {
textContent.put("mentioned_mobile_list", mentionedMobileList);
}
items.put("text", textContent);
return JSON.toJSONString(items);
}
}

View File

@ -0,0 +1,150 @@
package io.dataease.notice.sender;
import io.dataease.commons.constants.NoticeConstants;
import io.dataease.commons.utils.LogUtil;
import io.dataease.notice.domain.MessageDetail;
import io.dataease.notice.domain.UserDetail;
import io.dataease.service.UserService;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public abstract class AbstractNoticeSender implements NoticeSender {
@Resource
private UserService userService;
protected String getContext(MessageDetail messageDetail, NoticeModel noticeModel) {
// 如果配置了模版就直接使用模版
if (StringUtils.isNotBlank(messageDetail.getTemplate())) {
return getContent(messageDetail.getTemplate(), noticeModel.getParamMap());
}
// 处理 userIds 中包含的特殊值
List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel.getRelatedUsers(), messageDetail.getEvent());
messageDetail.setUserIds(realUserIds);
// 处理 WeCom Ding context
String context = "";
switch (messageDetail.getEvent()) {
case NoticeConstants.Event.CREATE:
case NoticeConstants.Event.UPDATE:
case NoticeConstants.Event.DELETE:
case NoticeConstants.Event.COMMENT:
context = noticeModel.getContext();
break;
case NoticeConstants.Event.EXECUTE_FAILED:
context = noticeModel.getFailedContext();
break;
case NoticeConstants.Event.EXECUTE_SUCCESSFUL:
context = noticeModel.getSuccessContext();
break;
default:
break;
}
return context;
}
protected String getHtmlContext(MessageDetail messageDetail, NoticeModel noticeModel) {
// 如果配置了模版就直接使用模版
if (StringUtils.isNotBlank(messageDetail.getTemplate())) {
return getContent(messageDetail.getTemplate(), noticeModel.getParamMap());
}
// 处理 userIds 中包含的特殊值
List<String> realUserIds = getRealUserIds(messageDetail.getUserIds(), noticeModel.getRelatedUsers(), messageDetail.getEvent());
messageDetail.setUserIds(realUserIds);
// 处理 mail context
String context = "";
try {
switch (messageDetail.getEvent()) {
case NoticeConstants.Event.CREATE:
case NoticeConstants.Event.UPDATE:
case NoticeConstants.Event.DELETE:
case NoticeConstants.Event.COMMENT:
URL resource = this.getClass().getResource("/mail/" + noticeModel.getMailTemplate() + ".html");
context = IOUtils.toString(resource, StandardCharsets.UTF_8);
break;
case NoticeConstants.Event.EXECUTE_FAILED:
URL resource1 = this.getClass().getResource("/mail/" + noticeModel.getFailedMailTemplate() + ".html");
context = IOUtils.toString(resource1, StandardCharsets.UTF_8);
break;
case NoticeConstants.Event.EXECUTE_SUCCESSFUL:
URL resource2 = this.getClass().getResource("/mail/" + noticeModel.getSuccessMailTemplate() + ".html");
context = IOUtils.toString(resource2, StandardCharsets.UTF_8);
break;
default:
break;
}
} catch (IOException e) {
LogUtil.error(e);
}
return getContent(context, noticeModel.getParamMap());
}
protected String getContent(String template, Map<String, Object> context) {
if (MapUtils.isNotEmpty(context)) {
for (String k : context.keySet()) {
if (context.get(k) != null) {
template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", context.get(k).toString());
} else {
template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", "未设置");
}
}
}
return template;
}
protected List<String> getUserPhones(List<String> userIds) {
List<UserDetail> list = userService.queryTypeByIds(userIds);
List<String> phoneList = new ArrayList<>();
list.forEach(u -> phoneList.add(u.getPhone()));
LogUtil.info("收件人地址: " + phoneList);
return phoneList.stream().distinct().collect(Collectors.toList());
}
protected List<String> getUserEmails(List<String> userIds) {
List<UserDetail> list = userService.queryTypeByIds(userIds);
List<String> phoneList = new ArrayList<>();
list.forEach(u -> phoneList.add(u.getEmail()));
LogUtil.info("收件人地址: " + phoneList);
return phoneList.stream().distinct().collect(Collectors.toList());
}
private List<String> getRealUserIds(List<String> userIds, List<String> relatedUsers, String event) {
List<String> toUserIds = new ArrayList<>();
for (String userId : userIds) {
switch (userId) {
case NoticeConstants.RelatedUser.EXECUTOR:
if (StringUtils.equals(NoticeConstants.Event.CREATE, event)) {
toUserIds.addAll(relatedUsers);
}
break;
case NoticeConstants.RelatedUser.FOUNDER:
if (StringUtils.equals(NoticeConstants.Event.UPDATE, event)
|| StringUtils.equals(NoticeConstants.Event.DELETE, event)) {
toUserIds.addAll(relatedUsers);
}
break;
case NoticeConstants.RelatedUser.MAINTAINER:
if (StringUtils.equals(NoticeConstants.Event.COMMENT, event)) {
toUserIds.addAll(relatedUsers);
}
break;
default:
toUserIds.add(userId);
break;
}
}
return toUserIds;
}
}

View File

@ -0,0 +1,51 @@
package io.dataease.notice.sender;
import lombok.Builder;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
@Builder
public class NoticeModel {
/**
* 保存 测试id
*/
private String testId;
/**
* 保存状态
*/
private String status;
/**
* Event
*/
private String event;
/**
* 消息主题
*/
private String subject;
/**
* 消息内容
*/
private String context;
private String successContext;
private String failedContext;
/**
* html 消息模版
*/
private String mailTemplate;
private String failedMailTemplate;
private String successMailTemplate;
/**
* 保存特殊的用户
*/
private List<String> relatedUsers;
/**
* 模版里的参数信息
*/
private Map<String, Object> paramMap;
}

View File

@ -0,0 +1,9 @@
package io.dataease.notice.sender;
import io.dataease.notice.domain.MessageDetail;
import org.springframework.scheduling.annotation.Async;
public interface NoticeSender {
@Async
void send(MessageDetail messageDetail, NoticeModel noticeModel);
}

View File

@ -0,0 +1,47 @@
package io.dataease.notice.sender.impl;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.taobao.api.ApiException;
import io.dataease.commons.utils.LogUtil;
import io.dataease.notice.domain.MessageDetail;
import io.dataease.notice.sender.AbstractNoticeSender;
import io.dataease.notice.sender.NoticeModel;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class DingNoticeSender extends AbstractNoticeSender {
public void sendNailRobot(MessageDetail messageDetail, String context) {
List<String> userIds = messageDetail.getUserIds();
if (CollectionUtils.isEmpty(userIds)) {
return;
}
DingTalkClient client = new DefaultDingTalkClient(messageDetail.getWebhook());
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype("text");
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
text.setContent(context);
request.setText(text);
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
List<String> phoneList = super.getUserPhones(userIds);
LogUtil.info("收件人地址: " + phoneList);
at.setAtMobiles(phoneList);
request.setAt(at);
try {
client.execute(request);
} catch (ApiException e) {
LogUtil.error(e.getMessage(), e);
}
}
@Override
public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getContext(messageDetail, noticeModel);
sendNailRobot(messageDetail, context);
}
}

View File

@ -0,0 +1,50 @@
package io.dataease.notice.sender.impl;
import io.dataease.commons.utils.LogUtil;
import io.dataease.notice.domain.MessageDetail;
import io.dataease.notice.sender.AbstractNoticeSender;
import io.dataease.notice.sender.NoticeModel;
import io.dataease.notice.service.MailService;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.List;
@Component
public class MailNoticeSender extends AbstractNoticeSender {
@Resource
private MailService mailService;
private void sendMail(MessageDetail messageDetail, String context, NoticeModel noticeModel) throws MessagingException {
LogUtil.info("发送邮件开始 ");
JavaMailSenderImpl javaMailSender = mailService.getMailSender();
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(javaMailSender.getUsername());
LogUtil.info("发件人地址"+javaMailSender.getUsername());
LogUtil.info("helper"+helper);
helper.setSubject("MeterSphere " + noticeModel.getSubject());
List<String> emails = super.getUserEmails(messageDetail.getUserIds());
String[] users = emails.toArray(new String[0]);
LogUtil.info("收件人地址: " + emails);
helper.setText(context, true);
helper.setTo(users);
javaMailSender.send(mimeMessage);
}
@Override
public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getHtmlContext(messageDetail, noticeModel);
try {
sendMail(messageDetail, context, noticeModel);
LogUtil.info("发送邮件结束");
} catch (Exception e) {
LogUtil.error(e);
}
}
}

View File

@ -0,0 +1,39 @@
package io.dataease.notice.sender.impl;
import io.dataease.notice.sender.AbstractNoticeSender;
import io.dataease.commons.utils.LogUtil;
import io.dataease.notice.domain.MessageDetail;
import io.dataease.notice.message.TextMessage;
import io.dataease.notice.sender.NoticeModel;
import io.dataease.notice.util.WxChatbotClient;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.List;
@Component
public class WeComNoticeSender extends AbstractNoticeSender {
public void sendWechatRobot(MessageDetail messageDetail, String context) {
List<String> userIds = messageDetail.getUserIds();
if (CollectionUtils.isEmpty(userIds)) {
return;
}
TextMessage message = new TextMessage(context);
List<String> phoneLists = super.getUserPhones(userIds);
message.setMentionedMobileList(phoneLists);
try {
WxChatbotClient.send(messageDetail.getWebhook(), message);
} catch (IOException e) {
LogUtil.error(e.getMessage(), e);
}
}
@Override
public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getContext(messageDetail, noticeModel);
sendWechatRobot(messageDetail, context);
}
}

View File

@ -0,0 +1,79 @@
package io.dataease.notice.service;
import io.dataease.base.domain.SystemParameter;
import io.dataease.commons.constants.ParamConstants;
import io.dataease.commons.utils.EncryptUtils;
import io.dataease.service.system.SystemParameterService;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.Properties;
@Service
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class MailService {
@Resource
private SystemParameterService systemParameterService;
public JavaMailSenderImpl getMailSender() {
Properties props = new Properties();
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
List<SystemParameter> paramList = systemParameterService.getParamList(ParamConstants.Classify.MAIL.getValue());
javaMailSender.setDefaultEncoding("UTF-8");
javaMailSender.setProtocol("smtp");
props.put("mail.smtp.auth", "true");
for (SystemParameter p : paramList) {
switch (p.getParamKey()) {
case "smtp.host":
javaMailSender.setHost(p.getParamValue());
break;
case "smtp.port":
javaMailSender.setPort(Integer.parseInt(p.getParamValue()));
break;
case "smtp.account":
javaMailSender.setUsername(p.getParamValue());
break;
case "smtp.password":
javaMailSender.setPassword(EncryptUtils.aesDecrypt(p.getParamValue()).toString());
break;
case "smtp.ssl":
if (BooleanUtils.toBoolean(p.getParamValue())) {
javaMailSender.setProtocol("smtps");
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
}
break;
case "smtp.tls":
String result = BooleanUtils.toString(BooleanUtils.toBoolean(p.getParamValue()), "true", "false");
props.put("mail.smtp.starttls.enable", result);
props.put("mail.smtp.starttls.required", result);
break;
/* case "smtp.anon":
boolean isAnon = BooleanUtils.toBoolean(p.getParamValue());
if (isAnon) {
props.put("mail.smtp.auth", "false");
javaMailSender.setUsername(null);
javaMailSender.setPassword(null);
}
break;*/
default:
break;
}
}
props.put("mail.smtp.timeout", "30000");
props.put("mail.smtp.connectiontimeout", "5000");
javaMailSender.setJavaMailProperties(props);
return javaMailSender;
}
}

View File

@ -0,0 +1,65 @@
package io.dataease.notice.service;
import com.alibaba.nacos.client.utils.StringUtils;
import io.dataease.commons.constants.NoticeConstants;
import io.dataease.notice.domain.MessageDetail;
import io.dataease.notice.sender.NoticeModel;
import io.dataease.notice.sender.NoticeSender;
import io.dataease.notice.sender.impl.DingNoticeSender;
import io.dataease.notice.sender.impl.MailNoticeSender;
import io.dataease.notice.sender.impl.WeComNoticeSender;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Component
public class NoticeSendService {
@Resource
private MailNoticeSender mailNoticeSender;
@Resource
private WeComNoticeSender weComNoticeSender;
@Resource
private DingNoticeSender dingNoticeSender;
@Resource
private NoticeService noticeService;
private NoticeSender getNoticeSender(MessageDetail messageDetail) {
NoticeSender noticeSender = null;
switch (messageDetail.getType()) {
case NoticeConstants.Type.EMAIL:
noticeSender = mailNoticeSender;
break;
case NoticeConstants.Type.WECHAT_ROBOT:
noticeSender = weComNoticeSender;
break;
case NoticeConstants.Type.NAIL_ROBOT:
noticeSender = dingNoticeSender;
break;
default:
break;
}
return noticeSender;
}
public void send(String taskType, NoticeModel noticeModel) {
List<MessageDetail> messageDetails;
switch (taskType) {
case NoticeConstants.Mode.API:
messageDetails = noticeService.searchMessageByType(NoticeConstants.TaskType.JENKINS_TASK);
break;
case NoticeConstants.Mode.SCHEDULE:
messageDetails = noticeService.searchMessageByTestId(noticeModel.getTestId());
break;
default:
messageDetails = noticeService.searchMessageByType(taskType);
break;
}
messageDetails.forEach(messageDetail -> {
if (StringUtils.equals(messageDetail.getEvent(), noticeModel.getEvent())) {
this.getNoticeSender(messageDetail).send(messageDetail, noticeModel);
}
});
}
}

View File

@ -0,0 +1,160 @@
package io.dataease.notice.service;
import io.dataease.base.domain.MessageTask;
import io.dataease.base.domain.MessageTaskExample;
import io.dataease.base.mapper.MessageTaskMapper;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.user.SessionUser;
import io.dataease.commons.utils.SessionUtils;
import io.dataease.i18n.Translator;
import io.dataease.notice.domain.MessageDetail;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class NoticeService {
@Resource
private MessageTaskMapper messageTaskMapper;
public void saveMessageTask(MessageDetail messageDetail) {
MessageTaskExample example = new MessageTaskExample();
example.createCriteria().andIdentificationEqualTo(messageDetail.getIdentification());
List<MessageTask> messageTaskLists = messageTaskMapper.selectByExample(example);
if (messageTaskLists.size() > 0) {
delMessage(messageDetail.getIdentification());
}
SessionUser user = SessionUtils.getUser();
String orgId = user.getLastOrganizationId();
long time = System.currentTimeMillis();
String identification = messageDetail.getIdentification();
if (StringUtils.isBlank(identification)) {
identification = UUID.randomUUID().toString();
}
for (String userId : messageDetail.getUserIds()) {
checkUserIdExist(userId, messageDetail, orgId);
MessageTask messageTask = new MessageTask();
messageTask.setId(UUID.randomUUID().toString());
messageTask.setEvent(messageDetail.getEvent());
messageTask.setTaskType(messageDetail.getTaskType());
messageTask.setUserId(userId);
messageTask.setType(messageDetail.getType());
messageTask.setWebhook(messageDetail.getWebhook());
messageTask.setIdentification(identification);
messageTask.setIsSet(false);
messageTask.setOrganizationId(orgId);
messageTask.setTestId(messageDetail.getTestId());
messageTask.setCreateTime(time);
setTemplate(messageDetail, messageTask);
messageTaskMapper.insert(messageTask);
}
}
private void setTemplate(MessageDetail messageDetail, MessageTask messageTask) {
if (StringUtils.isNotBlank(messageDetail.getTemplate())) {
messageTask.setTemplate(messageDetail.getTemplate());
}
}
private void checkUserIdExist(String userId, MessageDetail list, String orgId) {
MessageTaskExample example = new MessageTaskExample();
if (StringUtils.isBlank(list.getTestId())) {
example.createCriteria()
.andUserIdEqualTo(userId)
.andEventEqualTo(list.getEvent())
.andTypeEqualTo(list.getType())
.andTaskTypeEqualTo(list.getTaskType())
.andWebhookEqualTo(list.getWebhook())
.andOrganizationIdEqualTo(orgId);
} else {
example.createCriteria()
.andUserIdEqualTo(userId)
.andEventEqualTo(list.getEvent())
.andTypeEqualTo(list.getType())
.andTaskTypeEqualTo(list.getTaskType())
.andWebhookEqualTo(list.getWebhook())
.andTestIdEqualTo(list.getTestId())
.andOrganizationIdEqualTo(orgId);
}
if (messageTaskMapper.countByExample(example) > 0) {
DEException.throwException(Translator.get("message_task_already_exists"));
}
}
public List<MessageDetail> searchMessageByTestId(String testId) {
MessageTaskExample example = new MessageTaskExample();
example.createCriteria().andTestIdEqualTo(testId);
List<MessageTask> messageTaskLists = messageTaskMapper.selectByExampleWithBLOBs(example);
List<MessageDetail> scheduleMessageTask = new ArrayList<>();
Map<String, List<MessageTask>> MessageTaskMap = messageTaskLists.stream().collect(Collectors.groupingBy(MessageTask::getIdentification));
MessageTaskMap.forEach((k, v) -> {
MessageDetail messageDetail = getMessageDetail(v);
scheduleMessageTask.add(messageDetail);
});
scheduleMessageTask.sort(Comparator.comparing(MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed());
return scheduleMessageTask;
}
public List<MessageDetail> searchMessageByType(String type) {
SessionUser user = SessionUtils.getUser();
String orgId = user.getLastOrganizationId();
List<MessageDetail> messageDetails = new ArrayList<>();
MessageTaskExample example = new MessageTaskExample();
example.createCriteria()
.andTaskTypeEqualTo(type)
.andOrganizationIdEqualTo(orgId);
List<MessageTask> messageTaskLists = messageTaskMapper.selectByExampleWithBLOBs(example);
Map<String, List<MessageTask>> messageTaskMap = messageTaskLists.stream()
.collect(Collectors.groupingBy(NoticeService::fetchGroupKey));
messageTaskMap.forEach((k, v) -> {
MessageDetail messageDetail = getMessageDetail(v);
messageDetails.add(messageDetail);
});
return messageDetails.stream()
.sorted(Comparator.comparing(MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed())
.collect(Collectors.toList())
.stream()
.distinct()
.collect(Collectors.toList());
}
private MessageDetail getMessageDetail(List<MessageTask> messageTasks) {
Set<String> userIds = new HashSet<>();
MessageDetail messageDetail = new MessageDetail();
for (MessageTask m : messageTasks) {
userIds.add(m.getUserId());
messageDetail.setEvent(m.getEvent());
messageDetail.setTaskType(m.getTaskType());
messageDetail.setWebhook(m.getWebhook());
messageDetail.setIdentification(m.getIdentification());
messageDetail.setType(m.getType());
messageDetail.setIsSet(m.getIsSet());
messageDetail.setCreateTime(m.getCreateTime());
messageDetail.setTemplate(m.getTemplate());
}
if (CollectionUtils.isNotEmpty(userIds)) {
messageDetail.setUserIds(new ArrayList<>(userIds));
}
return messageDetail;
}
private static String fetchGroupKey(MessageTask messageTask) {
return messageTask.getTaskType() + "#" + messageTask.getIdentification();
}
public int delMessage(String identification) {
MessageTaskExample example = new MessageTaskExample();
example.createCriteria().andIdentificationEqualTo(identification);
return messageTaskMapper.deleteByExample(example);
}
}

View File

@ -0,0 +1,47 @@
package io.dataease.notice.util;
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
public class SendResult {
private boolean isSuccess;
private Integer errorCode;
private String errorMsg;
public boolean isSuccess() {
return isSuccess;
}
public void setIsSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
public Integer getErrorCode() {
return errorCode;
}
public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public String toString() {
Map<String, Object> items = new HashMap<String, Object>();
items.put("errorCode", errorCode);
items.put("errorMsg", errorMsg);
items.put("isSuccess", isSuccess);
return JSON.toJSONString(items);
}
}

View File

@ -0,0 +1,50 @@
package io.dataease.notice.util;
import com.alibaba.fastjson.JSONObject;
import io.dataease.notice.message.Message;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
/**
*
*/
public class WxChatbotClient {
static HttpClient httpclient = HttpClients.createDefault();
public static SendResult send(String webhook, Message message) throws IOException {
if (StringUtils.isBlank(webhook)) {
return new SendResult();
}
HttpPost httppost = new HttpPost(webhook);
httppost.addHeader("Content-Type", "application/json; charset=utf-8");
StringEntity se = new StringEntity(message.toJsonString(), "utf-8");
httppost.setEntity(se);
SendResult sendResult = new SendResult();
HttpResponse response = httpclient.execute(httppost);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(response.getEntity());
JSONObject obj = JSONObject.parseObject(result);
Integer errcode = obj.getInteger("errcode");
sendResult.setErrorCode(errcode);
sendResult.setErrorMsg(obj.getString("errmsg"));
sendResult.setIsSuccess(errcode.equals(0));
}
return sendResult;
}
}

View File

@ -48,15 +48,19 @@ public class BaseDisplayService {
if (bytes == null) {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader());
switch (imageName) {
case "favicon":
bytes = IOUtils.toByteArray(resolver.getResources("/static/img/favicon.ico")[0].getInputStream());
contentType = MediaType.valueOf("image/vnd.microsoft.icon");
break;
case "logo":
bytes = IOUtils.toByteArray(resolver.getResources("/static/img/logo-light-MeterSphere.*.svg")[0].getInputStream());
bytes = IOUtils.toByteArray(resolver.getResources("/static/img/logo-light-MeterSphere*.svg")[0].getInputStream());
contentType = MediaType.valueOf("image/svg+xml");
break;
case "loginImage":
bytes = IOUtils.toByteArray(resolver.getResources("/static/img/info.*.png")[0].getInputStream());
bytes = IOUtils.toByteArray(resolver.getResources("/static/img/info*.png")[0].getInputStream());
break;
case "loginLogo":
bytes = IOUtils.toByteArray(resolver.getResources("/static/img/logo-dark-MeterSphere.*.svg")[0].getInputStream());
bytes = IOUtils.toByteArray(resolver.getResources("/static/img/logo-dark-MeterSphere*.svg")[0].getInputStream());
contentType = MediaType.valueOf("image/svg+xml");
break;
default:

View File

@ -85,9 +85,13 @@ public class FileService {
}
public FileMetadata saveFile(MultipartFile file) {
return saveFile(file,file.getOriginalFilename());
}
public FileMetadata saveFile(MultipartFile file,String originalFilename) {
final FileMetadata fileMetadata = new FileMetadata();
fileMetadata.setId(UUID.randomUUID().toString());
fileMetadata.setName(file.getOriginalFilename());
fileMetadata.setName(originalFilename);
fileMetadata.setSize(file.getSize());
fileMetadata.setCreateTime(System.currentTimeMillis());
fileMetadata.setUpdateTime(System.currentTimeMillis());

View File

@ -23,6 +23,7 @@ import io.dataease.controller.request.organization.QueryOrgMemberRequest;
import io.dataease.dto.UserDTO;
import io.dataease.dto.UserRoleDTO;
import io.dataease.i18n.Translator;
import io.dataease.notice.domain.UserDetail;
import io.dataease.security.MsUserToken;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
@ -63,6 +64,15 @@ public class UserService {
@Resource
private WorkspaceService workspaceService;
public List<UserDetail> queryTypeByIds(List<String> userIds) {
return extUserMapper.queryTypeByIds(userIds);
}
public Map<String, User> queryNameByIds(List<String> userIds) {
return extUserMapper.queryNameByIds(userIds);
}
public UserDTO insert(UserRequest user) {
checkUserParam(user);
//

View File

@ -0,0 +1,269 @@
package io.dataease.service.system;
import com.alibaba.fastjson.JSON;
import com.google.gson.JsonObject;
import io.dataease.base.domain.FileMetadata;
import io.dataease.base.domain.SystemParameter;
import io.dataease.base.domain.SystemParameterExample;
import io.dataease.base.mapper.FileContentMapper;
import io.dataease.base.mapper.FileMetadataMapper;
import io.dataease.base.mapper.SystemParameterMapper;
import io.dataease.base.mapper.ext.ExtSystemParameterMapper;
import io.dataease.commons.constants.ParamConstants;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.utils.BeanUtils;
import io.dataease.commons.utils.EncryptUtils;
import io.dataease.commons.utils.LogUtil;
import io.dataease.dto.BaseSystemConfigDTO;
import io.dataease.dto.SystemParameterDTO;
import io.dataease.i18n.Translator;
import io.dataease.notice.domain.MailInfo;
import io.dataease.service.FileService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileStore;
import java.time.Instant;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
public class SystemParameterService {
@Resource
private SystemParameterMapper systemParameterMapper;
@Resource
private ExtSystemParameterMapper extSystemParameterMapper;
@Resource
private FileService fileService;
public String searchEmail() {
return extSystemParameterMapper.email();
}
public String getSystemLanguage() {
String result = StringUtils.EMPTY;
SystemParameterExample example = new SystemParameterExample();
example.createCriteria().andParamKeyEqualTo(ParamConstants.I18n.LANGUAGE.getValue());
List<SystemParameter> list = systemParameterMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(list)) {
String value = list.get(0).getParamValue();
if (StringUtils.isNotBlank(value)) {
result = value;
}
}
return result;
}
public void editMail(List<SystemParameter> parameters) {
List<SystemParameter> paramList = this.getParamList(ParamConstants.Classify.MAIL.getValue());
boolean empty = paramList.size() <= 0;
parameters.forEach(parameter -> {
SystemParameterExample example = new SystemParameterExample();
if (parameter.getParamKey().equals(ParamConstants.MAIL.PASSWORD.getValue())) {
if (!StringUtils.isBlank(parameter.getParamValue())) {
String string = EncryptUtils.aesEncrypt(parameter.getParamValue()).toString();
parameter.setParamValue(string);
}
}
example.createCriteria().andParamKeyEqualTo(parameter.getParamKey());
if (systemParameterMapper.countByExample(example) > 0) {
systemParameterMapper.updateByPrimaryKey(parameter);
} else {
systemParameterMapper.insert(parameter);
}
example.clear();
});
}
public List<SystemParameter> getParamList(String type) {
SystemParameterExample example = new SystemParameterExample();
example.createCriteria().andParamKeyLike(type + "%");
return systemParameterMapper.selectByExample(example);
}
public void testConnection(HashMap<String, String> hashMap) {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setDefaultEncoding("UTF-8");
javaMailSender.setHost(hashMap.get(ParamConstants.MAIL.SERVER.getValue()));
javaMailSender.setPort(Integer.valueOf(hashMap.get(ParamConstants.MAIL.PORT.getValue())));
javaMailSender.setUsername(hashMap.get(ParamConstants.MAIL.ACCOUNT.getValue()));
javaMailSender.setPassword(hashMap.get(ParamConstants.MAIL.PASSWORD.getValue()));
Properties props = new Properties();
String recipients = hashMap.get(ParamConstants.MAIL.RECIPIENTS.getValue());
if (BooleanUtils.toBoolean(hashMap.get(ParamConstants.MAIL.SSL.getValue()))) {
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
}
if (BooleanUtils.toBoolean(hashMap.get(ParamConstants.MAIL.TLS.getValue()))) {
props.put("mail.smtp.starttls.enable", "true");
}
props.put("mail.smtp.timeout", "30000");
props.put("mail.smtp.connectiontimeout", "5000");
javaMailSender.setJavaMailProperties(props);
try {
javaMailSender.testConnection();
} catch (MessagingException e) {
LogUtil.error(e.getMessage(), e);
DEException.throwException(Translator.get("connection_failed"));
}
if(!StringUtils.isBlank(recipients)){
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = null;
try {
helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(javaMailSender.getUsername());
helper.setSubject("MeterSphere测试邮件 " );
helper.setText("这是一封测试邮件,邮件发送成功", true);
helper.setTo(recipients);
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
LogUtil.error(e.getMessage(), e);
DEException.throwException(Translator.get("connection_failed"));
}
}
}
public String getVersion() {
return System.getenv("MS_VERSION");
}
public MailInfo mailInfo(String type) {
List<SystemParameter> paramList = this.getParamList(type);
MailInfo mailInfo=new MailInfo ();
if (!CollectionUtils.isEmpty(paramList)) {
for (SystemParameter param : paramList) {
if (StringUtils.equals(param.getParamKey(),ParamConstants.MAIL.SERVER.getValue() )) {
mailInfo.setHost(param.getParamValue());
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.PORT.getValue())) {
mailInfo.setPort(param.getParamValue());
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.ACCOUNT.getValue())) {
mailInfo.setAccount(param.getParamValue());
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.PASSWORD.getValue())) {
String password = EncryptUtils.aesDecrypt(param.getParamValue()).toString();
mailInfo.setPassword(password);
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.SSL.getValue())) {
mailInfo.setSsl(param.getParamValue());
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.TLS.getValue())) {
mailInfo.setTls(param.getParamValue());
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.RECIPIENTS.getValue())) {
mailInfo.setRecipient(param.getParamValue());
}
}
}
return mailInfo;
}
public void saveLdap(List<SystemParameter> parameters) {
SystemParameterExample example = new SystemParameterExample();
parameters.forEach(param -> {
if (param.getParamKey().equals(ParamConstants.LDAP.PASSWORD.getValue())) {
String string = EncryptUtils.aesEncrypt(param.getParamValue()).toString();
param.setParamValue(string);
}
example.createCriteria().andParamKeyEqualTo(param.getParamKey());
if (systemParameterMapper.countByExample(example) > 0) {
systemParameterMapper.updateByPrimaryKey(param);
} else {
systemParameterMapper.insert(param);
}
example.clear();
});
}
public String getValue(String key) {
SystemParameter param = systemParameterMapper.selectByPrimaryKey(key);
if (param == null) {
return null;
}
return param.getParamValue();
}
public List<SystemParameterDTO> getSystemParameterInfo(String paramConstantsType) {
List<SystemParameter> paramList = this.getParamList(paramConstantsType);
List<SystemParameterDTO> dtoList = new ArrayList<>();
for (SystemParameter systemParameter : paramList) {
SystemParameterDTO systemParameterDTO = new SystemParameterDTO();
BeanUtils.copyBean(systemParameterDTO, systemParameter);
if (systemParameter.getType().equalsIgnoreCase("file")) {
FileMetadata fileMetadata = fileService.getFileMetadataById(systemParameter.getParamValue());
if (fileMetadata != null) {
systemParameterDTO.setFileName(fileMetadata.getName());
}
}
dtoList.add(systemParameterDTO);
}
dtoList.sort(Comparator.comparingInt(SystemParameter::getSort));
return dtoList;
}
public void saveUIInfo(Map<String,List<SystemParameterDTO>> request, List<MultipartFile> bodyFiles) throws IOException {
List<SystemParameterDTO> parameters = request.get("systemParams");
for (MultipartFile multipartFile : bodyFiles) {
if (!multipartFile.isEmpty()) {
//防止添加非图片文件
try (InputStream input = multipartFile.getInputStream()) {
try {
// It's an image (only BMP, GIF, JPG and PNG are recognized).
ImageIO.read(input).toString();
} catch (Exception e) {
DEException.throwException("Uploaded images do not meet the image format requirements");
return;
}
}
String multipartFileName = multipartFile.getOriginalFilename();
String[] split = Objects.requireNonNull(multipartFileName).split(",");
parameters.stream().filter(systemParameterDTO -> systemParameterDTO.getParamKey().equalsIgnoreCase(split[1])).forEach(systemParameterDTO -> {
systemParameterDTO.setFileName(split[0]);
systemParameterDTO.setFile(multipartFile);
});
}
}
for (SystemParameterDTO systemParameter : parameters) {
MultipartFile file = systemParameter.getFile();
if (systemParameter.getType().equalsIgnoreCase("file")) {
if (StringUtils.isBlank(systemParameter.getFileName())) {
fileService.deleteFileById(systemParameter.getParamValue());
}
if (file != null) {
fileService.deleteFileById(systemParameter.getParamValue());
FileMetadata fileMetadata = fileService.saveFile(systemParameter.getFile(),systemParameter.getFileName());
systemParameter.setParamValue(fileMetadata.getId());
}
if (file == null && systemParameter.getFileName() == null) {
systemParameter.setParamValue(null);
}
}
systemParameterMapper.deleteByPrimaryKey(systemParameter.getParamKey());
systemParameterMapper.insert(systemParameter);
}
}
public static void main(String[] args) {
String info="[{\"paramKey\":\"base.url\",\"paramValue\":null,\"type\":\"text\",\"sort\":1,\"file\":null,\"fileName\":null},{\"paramKey\":\"base.title\",\"paramValue\":\"DataEase Title\",\"type\":\"text\",\"sort\":3,\"file\":null,\"fileName\":null},{\"paramKey\":\"base.logo\",\"paramValue\":\"DataEase\",\"type\":\"text\",\"sort\":4,\"file\":null,\"fileName\":\"favicon.icon.png\"}]";
List<SystemParameterDTO> temp = JSON.parseArray(info,SystemParameterDTO.class);
System.out.println("===>");
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -32,11 +32,11 @@ export default {
// component: () => import('@/business/components/settings/system/TestResourcePool'),
// meta: {system: true, title: 'commons.test_resource_pool'}
// },
// {
// path: 'systemparametersetting',
// component: () => import('@/business/components/settings/system/SystemParameterSetting'),
// meta: {system: true, title: 'commons.system_parameter_setting'}
// },
{
path: 'systemparametersetting',
component: () => import('@/business/components/settings/system/SystemParameterSetting'),
meta: {system: true, title: 'commons.system_parameter_setting'}
},
...requireContext.keys().map(key => requireContext(key).system),
...requireContext.keys().map(key => requireContext(key).license),
{

View File

@ -1,19 +1,45 @@
<template>
<div v-loading="result.loading">
<el-form :model="formInline" :rules="rules" ref="formInline" class="demo-form-inline"
{{systemParams}}
<el-form ref="systemParams" class="demo-form-inline"
:disabled="show" v-loading="loading" size="small">
<el-row>
<el-col>
<el-form-item :label="$t('system_config.base.url')" prop="url">
<el-input v-model="formInline.url" :placeholder="$t('system_config.base.url_tip')"/>
<i>({{$t('commons.examples')}}:https://rdmetersphere.fit2cloud.com)</i>
<el-col v-for="(param,index) in systemParams" :key="index">
<!--logo upload-->
<el-form-item :label="$t('system_config.base.logo')"
v-if="param.paramKey==='base.logo'">
<el-upload style="float: left"
v-loading="result.loading"
class="upload-demo"
action=""
accept=".jpeg,.jpg,.png,.gif"
:on-exceed="handleExceed"
:beforeUpload="uploadValidate"
:on-error="handleError"
:show-file-list="false"
:file-list="filesTmp"
:http-request="uploadLogo">
<el-button style="display: inline-block" size="mini" type="success" plain>
{{ $t('commons.upload') }}
</el-button>
</el-upload>
<el-button style="float:left;margin-left: 10px;margin-top: 3px" size="mini" type="danger" plain
@click="removeValue('base.logo')">
{{ $t('commons.upload') }}
</el-button>
<el-input :disabled="true" v-model="param.fileName"
:placeholder="$t('system_config.base.logo_size')+'135px * 30px'"/>
</el-form-item>
<!--title-->
<el-form-item :label="$t('system_config.base.title')" v-if="param.paramKey==='base.title'">
<el-input v-model="param.paramValue" placeholder="egDateEase"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div>
<el-button @click="edit" v-if="showEdit" size="small">{{ $t('commons.edit') }}</el-button>
<el-button type="success" @click="save('formInline')" v-if="showSave" :disabled="disabledSave" size="small">
<el-button type="success" @click="save('systemParams')" v-if="showSave" :disabled="disabledSave" size="small">
{{ $t('commons.save') }}
</el-button>
<el-button @click="cancel" type="info" v-if="showCancel" size="small">{{ $t('commons.cancel') }}</el-button>
@ -22,84 +48,123 @@
</template>
<script>
import ElUploadList from "element-ui/packages/upload/src/upload-list";
export default {
name: "BaseSetting",
data() {
return {
formInline: {},
input: '',
visible: true,
result: {},
showEdit: true,
showSave: false,
showCancel: false,
show: true,
disabledConnection: false,
disabledSave: false,
loading: false,
rules: {
url: [
{
required: true,
message: this.$t('system_par'),
trigger: ['change', 'blur']
},
],
export default {
name: "BaseSetting",
data() {
return {
filesTmp: [],
suffixes: new Set(['png', 'jpg', 'gif', 'jpeg']),
files: [],
systemParams: [],
systemParamsOld: [],
input: '',
visible: true,
result: {},
showEdit: true,
showSave: false,
showCancel: false,
show: true,
disabledConnection: false,
disabledSave: false,
loading: false,
rules: {
url: [
{
required: true,
message: 'Not Null',
trigger: ['change', 'blur']
},
],
}
}
}
},
created() {
this.query()
},
methods: {
query() {
this.result = this.$get("/system/base/info", response => {
this.formInline = response.data;
this.$nextTick(() => {
this.$refs.formInline.clearValidate();
},
created() {
this.query()
},
methods: {
query() {
this.result = this.$get("/system/base/info", response => {
debugger;
this.systemParams = response.data;
})
})
},
edit() {
this.showEdit = false;
this.showSave = true;
this.showCancel = true;
this.show = false;
},
save(formInline) {
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
let param = [
{paramKey: "base.url", paramValue: this.formInline.url, type: "text", sort: 1},
];
},
edit() {
this.showEdit = false;
this.showSave = true;
this.showCancel = true;
this.show = false;
},
save() {
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
this.systemParams.forEach((param) => {
if (param.file !== null) {
let file = param.file;
let name = file.name + "," + param.paramKey;
let newfile = new File([file], name, {type: file.type});
this.files.push(newfile);
param.file = null;
}
});
this.$refs[formInline].validate(valid => {
if (valid) {
this.result = this.$post("/system/save/base", param, response => {
if (response.success) {
this.$success(this.$t('commons.save_success'));
} else {
this.$message.error(this.$t('commons.save_failed'));
}
});
} else {
this.result = this.$fileUpload("/system/save/base", null, this.files, {"systemParams": this.systemParams}, response => {
if (response.success) {
this.query();//
this.$success(this.$t('commons.save_success'));
} else {
this.$message.error(this.$t('commons.save_failed'));
}
});
},
cancel() {
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
this.query();
},
handleExceed(files, fileList) {
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
},
handleError() {
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
},
uploadValidate(file) {
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
if (!this.suffixes.has(suffix)) {
this.$warning(this.$t('test_track.case.import.upload_limit_format'));
return false;
}
})
},
cancel() {
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
this.query();
if (file.size / 1024 / 1024 > 5) {
this.$warning(this.$t('test_track.case.import.upload_limit_size'));
return false;
}
this.errList = [];
return true;
},
uploadLogo(file) {
this.systemParams.forEach((param) => {
if (param.paramKey === "base.logo") {
param.fileName = file.file.name;
param.file = file.file;
}
})
},
removeValue(paramKey) {
this.systemParams.forEach((param) => {
if (param.paramKey === paramKey) {
param.fileName = null;
param.file = null;
}
});
}
}
}
}
</script>
<style scoped>
@ -108,4 +173,10 @@ export default {
min-height: 300px;
}
.inline-block {
display: inline-block;
position: absolute;
left: 105px;
}
</style>

View File

@ -2,21 +2,15 @@
<el-card>
<el-tabs class="system-setting" v-model="activeName">
<el-tab-pane :label="$t('system_config.base_config')" name="base">
<base-setting/>
<!-- <el-tab-pane :label="$t('system_config.base_config')" name="base">-->
<!-- <base-setting/>-->
<!-- </el-tab-pane>-->
<el-tab-pane :label="$t('display.title')" name="ui">
<ui-setting/>
</el-tab-pane>
<el-tab-pane :label="$t('system_parameter_setting.mailbox_service_settings')" name="email">
<email-setting/>
</el-tab-pane>
<el-tab-pane :label="$t('system_parameter_setting.ldap_setting')" name="ldap">
<ldap-setting/>
</el-tab-pane>
<el-tab-pane v-if="hasLicense()" :label="$t('display.title')" name="display">
<ms-display/>
</el-tab-pane>
<el-tab-pane v-if="hasLicense()" :label="$t('auth_source.title')" name="auth">
<ms-auth/>
</el-tab-pane>
</el-tabs>
</el-card>
</template>
@ -24,6 +18,7 @@
<script>
import EmailSetting from "./EmailSetting";
import LdapSetting from "./LdapSetting";
import UiSetting from "./UiSetting";
import BaseSetting from "./BaseSetting";
import {hasLicense} from '@/common/js/utils';
@ -35,6 +30,7 @@ export default {
name: "SystemParameterSetting",
components: {
BaseSetting,
UiSetting,
EmailSetting,
LdapSetting,
"MsDisplay": display.default,
@ -42,7 +38,7 @@ export default {
},
data() {
return {
activeName: 'base',
activeName: 'ui',
}
},
methods: {

View File

@ -0,0 +1,265 @@
<template>
<div v-loading="result.loading">
<el-form ref="systemParams" class="demo-form-inline"
:disabled="show" v-loading="loading" size="small">
<el-row>
<el-col v-for="(param,index) in systemParams" :key="index">
<!--logo upload-->
<el-form-item :label="$t('display.logo')"
v-if="param.paramKey==='ui.logo'">
<el-upload style="float: right;margin-left: 10px"
v-loading="result.loading"
class="upload-demo"
action=""
accept=".jpeg,.jpg,.png,.gif"
:on-exceed="handleExceed"
:beforeUpload="uploadValidate"
:on-error="handleError"
:show-file-list="false"
:file-list="filesTmp"
:http-request="uploadLogo">
<el-button style="display: inline-block" size="mini" type="success" plain>
{{ $t('commons.upload') }}
</el-button>
</el-upload>
<el-button style="float:right;margin-top: 3px" size="mini" type="danger" plain
@click="removeValue('ui.logo')">
{{ $t('commons.clear') }}
</el-button>
<el-input :disabled="true" v-model="param.fileName"
:placeholder="$t('display.advice_size')+'135px * 30px'"/>
</el-form-item>
<!--logo upload-->
<el-form-item :label="$t('display.loginImage')"
v-if="param.paramKey==='ui.loginImage'">
<el-upload style="float: right;margin-left: 10px"
v-loading="result.loading"
class="upload-demo"
action=""
accept=".jpeg,.jpg,.png,.gif"
:on-exceed="handleExceed"
:beforeUpload="uploadValidate"
:on-error="handleError"
:show-file-list="false"
:file-list="filesTmp"
:http-request="uploadLoginImage">
<el-button style="display: inline-block" size="mini" type="success" plain>
{{ $t('commons.upload') }}
</el-button>
</el-upload>
<el-button style="float:right;margin-top: 3px" size="mini" type="danger" plain
@click="removeValue('ui.loginImage')">
{{ $t('commons.clear') }}
</el-button>
<el-input :disabled="true" v-model="param.fileName"
:placeholder="$t('display.advice_size')+'500px * 450px'"/>
</el-form-item>
<!--favicon upload-->
<el-form-item :label="$t('display.loginLogo')"
v-if="param.paramKey==='ui.loginLogo'">
<el-upload style="float: right;margin-left: 10px"
v-loading="result.loading"
class="upload-demo"
action=""
accept=".jpeg,.jpg,.png,.gif"
:on-exceed="handleExceed"
:beforeUpload="uploadValidate"
:on-error="handleError"
:show-file-list="false"
:file-list="filesTmp"
:http-request="uploadLoginLogo">
<el-button style="display: inline-block" size="mini" type="success" plain>
{{ $t('commons.upload') }}
</el-button>
</el-upload>
<el-button style="float:right;margin-top: 3px" size="mini" type="danger" plain
@click="removeValue('ui.loginLogo')">
{{ $t('commons.clear') }}
</el-button>
<el-input :disabled="true" v-model="param.fileName"
:placeholder="$t('display.advice_size')+'135px * 30px'"/>
</el-form-item>
<!--favicon upload-->
<el-form-item :label="$t('display.favicon')"
v-if="param.paramKey==='ui.favicon'">
<el-upload style="float: right;margin-left: 10px"
v-loading="result.loading"
class="upload-demo"
action=""
accept=".jpeg,.jpg,.png,.gif"
:on-exceed="handleExceed"
:beforeUpload="uploadValidate"
:on-error="handleError"
:show-file-list="false"
:file-list="filesTmp"
:http-request="uploadFavicon">
<el-button style="display: inline-block" size="mini" type="success" plain>
{{ $t('commons.upload') }}
</el-button>
</el-upload>
<el-button style="float:right;margin-top: 3px" size="mini" type="danger" plain
@click="removeValue('ui.favicon')">
{{ $t('commons.clear') }}
</el-button>
<el-input :disabled="true" v-model="param.fileName"
:placeholder="$t('display.advice_size')+'16px * 16px'"/>
</el-form-item>
<!--ui.loginTitle-->
<el-form-item :label="$t('display.loginTitle')" v-if="param.paramKey==='ui.loginTitle'">
<el-input v-model="param.paramValue" placeholder="egDateEase"/>
</el-form-item>
<!--ui.title-->
<el-form-item :label="$t('display.title')" v-if="param.paramKey==='ui.title'">
<el-input v-model="param.paramValue" placeholder="egDateEase"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div>
<el-button @click="edit" v-if="showEdit" size="small">{{ $t('commons.edit') }}</el-button>
<el-button type="success" @click="save" v-if="showSave" :disabled="disabledSave" size="small">
{{ $t('commons.save') }}
</el-button>
<el-button @click="cancel" type="info" v-if="showCancel" size="small">{{ $t('commons.cancel') }}</el-button>
</div>
</div>
</template>
<script>
import ElUploadList from "element-ui/packages/upload/src/upload-list";
export default {
name: "UiSetting",
data() {
return {
filesTmp: [],
suffixes: new Set(['png', 'jpg', 'gif', 'jpeg']),
files: [],
systemParams: [],
systemParamsOld: [],
input: '',
visible: true,
result: {},
showEdit: true,
showSave: false,
showCancel: false,
show: true,
disabledConnection: false,
disabledSave: false,
loading: false,
rules: {
url: [
{
required: true,
message: 'Not Null',
trigger: ['change', 'blur']
},
],
}
}
},
created() {
this.query()
},
methods: {
query() {
this.result = this.$get("/system/ui/info", response => {
debugger;
this.systemParams = response.data;
})
},
edit() {
this.showEdit = false;
this.showSave = true;
this.showCancel = true;
this.show = false;
},
save() {
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
this.systemParams.forEach((systemParam) => {
if (systemParam.file !== null) {
let file = systemParam.file;
let name = file.name + "," + systemParam.paramKey;
let newfile = new File([file], name, {type: file.type});
this.files.push(newfile);
systemParam.file = null;
}
});
this.result = this.$fileUpload("/system/save/ui", null, this.files, {"systemParams": this.systemParams}, response => {
if (response.success) {
this.query();//
this.$success(this.$t('commons.save_success'));
} else {
this.$message.error(this.$t('commons.save_failed'));
}
});
},
cancel() {
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
this.query();
},
handleExceed(files, fileList) {
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
},
handleError() {
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
},
uploadValidate(file) {
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
if (!this.suffixes.has(suffix)) {
this.$warning(this.$t('test_track.case.import.upload_limit_format'));
return false;
}
if (file.size / 1024 / 1024 > 5) {
this.$warning(this.$t('test_track.case.import.upload_limit_size'));
return false;
}
this.errList = [];
return true;
},
uploadLogo(file) {
this.upload(file,'ui.logo')
},
uploadFavicon(file) {
this.upload(file,'ui.favicon')
},
uploadLoginImage(file) {
this.upload(file,'ui.loginImage')
},
uploadLoginLogo(file) {
this.upload(file,'ui.loginLogo')
},
upload(file,paramKey) {
this.systemParams.forEach((systemParam) => {
if (systemParam.paramKey === paramKey) {
systemParam.fileName = file.file.name;
systemParam.file = file.file;
}
})
},
removeValue(paramKey) {
this.systemParams.forEach((systemParam) => {
if (systemParam.paramKey === paramKey) {
systemParam.fileName = null;
systemParam.file = null;
}
});
}
}
}
</script>
<style scoped>
.el-form {
min-height: 300px;
}
</style>

View File

@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="shortcut icon" href="<%= BASE_URL %>favicon.ico">
<link rel="shortcut icon" href="<%= BASE_URL %>test-favicon.ico">
<title>DataEase</title>
</head>
<body>

View File

@ -1,5 +1,6 @@
export default {
commons: {
upload:'Upload',
cover: 'Cover',
not_cover: 'Not Cover',
import_mode: 'Import mode',
@ -34,7 +35,7 @@ export default {
operating: 'Operating',
input_limit: 'Within {0} and {1} characters',
login: 'Sign In',
welcome: 'One-stop open source continuous testing platform',
welcome: 'One-stop open source data analysis platform',
username: 'Username',
password: 'Password',
input_username: 'Please enter username',
@ -216,12 +217,21 @@ export default {
loginImage: 'Picture on the right side of the login page',
loginTitle: 'Login page prompt information',
pageTitle: 'Page Title',
advice_size:"The recommended image size is ",
favicon:"Favicon",
},
system_config: {
base_config: 'Base Config',
base: {
url: 'Website URL',
url_tip: 'examplehttp://localhost:8081'
url_tip: 'examplehttp://localhost:8081',
logo: "System LOGO (displayed in the LOGO in the upper left corner of the system homepage)",
advice_size:"The recommended image size is ",
title:"Title (text displayed on browser tab page)",
favicon:"Favicon",
system_name:"System name (displayed in the system name in the upper left corner of the system home page)",
login_image: "Login page image (the image shown on the login page)",
login_name:"System name displayed on login page"
}
},
workspace: {

View File

@ -1,5 +1,6 @@
export default {
commons: {
upload:'上传',
cover: '覆盖',
not_cover: '不覆盖',
import_mode: '导入模式',
@ -35,7 +36,7 @@ export default {
operating: '操作',
input_limit: '长度在 {0} 到 {1} 个字符',
login: '登录',
welcome: '一站式开源持续测试平台',
welcome: '一站式开源数据分析平台',
username: '姓名',
password: '密码',
input_username: '请输入用户姓名',
@ -218,12 +219,21 @@ export default {
loginImage: '登陆页面右侧图片',
loginTitle: '登陆页面提示信息',
pageTitle: '页面 Title',
favicon:"Favicon浏览器Tab页上的小图标",
advice_size:"建议图片大小",
},
system_config: {
base_config: '基本配置',
base: {
url: '当前站点URL',
url_tip: '例如http://localhost:8081'
url_tip: '例如http://localhost:8081',
logo: "系统LOGO显示在系统主页左上角的LOGO",
advice_size:"建议图片大小",
title:"Title浏览器Tab页上的显示的文字",
favicon:"Favicon浏览器Tab页上的小图标",
system_name:"系统名称(显示在系统主页左上角的系统名称)",
login_image: "登录页图片(登录页中显示的图片)",
login_name:"登录页显示的系统名称"
}
},
workspace: {

View File

@ -1,5 +1,6 @@
export default {
commons: {
upload:'上传',
cover: '覆蓋',
not_cover: '不覆蓋',
import_mode: '導入模式',
@ -35,7 +36,7 @@ export default {
operating: '操作',
input_limit: '長度在 {0} 到 {1} 個字符',
login: '登錄',
welcome: '壹站式開源持續測試平臺',
welcome: '壹站式開源数据分析平臺',
username: '姓名',
password: '密碼',
input_username: '請輸入用戶姓名',
@ -217,12 +218,21 @@ export default {
loginImage: '登陸頁面右側圖片',
loginTitle: '登陸頁面提示信息',
pageTitle: '頁面 Title',
favicon:"Favicon瀏覽器Tab頁上的小圖標",
advice_size:"建議圖片大小",
},
system_config: {
base_config: '基本配置',
base: {
url: '當前站點URL',
url_tip: '例如http://localhost:8081'
url_tip: '例如http://localhost:8081',
logo: "系統LOGO顯示在系統主頁左上角的LOGO",
advice_size:"建議圖片大小",
title:"Title瀏覽器Tab頁上的顯示的文字",
favicon:"Favicon瀏覽器Tab頁上的小圖標",
system_name:"系統名稱(顯示在系統主頁左上角的系統名稱)",
login_image: "登錄頁圖片(登錄頁中顯示的圖片)",
login_name:"登錄頁顯示的系統名稱"
}
},
workspace: {

View File

@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="shortcut icon" href="<%= BASE_URL %>favicon.ico">
<link rel="shortcut icon" href="<%= BASE_URL %>display/file/favicon">
<title>DataEase</title>
</head>
<body>