Merge branch '于相涌/mail' into 于相涌/Lark
continuous-integration/drone/push Build is passing Details

pull/1/head
YXY 1 year ago
commit 7e848df561

@ -10,7 +10,8 @@ public enum AppType {
*
*/
MULTIDIMENSIONAL_TABLE("MULTIDIMENSIONAL_TABLE", "多维表格"),
APPROVAL_TASK("APPROVAL_TASK", "审批回调");
APPROVAL_TASK("APPROVAL_TASK", "审批回调"),
SYNC_EMAIL("SYNC_EMAIL", "同步邮箱");
private final String code;
private final String info;

@ -13,7 +13,8 @@ public enum EventOperateType {
CREATE("CREATE", "创建"),
UPDATE("UPDATE", "更新"),
DELETE("DELETE", "删除"),
STOP("STOP", "终止");
STOP("STOP", "终止"),
SYNC_MAIL("SYNC_MAIL", "同步邮件"),;
private final String code;
private final String info;

@ -12,7 +12,8 @@ public enum TableRelationTypeEnum {
*/
MAINTENANCE_ROW_RELATION("MAINTENANCE_ROW_RELATION", "维护表之间的字段关系"),
SINGLE_DIRECTION("SINGLE_DIRECTION", "单向传递"),
DOUBLE_DIRECTION("DOUBLE_DIRECTION", "双向传递");
DOUBLE_DIRECTION("DOUBLE_DIRECTION", "双向传递"),
SYNC_EMAIL("SYNC_EMAIL", "同步邮箱"),;
private String code;
private String info;

@ -57,7 +57,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
</dependencies>

@ -0,0 +1,25 @@
package com.ruoyi.flyingbook.domain;
import lombok.Data;
import java.io.Serializable;
/**
* lark_table_relation
*
* @author ruoyi
* @date 2023-03-15
*/
@Data
public class LarkCompanyTableInfo implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String appId;
private String appSecret;
private String fromAppToken;
private String fromTableId;
private String toAppToken;
private String toTableId;
}

@ -0,0 +1,44 @@
package com.ruoyi.flyingbook.domain;
import lombok.Data;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* @author ruoyi
* @date 2023-04-09
*/
@Data
public class MailInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private Long larkTableId;
/** 邮件服务器地址 */
private String mailServer;
/** 邮件服务器端口 */
private String mailPort;
/** 邮件服务器使用协议 */
private String mailProtocol;
/** 账号 */
private String mailUserName;
/** 邮箱授权码 */
private String mailAuthorizationCode;
/** 收件箱地址 */
private String mailReceiveFolder;
/** 邮件来源名称 */
private String sourceName;
/**
* @see com.ruoyi.common.enums.FlagStatus
*/
private Long flag;
}

@ -15,6 +15,8 @@ import java.util.List;
@AllArgsConstructor
public class LarkRequest {
private Long id;
private String appId;
private String appSecret;

@ -0,0 +1,145 @@
package com.ruoyi.flyingbook.mail;
import com.lark.oapi.service.bitable.v1.model.CreateAppTableRecordRespBody;
import com.ruoyi.common.enums.EventOperateType;
import com.ruoyi.flyingbook.LarkHelper.LarkTableHelper;
import com.ruoyi.flyingbook.domain.Event;
import com.ruoyi.flyingbook.domain.EventLog;
import com.ruoyi.flyingbook.domain.lark.LarkTableRequest;
import com.ruoyi.flyingbook.mail.request.MailRequest;
import com.ruoyi.flyingbook.mapper.EventLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author yuxiangyong
* @create 2023-04-09 20:27
*/
@Slf4j
public class MailHelper {
@Autowired
private LarkTableHelper larkTableHelper;
@Autowired
private EventLogMapper eventLogMapper;
protected void parseMsg(Message[] messages, LarkTableRequest add, MailRequest req) {
log.info("------------------------开始解析邮件----------------------------------");
/**
*
*/
List<EventLog> logs = new ArrayList<>();
for (Message message : messages) {
String msgSubject = null;
try {
log.info("----------------------------------------------------------");
String from = MimeUtility.decodeText(message.getFrom()[0].toString());
InternetAddress internetAddress = new InternetAddress(from);
String receiveAddress = this.getReceiveAddress(message, null);
if (!from.contains(req.getSourceName())){
continue;
}
msgSubject = String.format("主题:%s,发件人:%s(%s),收件人:%s",
message.getSubject(),
internetAddress.getPersonal(),
internetAddress.getAddress(),
receiveAddress);
String recordId = syncLarkTable(message,add,req.getSourceName());
this.buildLog(logs,msgSubject,recordId,null);
message.setFlag(Flags.Flag.SEEN, true);
} catch (Exception e) {
this.buildLog(logs,msgSubject,null,e);
}
}
if (CollectionUtils.isNotEmpty(logs)){
eventLogMapper.insertBatchEventLog(logs);
}
}
public String getReceiveAddress(Message msg, Message.RecipientType type) throws MessagingException {
StringBuffer receiveAddress = new StringBuffer();
Address[] addresss = null;
if (type == null) {
addresss = msg.getAllRecipients();
} else {
addresss = msg.getRecipients(type);
}
if (addresss == null || addresss.length < 1) {
return null;
}
for (Address address : addresss) {
InternetAddress internetAddress = (InternetAddress) address;
receiveAddress.append(internetAddress.toUnicodeString()).append(",");
}
receiveAddress.deleteCharAt(receiveAddress.length() - 1); //删除最后一个逗号
return receiveAddress.toString();
}
public void getMailTextContent(Part part, StringBuffer content) throws MessagingException, IOException {
//如果是文本类型的附件通过getContent方法可以取到文本内容但这不是我们需要的结果所以在这里要做判断
boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;
if (part.isMimeType("text/*") && !isContainTextAttach) {
content.append(part.getContent().toString());
} else if (part.isMimeType("message/rfc822")) {
getMailTextContent((Part) part.getContent(), content);
} else if (part.isMimeType("multipart/*")) {
Multipart multipart = (Multipart) part.getContent();
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
getMailTextContent(bodyPart, content);
}
}
}
private void buildLog(List<EventLog> logs,String message,String recordId,Exception e){
EventLog log = e == null ?
new EventLog(null, EventOperateType.SYNC_MAIL.getCode(), message)
: new EventLog(null, EventOperateType.SYNC_MAIL.getCode(), message,null,e.getMessage());
log.setRemark(recordId);
logs.add(log);
}
private String syncLarkTable(Message message,LarkTableRequest add,String sourceName) throws MessagingException, IOException {
StringBuffer content = new StringBuffer(30);
getMailTextContent(message,content);
Map<String, Object> body = this.buildBody(message,content.toString());
body.put("邮箱来源",sourceName);
body.put("数据时间",this.getReceiveDate(message));
body.put("备注",content);
add.setBody(body);
CreateAppTableRecordRespBody respBody = larkTableHelper.addTableRecord(add);
return respBody.getRecord().getRecordId();
}
protected Map<String,Object> buildBody(Message message,String content){
return new HashMap<>();
}
protected String getReceiveDate(Message message){
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(message.getReceivedDate());
} catch (MessagingException e) {
}
return null;
}
}

