mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-04 23:17:34 +08:00
feat: cleanup support address and inactive address (#671)
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
- fix: |UI| 修复 User 查看收件箱,不选择地址时,关键词查询不生效
|
- fix: |UI| 修复 User 查看收件箱,不选择地址时,关键词查询不生效
|
||||||
- fix: 修复自动清理任务,时间为 0 时不生效的问题
|
- fix: 修复自动清理任务,时间为 0 时不生效的问题
|
||||||
|
- feat: 清理功能增加 创建 n 天前地址清理,n 天前未活跃地址清理
|
||||||
|
|
||||||
## v0.10.0
|
## v0.10.0
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ const cleanupModel = ref({
|
|||||||
cleanMailsDays: 30,
|
cleanMailsDays: 30,
|
||||||
enableUnknowMailsAutoCleanup: false,
|
enableUnknowMailsAutoCleanup: false,
|
||||||
cleanUnknowMailsDays: 30,
|
cleanUnknowMailsDays: 30,
|
||||||
enableAddressAutoCleanup: false,
|
|
||||||
cleanAddressDays: 30,
|
|
||||||
enableSendBoxAutoCleanup: false,
|
enableSendBoxAutoCleanup: false,
|
||||||
cleanSendBoxDays: 30,
|
cleanSendBoxDays: 30,
|
||||||
|
enableAddressAutoCleanup: false,
|
||||||
|
cleanAddressDays: 30,
|
||||||
|
enableInactiveAddressAutoCleanup: false,
|
||||||
|
cleanInactiveAddressDays: 30,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { t } = useI18n({
|
const { t } = useI18n({
|
||||||
@@ -24,6 +26,8 @@ const { t } = useI18n({
|
|||||||
mailBoxLabel: 'Cleanup the inbox before n days',
|
mailBoxLabel: 'Cleanup the inbox before n days',
|
||||||
mailUnknowLabel: "Cleanup the unknow mail before n days",
|
mailUnknowLabel: "Cleanup the unknow mail before n days",
|
||||||
sendBoxLabel: "Cleanup the sendbox before n days",
|
sendBoxLabel: "Cleanup the sendbox before n days",
|
||||||
|
addressCreateLabel: "Cleanup the address created before n days",
|
||||||
|
inactiveAddressLabel: "Cleanup the inactive address before n days",
|
||||||
cleanupNow: "Cleanup now",
|
cleanupNow: "Cleanup now",
|
||||||
autoCleanup: "Auto cleanup",
|
autoCleanup: "Auto cleanup",
|
||||||
cleanupSuccess: "Cleanup success",
|
cleanupSuccess: "Cleanup success",
|
||||||
@@ -35,6 +39,8 @@ const { t } = useI18n({
|
|||||||
mailBoxLabel: '清理 n 天前的收件箱',
|
mailBoxLabel: '清理 n 天前的收件箱',
|
||||||
mailUnknowLabel: "清理 n 天前的无收件人邮件",
|
mailUnknowLabel: "清理 n 天前的无收件人邮件",
|
||||||
sendBoxLabel: "清理 n 天前的发件箱",
|
sendBoxLabel: "清理 n 天前的发件箱",
|
||||||
|
addressCreateLabel: "清理 n 天前创建的地址",
|
||||||
|
inactiveAddressLabel: "清理 n 天前的未活跃地址",
|
||||||
autoCleanup: "自动清理",
|
autoCleanup: "自动清理",
|
||||||
cleanupSuccess: "清理成功",
|
cleanupSuccess: "清理成功",
|
||||||
cleanupNow: "立即清理",
|
cleanupNow: "立即清理",
|
||||||
@@ -86,9 +92,14 @@ onMounted(async () => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<n-card :bordered="false" embedded>
|
<n-card :bordered="false" embedded>
|
||||||
<n-alert :show-icon="false" :bordered="false">
|
<n-alert :show-icon="false" :bordered="false" type="warning">
|
||||||
<span>{{ t('cronTip') }}</span>
|
<span>{{ t('cronTip') }}</span>
|
||||||
</n-alert>
|
</n-alert>
|
||||||
|
<n-flex justify="end">
|
||||||
|
<n-button @click="save" type="primary" :loading="loading">
|
||||||
|
{{ t('save') }}
|
||||||
|
</n-button>
|
||||||
|
</n-flex>
|
||||||
<n-form :model="cleanupModel">
|
<n-form :model="cleanupModel">
|
||||||
<n-form-item-row :label="t('mailBoxLabel')">
|
<n-form-item-row :label="t('mailBoxLabel')">
|
||||||
<n-checkbox v-model:checked="cleanupModel.enableMailsAutoCleanup">
|
<n-checkbox v-model:checked="cleanupModel.enableMailsAutoCleanup">
|
||||||
@@ -126,9 +137,30 @@ onMounted(async () => {
|
|||||||
{{ t('cleanupNow') }}
|
{{ t('cleanupNow') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-form-item-row>
|
</n-form-item-row>
|
||||||
<n-button @click="save" type="primary" block :loading="loading">
|
<n-form-item-row :label="t('addressCreateLabel')">
|
||||||
{{ t('save') }}
|
<n-checkbox v-model:checked="cleanupModel.enableAddressAutoCleanup">
|
||||||
</n-button>
|
{{ t('autoCleanup') }}
|
||||||
|
</n-checkbox>
|
||||||
|
<n-input-number v-model:value="cleanupModel.cleanAddressDays" :placeholder="t('tip')" />
|
||||||
|
<n-button @click="cleanup('addressCreated', cleanupModel.cleanAddressDays)">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon :component="CleaningServicesFilled" />
|
||||||
|
</template>
|
||||||
|
{{ t('cleanupNow') }}
|
||||||
|
</n-button>
|
||||||
|
</n-form-item-row>
|
||||||
|
<n-form-item-row :label="t('inactiveAddressLabel')">
|
||||||
|
<n-checkbox v-model:checked="cleanupModel.enableInactiveAddressAutoCleanup">
|
||||||
|
{{ t('autoCleanup') }}
|
||||||
|
</n-checkbox>
|
||||||
|
<n-input-number v-model:value="cleanupModel.cleanInactiveAddressDays" :placeholder="t('tip')" />
|
||||||
|
<n-button @click="cleanup('inactiveAddress', cleanupModel.cleanInactiveAddressDays)">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon :component="CleaningServicesFilled" />
|
||||||
|
</template>
|
||||||
|
{{ t('cleanupNow') }}
|
||||||
|
</n-button>
|
||||||
|
</n-form-item-row>
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-card>
|
</n-card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ export default {
|
|||||||
return c.json({ success: true })
|
return c.json({ success: true })
|
||||||
},
|
},
|
||||||
getCleanup: async (c: Context<HonoCustomType>) => {
|
getCleanup: async (c: Context<HonoCustomType>) => {
|
||||||
const value = await getJsonSetting(c, CONSTANTS.AUTO_CLEANUP_KEY);
|
const cleanupSetting = await getJsonSetting<CleanupSettings>(c, CONSTANTS.AUTO_CLEANUP_KEY);
|
||||||
const cleanupSetting = new CleanupSettings(value);
|
|
||||||
return c.json(cleanupSetting)
|
return c.json(cleanupSetting)
|
||||||
},
|
},
|
||||||
saveCleanup: async (c: Context<HonoCustomType>) => {
|
saveCleanup: async (c: Context<HonoCustomType>) => {
|
||||||
const value = await c.req.json();
|
const cleanupSetting = await c.req.json<CleanupSettings>();
|
||||||
const cleanupSetting = new CleanupSettings(value);
|
|
||||||
await saveSetting(c, CONSTANTS.AUTO_CLEANUP_KEY, JSON.stringify(cleanupSetting));
|
await saveSetting(c, CONSTANTS.AUTO_CLEANUP_KEY, JSON.stringify(cleanupSetting));
|
||||||
return c.json({ success: true })
|
return c.json({ success: true })
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-1
@@ -155,6 +155,18 @@ export const cleanup = async (
|
|||||||
}
|
}
|
||||||
console.log(`Cleanup ${cleanType} before ${cleanDays} days`);
|
console.log(`Cleanup ${cleanType} before ${cleanDays} days`);
|
||||||
switch (cleanType) {
|
switch (cleanType) {
|
||||||
|
case "inactiveAddress":
|
||||||
|
await batchDeleteAddressWithData(
|
||||||
|
c,
|
||||||
|
`updated_at < datetime('now', '-${cleanDays} day')`
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
case "addressCreated":
|
||||||
|
await batchDeleteAddressWithData(
|
||||||
|
c,
|
||||||
|
`created_at < datetime('now', '-${cleanDays} day')`
|
||||||
|
)
|
||||||
|
break;
|
||||||
case "mails":
|
case "mails":
|
||||||
await c.env.DB.prepare(`
|
await c.env.DB.prepare(`
|
||||||
DELETE FROM raw_mails WHERE created_at < datetime('now', '-${cleanDays} day')`
|
DELETE FROM raw_mails WHERE created_at < datetime('now', '-${cleanDays} day')`
|
||||||
@@ -177,6 +189,37 @@ export const cleanup = async (
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const batchDeleteAddressWithData = async (
|
||||||
|
c: Context<HonoCustomType>,
|
||||||
|
addressQueryCondition: string,
|
||||||
|
): Promise<boolean> => {
|
||||||
|
await c.env.DB.prepare(
|
||||||
|
`DELETE FROM raw_mails WHERE address IN ( ` +
|
||||||
|
`SELECT name FROM address WHERE ${addressQueryCondition})`
|
||||||
|
).run();
|
||||||
|
await c.env.DB.prepare(
|
||||||
|
`DELETE FROM sendbox WHERE address IN ( ` +
|
||||||
|
`SELECT name FROM address WHERE ${addressQueryCondition})`
|
||||||
|
).run();
|
||||||
|
await c.env.DB.prepare(
|
||||||
|
`DELETE FROM auto_reply_mails WHERE address IN ( ` +
|
||||||
|
`SELECT name FROM address WHERE ${addressQueryCondition})`
|
||||||
|
).run();
|
||||||
|
await c.env.DB.prepare(
|
||||||
|
`DELETE FROM address_sender WHERE address IN ( ` +
|
||||||
|
`SELECT name FROM address WHERE ${addressQueryCondition})`
|
||||||
|
).run();
|
||||||
|
await c.env.DB.prepare(
|
||||||
|
`DELETE FROM users_address WHERE address_id IN ( ` +
|
||||||
|
`SELECT id FROM address WHERE ${addressQueryCondition})`
|
||||||
|
).run();
|
||||||
|
// delete address
|
||||||
|
await c.env.DB.prepare(`
|
||||||
|
DELETE FROM address WHERE ${addressQueryCondition}`
|
||||||
|
).run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: need senbox delete?
|
* TODO: need senbox delete?
|
||||||
*/
|
*/
|
||||||
@@ -214,13 +257,19 @@ export const deleteAddressWithData = async (
|
|||||||
const { success: sendAccess } = await c.env.DB.prepare(
|
const { success: sendAccess } = await c.env.DB.prepare(
|
||||||
`DELETE FROM address_sender WHERE address = ? `
|
`DELETE FROM address_sender WHERE address = ? `
|
||||||
).bind(address).run();
|
).bind(address).run();
|
||||||
|
const { success: sendboxSuccess } = await c.env.DB.prepare(
|
||||||
|
`DELETE FROM sendbox WHERE address = ? `
|
||||||
|
).bind(address).run();
|
||||||
const { success: addressSuccess } = await c.env.DB.prepare(
|
const { success: addressSuccess } = await c.env.DB.prepare(
|
||||||
`DELETE FROM users_address WHERE address_id = ? `
|
`DELETE FROM users_address WHERE address_id = ? `
|
||||||
).bind(address_id).run();
|
).bind(address_id).run();
|
||||||
|
const { success: autoReplySuccess } = await c.env.DB.prepare(
|
||||||
|
`DELETE FROM auto_reply_mails WHERE address = ? `
|
||||||
|
).bind(address).run();
|
||||||
const { success } = await c.env.DB.prepare(
|
const { success } = await c.env.DB.prepare(
|
||||||
`DELETE FROM address WHERE name = ? `
|
`DELETE FROM address WHERE name = ? `
|
||||||
).bind(address).run();
|
).bind(address).run();
|
||||||
if (!success || !mailSuccess || !addressSuccess || !sendAccess) {
|
if (!success || !mailSuccess || !sendboxSuccess || !addressSuccess || !sendAccess || !autoReplySuccess) {
|
||||||
throw new Error("Failed to delete address")
|
throw new Error("Failed to delete address")
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export type WebhookMail = {
|
|||||||
parsedHtml: string;
|
parsedHtml: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CleanupSettings {
|
export type CleanupSettings = {
|
||||||
|
|
||||||
enableMailsAutoCleanup: boolean | undefined;
|
enableMailsAutoCleanup: boolean | undefined;
|
||||||
cleanMailsDays: number;
|
cleanMailsDays: number;
|
||||||
@@ -40,23 +40,12 @@ export class CleanupSettings {
|
|||||||
cleanUnknowMailsDays: number;
|
cleanUnknowMailsDays: number;
|
||||||
enableSendBoxAutoCleanup: boolean | undefined;
|
enableSendBoxAutoCleanup: boolean | undefined;
|
||||||
cleanSendBoxDays: number;
|
cleanSendBoxDays: number;
|
||||||
|
enableAddressAutoCleanup: boolean | undefined;
|
||||||
constructor(data: CleanupSettings | undefined | null) {
|
cleanAddressDays: number;
|
||||||
const {
|
enableInactiveAddressAutoCleanup: boolean | undefined;
|
||||||
enableMailsAutoCleanup, cleanMailsDays,
|
cleanInactiveAddressDays: number;
|
||||||
enableUnknowMailsAutoCleanup, cleanUnknowMailsDays,
|
|
||||||
enableSendBoxAutoCleanup, cleanSendBoxDays
|
|
||||||
} = data || {};
|
|
||||||
this.enableMailsAutoCleanup = enableMailsAutoCleanup;
|
|
||||||
this.cleanMailsDays = cleanMailsDays || 0;
|
|
||||||
this.enableUnknowMailsAutoCleanup = enableUnknowMailsAutoCleanup;
|
|
||||||
this.cleanUnknowMailsDays = cleanUnknowMailsDays || 0;
|
|
||||||
this.enableSendBoxAutoCleanup = enableSendBoxAutoCleanup;
|
|
||||||
this.cleanSendBoxDays = cleanSendBoxDays || 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class GeoData {
|
export class GeoData {
|
||||||
|
|
||||||
ip: string;
|
ip: string;
|
||||||
|
|||||||
+19
-2
@@ -6,11 +6,14 @@ import { CleanupSettings } from './models';
|
|||||||
|
|
||||||
export async function scheduled(event: ScheduledEvent, env: Bindings, ctx: any) {
|
export async function scheduled(event: ScheduledEvent, env: Bindings, ctx: any) {
|
||||||
console.log("Scheduled event: ", event);
|
console.log("Scheduled event: ", event);
|
||||||
const value = await getJsonSetting(
|
const autoCleanupSetting = await getJsonSetting<CleanupSettings>(
|
||||||
{ env: env, } as Context<HonoCustomType>,
|
{ env: env, } as Context<HonoCustomType>,
|
||||||
CONSTANTS.AUTO_CLEANUP_KEY
|
CONSTANTS.AUTO_CLEANUP_KEY
|
||||||
);
|
);
|
||||||
const autoCleanupSetting = new CleanupSettings(value);
|
if (!autoCleanupSetting) {
|
||||||
|
console.log("No auto cleanup settings found, skipping cleanup.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.log("autoCleanupSetting:", JSON.stringify(autoCleanupSetting));
|
console.log("autoCleanupSetting:", JSON.stringify(autoCleanupSetting));
|
||||||
if (autoCleanupSetting.enableMailsAutoCleanup) {
|
if (autoCleanupSetting.enableMailsAutoCleanup) {
|
||||||
await cleanup(
|
await cleanup(
|
||||||
@@ -33,4 +36,18 @@ export async function scheduled(event: ScheduledEvent, env: Bindings, ctx: any)
|
|||||||
autoCleanupSetting.cleanSendBoxDays
|
autoCleanupSetting.cleanSendBoxDays
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (autoCleanupSetting.enableInactiveAddressAutoCleanup) {
|
||||||
|
await cleanup(
|
||||||
|
{ env: env, } as Context<HonoCustomType>,
|
||||||
|
"inactiveAddress",
|
||||||
|
autoCleanupSetting.cleanInactiveAddressDays
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (autoCleanupSetting.enableAddressAutoCleanup) {
|
||||||
|
await cleanup(
|
||||||
|
{ env: env, } as Context<HonoCustomType>,
|
||||||
|
"addressCreated",
|
||||||
|
autoCleanupSetting.cleanAddressDays
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user