/lib/plugin/egg-dora-maildelivery/app/controller/manage/mailDelivery.js

https://github.com/doramart/DoraCMS · JavaScript · 369 lines · 278 code · 88 blank · 3 comment · 21 complexity · 51ad25e99b158327dac4c835fded1e26 MD5 · raw file

  1. const xss = require("xss");
  2. const _ = require('lodash');
  3. const schedule = require('node-schedule');
  4. const mailDeliveryRule = (ctx) => {
  5. return {
  6. emailType: {
  7. type: "string",
  8. required: true,
  9. message: ctx.__("validate_error_field", [ctx.__("邮件类型")])
  10. },
  11. timing: {
  12. type: "string",
  13. required: true,
  14. message: ctx.__("validate_error_field", [ctx.__("定时")])
  15. },
  16. comments: {
  17. type: "string",
  18. required: true,
  19. message: ctx.__("validate_error_field", [ctx.__("备注")])
  20. },
  21. type: {
  22. type: "string",
  23. required: true,
  24. message: ctx.__("validate_error_field", [ctx.__("任务类型")])
  25. },
  26. }
  27. }
  28. const sendEmailByTask = async (ctx, taskId, emailInfo, targetUserInfo) => {
  29. try {
  30. let {
  31. allEmailArr,
  32. allUserIdArr
  33. } = targetUserInfo;
  34. for (let j = 0; j < allEmailArr.length; j++) {
  35. const emailArr = allEmailArr[j];
  36. const sendEmailDo = () => {
  37. return new Promise((resolve, reject) => {
  38. setTimeout(async () => {
  39. let sendResult = await ctx.helper.reqJsonData('mailTemplate/sendEmail', {
  40. tempkey: "-1", // -1特指邮件群发
  41. info: {
  42. title: emailInfo.comments,
  43. targets: emailArr.join(','),
  44. content: emailInfo.content,
  45. }
  46. }, "post");
  47. await ctx.service.sendLog.create({
  48. taskId,
  49. recipient: allUserIdArr[j],
  50. recipientEmail: emailArr,
  51. state: sendResult,
  52. createTime: new Date()
  53. });
  54. resolve();
  55. }, 1500)
  56. })
  57. }
  58. await sendEmailDo();
  59. }
  60. } catch (error) {
  61. await ctx.service.mailDelivery.update(ctx, taskId, {
  62. state: '1'
  63. });
  64. await ctx.service.sendLog.create({
  65. taskId,
  66. recipient: targetUser._id,
  67. recipientEmail: targetUser.email,
  68. state: '0',
  69. createTime: new Date()
  70. });
  71. }
  72. }
  73. const sendMailByTimingTask = async (ctx, taskId, emailInfo, sendUserInfo) => {
  74. if (!_.isEmpty(global['sendMailTimingTask_' + taskId])) {
  75. global['sendMailTimingTask_' + taskId].cancel();
  76. }
  77. global['sendMailTimingTask_' + taskId] = schedule.scheduleJob(emailInfo.timing, async function () {
  78. if (!_.isEmpty(sendUserInfo)) {
  79. sendEmailByTask(ctx, taskId, emailInfo, sendUserInfo);
  80. }
  81. });
  82. }
  83. // 群发用户邮箱集合
  84. const getSendUserInfo = async (ctx, targetType, targetUsers = []) => {
  85. let skipCount = 20; // 设定批量发送最小单位
  86. let allUserCount, queryObj = {};
  87. if (targetType == '0') {
  88. allUserCount = await ctx.service.user.count();
  89. } else if (targetType == '1') {
  90. allUserCount = targetUsers.length;
  91. queryObj = {
  92. _id: {
  93. $in: targetUsers
  94. }
  95. }
  96. }
  97. let sendNum = Math.ceil(allUserCount / skipCount);
  98. let allUserIdArr = [];
  99. let allEmailArr = [];
  100. for (let i = 0; i < sendNum; i++) {
  101. let unitUser = await ctx.service.user.find({
  102. isPaging: '0',
  103. current: i,
  104. pageSize: skipCount
  105. }, {
  106. query: queryObj,
  107. files: "email"
  108. })
  109. if (!_.isEmpty(unitUser)) {
  110. let unitEmails = unitUser.map((item) => {
  111. return item.email;
  112. })
  113. let unitIds = unitUser.map((item) => {
  114. return item._id;
  115. })
  116. allEmailArr.push(unitEmails);
  117. allUserIdArr.push(unitIds);
  118. }
  119. }
  120. return {
  121. allEmailArr,
  122. allUserIdArr
  123. }
  124. }
  125. const doSendEmailTask = async (ctx, fields, taskId) => {
  126. try {
  127. let targetUsers = fields.targets;
  128. let sendUserInfo = await getSendUserInfo(ctx, fields.targetType, targetUsers)
  129. if (fields.type == '0') { // 立即发送
  130. if (!_.isEmpty(sendUserInfo)) {
  131. sendEmailByTask(ctx, taskId, fields, sendUserInfo);
  132. }
  133. // 更新发送状态
  134. await ctx.service.mailDelivery.update(ctx, taskId, {
  135. state: '2'
  136. });
  137. } else if (fields.type == '1') { // 定时发送
  138. if (!fields.timing) {
  139. fields.timing = new Date();
  140. }
  141. if (!_.isEmpty(sendUserInfo)) {
  142. sendMailByTimingTask(ctx, taskId, fields, sendUserInfo)
  143. }
  144. await ctx.service.mailDelivery.update(ctx, taskId, {
  145. state: '2'
  146. });
  147. }
  148. } catch (error) {
  149. console.log('email send error', error);
  150. }
  151. }
  152. let MailDeliveryController = {
  153. async list(ctx) {
  154. try {
  155. let payload = ctx.query;
  156. let queryObj = {};
  157. let mailDeliveryList = await ctx.service.mailDelivery.find(payload, {
  158. query: queryObj,
  159. populate: ["sender", "emailType"],
  160. sort: {
  161. createTime: -1
  162. }
  163. });
  164. ctx.helper.renderSuccess(ctx, {
  165. data: mailDeliveryList
  166. });
  167. } catch (err) {
  168. ctx.helper.renderFail(ctx, {
  169. message: err
  170. });
  171. }
  172. },
  173. async sendloglist(ctx) {
  174. try {
  175. let payload = ctx.query;
  176. let queryObj = {
  177. taskId: payload.taskId
  178. };
  179. let sendLogList = await ctx.service.sendLog.find(payload, {
  180. query: queryObj,
  181. populate: ["recipient"],
  182. sort: {
  183. createTime: -1
  184. }
  185. });
  186. ctx.helper.renderSuccess(ctx, {
  187. data: sendLogList
  188. });
  189. } catch (err) {
  190. ctx.helper.renderFail(ctx, {
  191. message: err
  192. });
  193. }
  194. },
  195. async create(ctx) {
  196. try {
  197. let fields = ctx.request.body || {};
  198. let sendMailTask;
  199. const formObj = {
  200. sender: ctx.session.adminUserInfo._id,
  201. emailType: fields.emailType,
  202. state: "0",
  203. timing: fields.timing,
  204. comments: fields.comments,
  205. content: fields.content,
  206. type: fields.type,
  207. targets: fields.targets,
  208. targetType: fields.targetType,
  209. createTime: new Date()
  210. }
  211. ctx.validate(mailDeliveryRule(ctx), formObj);
  212. sendMailTask = await ctx.service.mailDelivery.create(formObj);
  213. doSendEmailTask(ctx, fields, sendMailTask._id);
  214. ctx.helper.renderSuccess(ctx);
  215. } catch (err) {
  216. ctx.helper.renderFail(ctx, {
  217. message: err
  218. });
  219. }
  220. },
  221. async getOne(ctx) {
  222. try {
  223. let _id = ctx.query.id;
  224. let targetItem = await ctx.service.mailDelivery.item(ctx, {
  225. query: {
  226. _id: _id
  227. },
  228. populate: ["targets"]
  229. });
  230. ctx.helper.renderSuccess(ctx, {
  231. data: targetItem
  232. });
  233. } catch (err) {
  234. ctx.helper.renderFail(ctx, {
  235. message: err
  236. });
  237. }
  238. },
  239. async update(ctx) {
  240. try {
  241. let fields = ctx.request.body || {};
  242. const formObj = {
  243. sender: ctx.session.adminUserInfo._id,
  244. emailType: fields.emailType,
  245. timing: fields.timing,
  246. comments: fields.comments,
  247. content: fields.content,
  248. type: fields.type,
  249. targets: fields.targets,
  250. targetType: fields.targetType,
  251. updateTime: new Date()
  252. }
  253. ctx.validate(mailDeliveryRule(ctx), formObj);
  254. await ctx.service.mailDelivery.update(ctx, fields._id, formObj);
  255. doSendEmailTask(ctx, fields, fields._id);
  256. ctx.helper.renderSuccess(ctx);
  257. } catch (err) {
  258. ctx.helper.renderFail(ctx, {
  259. message: err
  260. });
  261. }
  262. },
  263. async removes(ctx) {
  264. try {
  265. let targetIds = ctx.query.ids;
  266. await ctx.service.mailDelivery.removes(ctx, targetIds);
  267. // 删除与该任务相关的发送记录
  268. await ctx.service.sendLog.removes(ctx, targetIds, 'taskId');
  269. if (!_.isEmpty(global['sendMailTimingTask_' + targetIds])) {
  270. global['sendMailTimingTask_' + targetIds].cancel();
  271. }
  272. ctx.helper.renderSuccess(ctx);
  273. } catch (err) {
  274. xxx
  275. ctx.helper.renderFail(ctx, {
  276. message: err
  277. });
  278. }
  279. },
  280. }
  281. module.exports = MailDeliveryController;