@ -0,0 +1,153 @@
package com.ruoyi.flyingbook.mail;
import com.ruoyi.flyingbook.domain.lark.LarkTableRequest;
import com.ruoyi.flyingbook.mail.request.MailRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.Index;
import org.springframework.stereotype.Component;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import javax.mail.search.FlagTerm;
import java.security.Security;
import java.util.*;
/**
* @author yuxiangyong
* @create 2023-04-09 15:28
*/
@Slf4j
@Component
public class MailHttpHelper extends MailHelper{
private static final List<String> degreeList = Arrays.asList("初一","初二","初三","中专","专科","高考","高中","高一","高二","高三","本科","大一","大二","大三","大四");
public static void main(String[] args) {
MailHttpHelper mailHelper = new MailHttpHelper();
// MailRequest req = new MailRequest("xjia.synology.me",5000,"xjzsb","12345678");
// req = new MailRequest("xjia.synology.me",143,"xjzsb@xjia-edu.com","12345678");
// mailHelper.receiveMail(req,null);
// mailHelper.buildBody(null,"刘畅文祺 13996409399父亲微信同 重庆 高三作曲 英语120 文化一本线 意向美国伯克利 其他国家也可以考虑一下 费用没问题 了解过其他学校 过几天联系");
}
public void receiveMail(MailRequest req, LarkTableRequest add){
// 定义连接imap服务器的属性信息
Properties props = new Properties();
props.put("mail.store.protocol", req.getEmailProtocol());
props.put("mail.imap.host", req.getEmailServer());
props.put("mail.imap.port", req.getEmailPort());
props.put("mail.imap.starttls.enable", "true");
//创建会话
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(req.getUserName(),req.getAuthorizationCode());
}
});
Store store = null;
Folder folder = null;
try {
//存储对象
store = session.getStore(req.getEmailProtocol());
//连接
store.connect(req.getEmailServer(),req.getEmailPort(),req.getUserName(),req.getAuthorizationCode());
// 获得收件箱
folder = store.getFolder(req.getReceiveFolder());
// 以读写模式打开收件箱
folder.open(Folder.READ_WRITE);
//false 表示未读
FlagTerm flagTerm = new FlagTerm(new Flags(Flags.Flag.SEEN),true);
//获得收件箱的邮件列表
Message[] messages = folder.search(flagTerm);
// 打印不同状态的邮件数量
log.info("收件箱中共{}封邮件!\n共{}封未读邮件!\n共{}封新邮件!\n共{}封已删除邮件!",
messages.length,
folder.getUnreadMessageCount(),
folder.getNewMessageCount(),
folder.getDeletedMessageCount());
this.parseMsg(messages,add,req);
} catch (Exception e) {
log.error("邮件解析失败",e);
} finally {
try {
if (folder != null) {
folder.close(false);
}
if (store != null) {
store.close();
}
} catch (MessagingException e) {
log.error("邮件解析失败",e);
}
}
}
/**
*
*/
@Override
protected Map<String, Object> buildBody(Message message,String content) {
Map<String, Object> map = new HashMap<>();
try {
Integer index = 1;
StringBuilder str = new StringBuilder();
for (String s : content.split("")) {
if (StringUtils.isNotBlank(str) && s.equals(" ")){
this.fillMap(map,str.toString(),index);
str = new StringBuilder();
index ++;
continue;
}
if (s.equals(" ")){
continue;
}
str.append(s);
}
}catch (Exception e){
map.clear();
map.put("异常信息",e.getMessage());
log.error("解析邮件文本失败",e);
}
return map;
}
private void fillMap(Map<String, Object> map,String msg,Integer index){
switch (index){
case 1:
map.put("学生姓名",msg);
break;
case 2:
map.put("省市",msg);
break;
case 3:
Boolean degreeExist = Boolean.FALSE;
for (String degree : degreeList) {
if (msg.contains(degree)){
degreeExist = Boolean.TRUE;
map.put("现有学历",msg);
}
}
if (!degreeExist){
throw new RuntimeException("学历格式不正确");
}
break;
case 4:
int startIndex = msg.indexOf("1");
if (startIndex >= 0 && msg.length() - startIndex >= 11){
map.put("手机号码",msg.substring(startIndex,startIndex + 11));
}else {
throw new RuntimeException("电话号码格式不正确");
}
break;
case 5:
break;
case 6:
map.put("目标国家",msg);
break;
default:
break;
}
}
}

