foliko 1.0.48 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugins/email.js +73 -2
- package/plugins/web-plugin.js +13 -2
package/package.json
CHANGED
package/plugins/email.js
CHANGED
|
@@ -11,7 +11,12 @@ class EmailPlugin extends Plugin {
|
|
|
11
11
|
super()
|
|
12
12
|
this.name = 'email'
|
|
13
13
|
this.version = '1.0.0'
|
|
14
|
-
this.description =
|
|
14
|
+
this.description = `邮件收发插件 - 支持读取和发送电子邮件
|
|
15
|
+
发送邮件支持附件:
|
|
16
|
+
- attachments.path: 本地文件路径
|
|
17
|
+
- attachments.url: 远程图片/文件URL(自动下载)
|
|
18
|
+
- attachments.content: Base64内容
|
|
19
|
+
- attachments.cid: 嵌入式图片CID(HTML中用 <img src="cid:xxx"> 引用)`
|
|
15
20
|
this.priority = 10
|
|
16
21
|
// 默认不启用,需要在 plugins.json 中设置 enabled: true
|
|
17
22
|
this.enabled = false
|
|
@@ -34,7 +39,14 @@ class EmailPlugin extends Plugin {
|
|
|
34
39
|
body: z.string().describe('邮件正文内容'),
|
|
35
40
|
cc: z.string().optional().describe('抄送邮箱地址,多个用逗号分隔'),
|
|
36
41
|
bcc: z.string().optional().describe('密送邮箱地址,多个用逗号分隔'),
|
|
37
|
-
isHtml: z.boolean().optional().describe('是否为HTML格式,默认false')
|
|
42
|
+
isHtml: z.boolean().optional().describe('是否为HTML格式,默认false'),
|
|
43
|
+
attachments: z.array(z.object({
|
|
44
|
+
filename: z.string().describe('附件文件名'),
|
|
45
|
+
path: z.string().optional().describe('本地文件路径'),
|
|
46
|
+
url: z.string().optional().describe('远程图片URL'),
|
|
47
|
+
content: z.string().optional().describe('Base64编码内容(可带前缀如 data:image/png;base64,)'),
|
|
48
|
+
cid: z.string().optional().describe('嵌入式图片的CID(用于在HTML中嵌入图片,如 <img src="cid:xxx">)')
|
|
49
|
+
})).optional().describe('附件列表,支持本地文件、远程URL或Base64内容')
|
|
38
50
|
}),
|
|
39
51
|
execute: async (args) => {
|
|
40
52
|
return this._sendEmail(args)
|
|
@@ -119,6 +131,10 @@ class EmailPlugin extends Plugin {
|
|
|
119
131
|
async _sendEmail(args) {
|
|
120
132
|
try {
|
|
121
133
|
const nodemailer = require('nodemailer')
|
|
134
|
+
const https = require('https')
|
|
135
|
+
const http = require('http')
|
|
136
|
+
const fs = require('fs')
|
|
137
|
+
const path = require('path')
|
|
122
138
|
|
|
123
139
|
const smtpConfig = {
|
|
124
140
|
host: process.env.SMTP_HOST || 'smtp.gmail.com',
|
|
@@ -142,6 +158,32 @@ class EmailPlugin extends Plugin {
|
|
|
142
158
|
bcc: args.bcc
|
|
143
159
|
}
|
|
144
160
|
|
|
161
|
+
// 处理附件
|
|
162
|
+
if (args.attachments && args.attachments.length > 0) {
|
|
163
|
+
mailOptions.attachments = []
|
|
164
|
+
for (const att of args.attachments) {
|
|
165
|
+
const attachment = { filename: att.filename }
|
|
166
|
+
|
|
167
|
+
if (att.path) {
|
|
168
|
+
// 本地文件
|
|
169
|
+
attachment.content = fs.createReadStream(att.path)
|
|
170
|
+
} else if (att.url) {
|
|
171
|
+
// 远程URL
|
|
172
|
+
attachment.content = await this._fetchUrl(att.url)
|
|
173
|
+
} else if (att.content) {
|
|
174
|
+
// Base64 内容
|
|
175
|
+
const base64Data = att.content.replace(/^data:[^;]+;base64,/, '')
|
|
176
|
+
attachment.content = Buffer.from(base64Data, 'base64')
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (att.cid) {
|
|
180
|
+
attachment.cid = att.cid
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
mailOptions.attachments.push(attachment)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
145
187
|
const info = await transporter.sendMail(mailOptions)
|
|
146
188
|
return {
|
|
147
189
|
success: true,
|
|
@@ -159,6 +201,35 @@ class EmailPlugin extends Plugin {
|
|
|
159
201
|
}
|
|
160
202
|
}
|
|
161
203
|
|
|
204
|
+
_fetchUrl(url) {
|
|
205
|
+
return new Promise((resolve, reject) => {
|
|
206
|
+
const protocol = url.startsWith('https') ? https : http
|
|
207
|
+
const lib = url.startsWith('https') ? require('https') : require('http')
|
|
208
|
+
|
|
209
|
+
const request = lib.get(url, (response) => {
|
|
210
|
+
if (response.statusCode === 301 || response.statusCode === 302) {
|
|
211
|
+
// 处理重定向
|
|
212
|
+
this._fetchUrl(response.headers.location).then(resolve).catch(reject)
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const chunks = []
|
|
217
|
+
response.on('data', (chunk) => chunks.push(chunk))
|
|
218
|
+
response.on('end', () => {
|
|
219
|
+
const buffer = Buffer.concat(chunks)
|
|
220
|
+
resolve(buffer)
|
|
221
|
+
})
|
|
222
|
+
response.on('error', reject)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
request.on('error', reject)
|
|
226
|
+
request.setTimeout(10000, () => {
|
|
227
|
+
request.destroy()
|
|
228
|
+
reject(new Error('下载超时'))
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
162
233
|
async _readEmails(args) {
|
|
163
234
|
try {
|
|
164
235
|
const Imap = require('imap-mkl')
|
package/plugins/web-plugin.js
CHANGED
|
@@ -256,7 +256,7 @@ class WebPlugin extends Plugin {
|
|
|
256
256
|
async _handleRoute(c, route, pathname) {
|
|
257
257
|
const params = this._extractParams(route.path, pathname)
|
|
258
258
|
const query = this._parseQuery(c)
|
|
259
|
-
const body = await
|
|
259
|
+
const body = await this._parseBody(c)
|
|
260
260
|
|
|
261
261
|
const context = { params, query, body }
|
|
262
262
|
const result = await this._executeHandler(route.handler, context)
|
|
@@ -265,7 +265,7 @@ class WebPlugin extends Plugin {
|
|
|
265
265
|
|
|
266
266
|
async _handleWebhook(c, webhook) {
|
|
267
267
|
const query = this._parseQuery(c)
|
|
268
|
-
const body = await
|
|
268
|
+
const body = await this._parseBody(c)
|
|
269
269
|
const webhookData = {
|
|
270
270
|
path: webhook.path,
|
|
271
271
|
method: c.req.method,
|
|
@@ -490,6 +490,17 @@ class WebPlugin extends Plugin {
|
|
|
490
490
|
return query
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
+
async _parseBody(c) {
|
|
494
|
+
try {
|
|
495
|
+
const rawText = await c.req.text()
|
|
496
|
+
console.log(rawText)
|
|
497
|
+
if (!rawText) return {}
|
|
498
|
+
return JSON.parse(rawText)
|
|
499
|
+
} catch (e) {
|
|
500
|
+
return {}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
493
504
|
_getUrl(path='') {
|
|
494
505
|
if (this._baseUrl) {
|
|
495
506
|
return `${this._baseUrl}${path}`
|