@ -0,0 +1,105 @@
package com.ruoyi.flyingbook.mail;
import com.ruoyi.flyingbook.mail.request.MailRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import javax.mail.search.*;
import java.security.Security;
import java.util.Properties;
/**
* @author yuxiangyong
* @create 2023-04-09 15:28
*/
@Slf4j
@Component
public class MailTencentHelper {
/**
* ssl
*/
private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
public static void main(String[] args) {
MailTencentHelper mailHelper = new MailTencentHelper();
MailRequest req = new MailRequest("imap.qq.com",993,"932687738","ohziejkxqvsgbbag","新梦想");
mailHelper.receiveMail(req);
}
public void receiveMail(MailRequest req){
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
// 定义连接imap服务器的属性信息
String portStr = String.valueOf(req.getEmailPort());
Properties props = new Properties();
props.setProperty("mail.imap.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.imap.socketFactory.fallback", "false");
props.setProperty("mail.transport.protocol", req.getEmailProtocol());
props.setProperty("mail.imap.port", portStr);
props.setProperty("mail.imap.socketFactory.port", portStr);
//创建会话
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(req.getUserName(),req.getAuthorizationCode());
}
});
Store store = null;
Folder folder = null;
try {
//存储对象
store = session.getStore(req.getEmailProtocol());
//连接
store.connect(req.getEmailServer(),req.getEmailPort(),req.getUserName(),req.getAuthorizationCode());
// 获得收件箱
folder = store.getFolder(req.getReceiveFolder());
// 以读写模式打开收件箱
folder.open(Folder.READ_WRITE);
//false 表示未读
FlagTerm flagTerm = new FlagTerm(new Flags(Flags.Flag.SEEN),false);
//获得收件箱的邮件列表
Message[] messages = folder.search(flagTerm);
// 打印不同状态的邮件数量
log.info("------------------------开始解析邮件----------------------------------");
for (int i = 0; i < messages.length; i++) {
Message message = messages[i];
if (!message.getSubject().contains(req.getSourceName())){
continue;
}
parseMsg(message);
//设置已读
message.setFlag(Flags.Flag.SEEN,true);
}
} catch (Exception e) {
log.error("邮件解析失败",e);
} finally {
try {
if (folder != null) {
folder.close(false);
}
if (store != null) {
store.close();
}
} catch (MessagingException e) {
log.error("邮件解析失败",e);
}
}
}
private void parseMsg(Message message){
try {
System.out.println("消息:"+ message.getSubject());
String from = MimeUtility.decodeText(message.getFrom()[0].toString());
InternetAddress internetAddress = new InternetAddress(from);
System.out.println("发件人:" + internetAddress.getPersonal() + '(' + internetAddress.getAddress() + ')');
}catch (Exception e){
}
}
}

@ -0,0 +1,80 @@
package com.ruoyi.flyingbook.mail.request;
import com.ruoyi.flyingbook.domain.MailInfo;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author yuxiangyong
* @create 2023-04-09 16:41
*/
@Data
@NoArgsConstructor
public class MailRequest {
/**
*
* imap.qq.com
*/
private String emailServer;
/**
*
* 993
*/
private Integer emailPort;
/**
*
* imap
*/
private String emailProtocol;
/**
*
*/
private String userName;
/**
*
*/
private String authorizationCode;
/**
*
* INBOX
*/
private String receiveFolder;
/** 邮件来源名称 */
private String sourceName;
/**
*
*/
private Boolean readFeedback;
private void fillDefault(Boolean readFeedback){
this.emailProtocol = "imap";
this.receiveFolder = "INBOX";
if (readFeedback != null){
this.readFeedback = readFeedback;
}
}
public MailRequest(String emailServer, Integer emailPort, String userName, String authorizationCode,String sourceName) {
this.emailServer = emailServer;
this.emailPort = emailPort;
this.userName = userName;
this.authorizationCode = authorizationCode;
this.sourceName = sourceName;
this.fillDefault(Boolean.TRUE);
}
public MailRequest(MailInfo info,Boolean readFeedback) {
this.emailServer = info.getMailServer();
this.emailPort = Integer.valueOf(info.getMailPort());
this.userName = info.getMailUserName();
this.authorizationCode = info.getMailAuthorizationCode();
this.emailProtocol = info.getMailProtocol();
this.receiveFolder = info.getMailReceiveFolder();
this.readFeedback = Boolean.TRUE.equals(readFeedback);
this.sourceName = info.getSourceName();
}
}

@ -1,6 +1,7 @@
package com.ruoyi.flyingbook.mapper;
import com.ruoyi.flyingbook.domain.LarkCompanyTableInfo;
import com.ruoyi.flyingbook.domain.LarkTableRelation;
import org.apache.ibatis.annotations.Param;
@ -62,4 +63,6 @@ public interface LarkTableRelationMapper
*/
public int deleteLarkTableRelationByIds(Long[] ids);
public List<LarkCompanyTableInfo> queryListByIdListJoinLarkCompany(@Param("tableIds") List<Long> tableIds, @Param("flag") Long flag, @Param("relationType") String relationType);
}

@ -0,0 +1,61 @@
package com.ruoyi.flyingbook.mapper;
import com.ruoyi.flyingbook.domain.MailInfo;
import java.util.List;
/**
* @author ruoyi
* @date 2023-04-09
*/
public interface MailInfoMapper
{
/**
*
*
* @param id ID
* @return
*/
public MailInfo selectMailInfoById(Long id);
/**
*
*
* @param mailInfo
* @return
*/
public List<MailInfo> selectMailInfoList(MailInfo mailInfo);
/**
*
*
* @param mailInfo
* @return
*/
public int insertMailInfo(MailInfo mailInfo);
/**
*
*
* @param mailInfo
* @return
*/
public int updateMailInfo(MailInfo mailInfo);
/**
*
*
* @param id ID
* @return
*/
public int deleteMailInfoById(Long id);
/**
*
*
* @param ids ID
* @return
*/
public int deleteMailInfoByIds(Long[] ids);
}

@ -0,0 +1,63 @@
package com.ruoyi.flyingbook.service;
import com.ruoyi.flyingbook.domain.MailInfo;
import java.util.List;
/**
* Service
*
* @author ruoyi
* @date 2023-04-09
*/
public interface IMailInfoService
{
/**
*
*
* @param id ID
* @return
*/
public MailInfo selectMailInfoById(Long id);
/**
*
*
* @param mailInfo
* @return
*/
public List<MailInfo> selectMailInfoList(MailInfo mailInfo);
/**
*
*
* @param mailInfo
* @return
*/
public int insertMailInfo(MailInfo mailInfo);
/**
*
*
* @param mailInfo
* @return
*/
public int updateMailInfo(MailInfo mailInfo);
/**
*
*
* @param ids ID
* @return
*/
public int deleteMailInfoByIds(Long[] ids);
/**
*
*
* @param id ID
* @return
*/
public int deleteMailInfoById(Long id);
}

@ -0,0 +1,96 @@
package com.ruoyi.flyingbook.service.impl;
import java.util.List;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.flyingbook.domain.MailInfo;
import com.ruoyi.flyingbook.mapper.MailInfoMapper;
import com.ruoyi.flyingbook.service.IMailInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Service
*
* @author ruoyi
* @date 2023-04-09
*/
@Service
public class MailInfoServiceImpl implements IMailInfoService
{
@Autowired
private MailInfoMapper mailInfoMapper;
/**
*
*
* @param id ID
* @return
*/
@Override
public MailInfo selectMailInfoById(Long id)
{
return mailInfoMapper.selectMailInfoById(id);
}
/**
*
*
* @param mailInfo
* @return
*/
@Override
public List<MailInfo> selectMailInfoList(MailInfo mailInfo)
{
return mailInfoMapper.selectMailInfoList(mailInfo);
}
/**
*
*
* @param mailInfo
* @return
*/
@Override
public int insertMailInfo(MailInfo mailInfo)
{
mailInfo.setCreateTime(DateUtils.getNowDate());
return mailInfoMapper.insertMailInfo(mailInfo);
}
/**
*
*
* @param mailInfo
* @return
*/
@Override
public int updateMailInfo(MailInfo mailInfo)
{
mailInfo.setUpdateTime(DateUtils.getNowDate());
return mailInfoMapper.updateMailInfo(mailInfo);
}
/**
*
*
* @param ids ID
* @return
*/
@Override
public int deleteMailInfoByIds(Long[] ids)
{
return mailInfoMapper.deleteMailInfoByIds(ids);
}
/**
*
*
* @param id ID
* @return
*/
@Override
public int deleteMailInfoById(Long id)
{
return mailInfoMapper.deleteMailInfoById(id);
}
}

@ -1,48 +1,73 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.flyingbook.mapper.LarkTableRelationMapper">
<resultMap type="com.ruoyi.flyingbook.domain.LarkTableRelation" id="LarkTableRelationResult">
<result property="id" column="id" />
<result property="larkCompanyRelationId" column="lark_company_relation_id" />
<result property="fromAppToken" column="from_app_token" />
<result property="fromTableId" column="from_table_id" />
<result property="toAppToken" column="to_app_token" />
<result property="toTableId" column="to_table_id" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="flag" column="flag" />
<result property="remark" column="remark" />
<result property="relationType" column="relation_type" />
<result property="id" column="id"/>
<result property="larkCompanyRelationId" column="lark_company_relation_id"/>
<result property="fromAppToken" column="from_app_token"/>
<result property="fromTableId" column="from_table_id"/>
<result property="toAppToken" column="to_app_token"/>
<result property="toTableId" column="to_table_id"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="flag" column="flag"/>
<result property="remark" column="remark"/>
<result property="relationType" column="relation_type"/>
</resultMap>
<resultMap type="com.ruoyi.flyingbook.domain.LarkCompanyTableInfo" id="LarkCompanyTableResult">
<result property="id" column="id"/>
<result property="appId" column="app_id"/>
<result property="appSecret" column="secret"/>
<result property="fromAppToken" column="from_app_token"/>
<result property="fromTableId" column="from_table_id"/>
<result property="toAppToken" column="to_app_token"/>
<result property="toTableId" column="to_table_id"/>
</resultMap>
<sql id="selectLarkTableRelationVo">
select id, lark_company_relation_id, from_app_token, from_table_id, to_app_token, to_table_id, create_by, create_time, update_by, update_time, flag, remark,relation_type from lark_table_relation
select id,
lark_company_relation_id,
from_app_token,
from_table_id,
to_app_token,
to_table_id,
create_by,
create_time,
update_by,
update_time,
flag,
remark,
relation_type
from lark_table_relation
</sql>
<select id="selectLarkTableRelationList" parameterType="com.ruoyi.flyingbook.domain.LarkTableRelation" resultMap="LarkTableRelationResult">
<select id="selectLarkTableRelationList" parameterType="com.ruoyi.flyingbook.domain.LarkTableRelation"
resultMap="LarkTableRelationResult">
<include refid="selectLarkTableRelationVo"/>
<where>
<if test="larkCompanyRelationId != null "> and lark_company_relation_id = #{larkCompanyRelationId}</if>
<if test="relationType != null and relationType != ''"> and relation_type = #{relationType}</if>
<if test="fromAppToken != null and fromAppToken != ''"> and from_app_token = #{fromAppToken}</if>
<if test="fromTableId != null and fromTableId != ''"> and from_table_id = #{fromTableId}</if>
<if test="toAppToken != null and toAppToken != ''"> and to_app_token = #{toAppToken}</if>
<if test="toTableId != null and toTableId != ''"> and to_table_id = #{toTableId}</if>
<if test="flag != null "> and flag = #{flag}</if>
<where>
<if test="larkCompanyRelationId != null ">and lark_company_relation_id = #{larkCompanyRelationId}</if>
<if test="relationType != null and relationType != ''">and relation_type = #{relationType}</if>
<if test="fromAppToken != null and fromAppToken != ''">and from_app_token = #{fromAppToken}</if>
<if test="fromTableId != null and fromTableId != ''">and from_table_id = #{fromTableId}</if>
<if test="toAppToken != null and toAppToken != ''">and to_app_token = #{toAppToken}</if>
<if test="toTableId != null and toTableId != ''">and to_table_id = #{toTableId}</if>
<if test="flag != null ">and flag = #{flag}</if>
</where>
</select>
<select id="selectLarkTableRelationById" parameterType="Long" resultMap="LarkTableRelationResult">
<include refid="selectLarkTableRelationVo"/>
where id = #{id}
</select>
<insert id="insertLarkTableRelation" parameterType="com.ruoyi.flyingbook.domain.LarkTableRelation" useGeneratedKeys="true" keyProperty="id">
<insert id="insertLarkTableRelation" parameterType="com.ruoyi.flyingbook.domain.LarkTableRelation"
useGeneratedKeys="true" keyProperty="id">
insert into lark_table_relation
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="larkCompanyRelationId != null">lark_company_relation_id,</if>
@ -57,7 +82,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="flag != null">flag,</if>
<if test="remark != null">remark,</if>
<if test="relationType != null">relation_type,</if>
</trim>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="larkCompanyRelationId != null">#{larkCompanyRelationId},</if>
<if test="fromAppToken != null">#{fromAppToken},</if>
@ -71,7 +96,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="flag != null">#{flag},</if>
<if test="remark != null">#{remark},</if>
<if test="relationType != null">#{relationType},</if>
</trim>
</trim>
</insert>
<update id="updateLarkTableRelation" parameterType="com.ruoyi.flyingbook.domain.LarkTableRelation">
@ -94,13 +119,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</update>
<delete id="deleteLarkTableRelationById" parameterType="Long">
delete from lark_table_relation where id = #{id}
delete
from lark_table_relation
where id = #{id}
</delete>
<delete id="deleteLarkTableRelationByIds" parameterType="String">
delete from lark_table_relation where id in
delete from lark_table_relation where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<select id="queryListByIdListJoinLarkCompany" resultMap="LarkCompanyTableResult">
SELECT
cr.app_id,
cr.secret,
tr.id,
tr.from_app_token,
tr.from_table_id,
tr.to_app_token,
tr.to_table_id
FROM
lark_table_relation tr
LEFT JOIN lark_company_relation cr ON tr.lark_company_relation_id = cr.id
WHERE
tr.id IN
<foreach collection="tableIds" open="(" close=")" separator="," item="id">
#{id}
</foreach>
AND tr.flag = #{flag}
AND tr.relation_type = #{relationType};
</select>
</mapper>

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.flyingbook.mapper.MailInfoMapper">
<resultMap type="com.ruoyi.flyingbook.domain.MailInfo" id="MailInfoResult">
<result property="id" column="id" />
<result property="larkTableId" column="lark_table_id" />
<result property="mailServer" column="mail_server" />
<result property="mailPort" column="mail_port" />
<result property="mailProtocol" column="mail_protocol" />
<result property="mailUserName" column="mail_user_name" />
<result property="mailAuthorizationCode" column="mail_authorization_code" />
<result property="mailReceiveFolder" column="mail_receive_folder" />
<result property="sourceName" column="source_name" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="flag" column="flag" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectMailInfoVo">
select id,lark_table_id, mail_server, mail_port, mail_protocol, mail_user_name, mail_authorization_code, mail_receive_folder,source_name, create_by, create_time, update_by, update_time, flag, remark from mail_info
</sql>
<select id="selectMailInfoList" parameterType="com.ruoyi.flyingbook.domain.MailInfo" resultMap="MailInfoResult">
<include refid="selectMailInfoVo"/>
<where>
<if test="larkTableId != null"> and lark_table_id = #{larkTableId}</if>
<if test="mailServer != null and mailServer != ''"> and mail_server = #{mailServer}</if>
<if test="mailPort != null and mailPort != ''"> and mail_port = #{mailPort}</if>
<if test="mailProtocol != null and mailProtocol != ''"> and mail_protocol = #{mailProtocol}</if>
<if test="mailUserName != null and mailUserName != ''"> and mail_user_name like concat('%', #{mailUserName}, '%')</if>
<if test="mailAuthorizationCode != null and mailAuthorizationCode != ''"> and mail_authorization_code = #{mailAuthorizationCode}</if>
<if test="mailReceiveFolder != null and mailReceiveFolder != ''"> and mail_receive_folder = #{mailReceiveFolder}</if>
<if test="sourceName != null and sourceName != ''"> and source_name = #{sourceName}</if>
<if test="flag != null "> and flag = #{flag}</if>
</where>
</select>
<select id="selectMailInfoById" parameterType="Long" resultMap="MailInfoResult">
<include refid="selectMailInfoVo"/>
where id = #{id}
</select>
<insert id="insertMailInfo" parameterType="com.ruoyi.flyingbook.domain.MailInfo" useGeneratedKeys="true" keyProperty="id">
insert into mail_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="larkTableId != null">lark_table_id,</if>
<if test="mailServer != null and mailServer != ''">mail_server,</if>
<if test="mailPort != null and mailPort != ''">mail_port,</if>
<if test="mailProtocol != null and mailProtocol != ''">mail_protocol,</if>
<if test="mailUserName != null and mailUserName != ''">mail_user_name,</if>
<if test="mailAuthorizationCode != null and mailAuthorizationCode != ''">mail_authorization_code,</if>
<if test="mailReceiveFolder != null">mail_receive_folder,</if>
<if test="sourceName != null">source_name,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="flag != null">flag,</if>
<if test="remark != null">remark,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="larkTableId != null">#{larkTableId},</if>
<if test="mailServer != null and mailServer != ''">#{mailServer},</if>
<if test="mailPort != null and mailPort != ''">#{mailPort},</if>
<if test="mailProtocol != null and mailProtocol != ''">#{mailProtocol},</if>
<if test="mailUserName != null and mailUserName != ''">#{mailUserName},</if>
<if test="mailAuthorizationCode != null and mailAuthorizationCode != ''">#{mailAuthorizationCode},</if>
<if test="mailReceiveFolder != null">#{mailReceiveFolder},</if>
<if test="sourceName != null">#{sourceName},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="flag != null">#{flag},</if>
<if test="remark != null">#{remark},</if>
</trim>
</insert>
<update id="updateMailInfo" parameterType="com.ruoyi.flyingbook.domain.MailInfo">
update mail_info
<trim prefix="SET" suffixOverrides=",">
<if test="larkTableId != null">lark_table_id = #{larkTableId},</if>
<if test="mailServer != null and mailServer != ''">mail_server = #{mailServer},</if>
<if test="mailPort != null and mailPort != ''">mail_port = #{mailPort},</if>
<if test="mailProtocol != null and mailProtocol != ''">mail_protocol = #{mailProtocol},</if>
<if test="mailUserName != null and mailUserName != ''">mail_user_name = #{mailUserName},</if>
<if test="mailAuthorizationCode != null and mailAuthorizationCode != ''">mail_authorization_code = #{mailAuthorizationCode},</if>
<if test="mailReceiveFolder != null">mail_receive_folder = #{mailReceiveFolder},</if>
<if test="sourceName != null">source_name = #{sourceName},</if>
<if test="createBy != null and createBy != ''">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="flag != null">flag = #{flag},</if>
<if test="remark != null">remark = #{remark},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteMailInfoById" parameterType="Long">
delete from mail_info where id = #{id}
</delete>
<delete id="deleteMailInfoByIds" parameterType="String">
delete from mail_info where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

@ -97,7 +97,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 过滤请求
.authorizeRequests()
// 对于登录login 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/captchaImage", "/approval", "/approval2").anonymous()
.antMatchers("/login", "/captchaImage", "/approval","/syncEmail", "/approval2").anonymous()
.antMatchers(
HttpMethod.GET,
"/*.html",

@ -34,6 +34,10 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-flyingbook</artifactId>
</dependency>
</dependencies>

@ -0,0 +1,24 @@
package com.ruoyi.quartz.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.quartz.task.MailSyncTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class MailInfoController extends BaseController {
@Autowired
private MailSyncTask mailSyncTask;
@PostMapping("/syncEmail")
public void syncEmail() {
mailSyncTask.syncMail();
}
}

@ -0,0 +1,94 @@
package com.ruoyi.quartz.task;
import com.ruoyi.common.enums.FlagStatus;
import com.ruoyi.common.enums.TableRelationTypeEnum;
import com.ruoyi.flyingbook.domain.LarkCompanyTableInfo;
import com.ruoyi.flyingbook.domain.MailInfo;
import com.ruoyi.flyingbook.domain.lark.LarkTableRequest;
import com.ruoyi.flyingbook.mail.MailHttpHelper;
import com.ruoyi.flyingbook.mail.request.MailRequest;
import com.ruoyi.flyingbook.mapper.LarkTableRelationMapper;
import com.ruoyi.flyingbook.service.IMailInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
*
*
* @author ruoyi
*/
@Slf4j
@Component("mailSyncTask")
public class MailSyncTask {
@Autowired
private MailHttpHelper mailHttpHelper;
@Autowired
private IMailInfoService iMailInfoService;
@Autowired
private LarkTableRelationMapper larkTableRelationMapper;
public void syncMail() {
log.info("MailSyncTask start");
MailInfo mailInfo = new MailInfo();
mailInfo.setFlag(FlagStatus.OK.getCode());
List<MailInfo> mailInfos = iMailInfoService.selectMailInfoList(mailInfo);
log.info("MailSyncTask execute size:{}", mailInfos.size());
Map<Long, LarkTableRequest> larkMap = this.getLarkMap(mailInfos);
for (MailInfo info : mailInfos) {
LarkTableRequest addRequest = larkMap.get(info.getLarkTableId());
if (addRequest == null) {
log.info("待同步邮箱未配置飞书相关信息,mailInfo:{}", info);
continue;
}
MailRequest request = new MailRequest(info, Boolean.TRUE);
mailHttpHelper.receiveMail(request,addRequest);
}
log.info("MailSyncTask end");
}
private Map<Long, LarkTableRequest> getLarkMap(List<MailInfo> mailInfos) {
List<Long> tableIds = mailInfos.stream()
.filter(r -> {
return r.getLarkTableId() != null;
})
.map(MailInfo::getLarkTableId)
.distinct()
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(tableIds)) {
return new HashMap<>();
}
List<LarkCompanyTableInfo> larkCompanyTableInfos = larkTableRelationMapper.queryListByIdListJoinLarkCompany(tableIds, FlagStatus.OK.getCode(), TableRelationTypeEnum.SYNC_EMAIL.getCode());
return larkCompanyTableInfos.stream()
.filter(r -> {
return r.getId() != null
&& StringUtils.isNotBlank(r.getAppId())
&& StringUtils.isNotBlank(r.getAppSecret())
&& StringUtils.isNotBlank(r.getToAppToken())
&& StringUtils.isNotBlank(r.getToTableId());
})
.map(r -> {
LarkTableRequest request = new LarkTableRequest();
request.setId(r.getId());
request.setAppId(r.getAppId());
request.setAppSecret(r.getAppSecret());
request.setAppToken(r.getToAppToken());
request.setAppTable(r.getToTableId());
return request;
})
.collect(
Collectors.toMap(LarkTableRequest::getId, Function.identity(), (k1, k2) -> k1)
);
}
}

@ -0,0 +1,22 @@
-- 菜单 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('【请填写功能名称】', '3', '1', 'info', 'system/info/index', 1, 0, 'C', '0', '0', 'system:info:list', '#', 'admin', sysdate(), '', null, '【请填写功能名称】菜单');
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('【请填写功能名称】查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', 'system:info:query', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('【请填写功能名称】新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', 'system:info:add', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('【请填写功能名称】修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', 'system:info:edit', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('【请填写功能名称】删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', 'system:info:remove', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('【请填写功能名称】导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', 'system:info:export', '#', 'admin', sysdate(), '', null, '');
Loading…
Cancel
Save