mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-05 23:47:50 +08:00
feat: add empty address cleanup feature (#765)
* feat: add empty address cleanup feature Add functionality to clean up email addresses that have never received any emails and were created more than N days ago. Changes: - Add emptyAddress cleanup type to backend cleanup logic - Add enableEmptyAddressAutoCleanup and cleanEmptyAddressDays to CleanupSettings model - Add scheduled task support for auto-cleanup of empty addresses - Add UI controls in Maintenance page for manual and auto cleanup - Add i18n support (English and Chinese translations) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: update dependencies Update package.json and lock files across frontend, worker, pages, and vitepress-docs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: update CHANGELOG for empty address cleanup feature Add entry for new maintenance page feature to clean up email addresses with no emails older than N days 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
## v1.1.0(main)
|
## v1.1.0(main)
|
||||||
|
|
||||||
|
- feat: |Admin| 维护页面增加清理 n 天前空邮件的邮箱地址功能
|
||||||
|
|
||||||
## v1.0.7
|
## v1.0.7
|
||||||
|
|
||||||
- feat: |Admin| 新增 IP 黑名单功能,用于限制访问频率较高的 API
|
- feat: |Admin| 新增 IP 黑名单功能,用于限制访问频率较高的 API
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
"vite-plugin-wasm": "^3.5.0",
|
"vite-plugin-wasm": "^3.5.0",
|
||||||
"workbox-build": "^7.3.0",
|
"workbox-build": "^7.3.0",
|
||||||
"workbox-window": "^7.3.0",
|
"workbox-window": "^7.3.0",
|
||||||
"wrangler": "^4.46.0"
|
"wrangler": "^4.47.0"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+332
-346
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,8 @@ const cleanupModel = ref({
|
|||||||
cleanInactiveAddressDays: 30,
|
cleanInactiveAddressDays: 30,
|
||||||
enableUnboundAddressAutoCleanup: false,
|
enableUnboundAddressAutoCleanup: false,
|
||||||
cleanUnboundAddressDays: 30,
|
cleanUnboundAddressDays: 30,
|
||||||
|
enableEmptyAddressAutoCleanup: false,
|
||||||
|
cleanEmptyAddressDays: 30,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { t } = useI18n({
|
const { t } = useI18n({
|
||||||
@@ -31,6 +33,7 @@ const { t } = useI18n({
|
|||||||
addressCreateLabel: "Cleanup the address created before n days",
|
addressCreateLabel: "Cleanup the address created before n days",
|
||||||
inactiveAddressLabel: "Cleanup the inactive address before n days",
|
inactiveAddressLabel: "Cleanup the inactive address before n days",
|
||||||
unboundAddressLabel: "Cleanup the unbound address before n days",
|
unboundAddressLabel: "Cleanup the unbound address before n days",
|
||||||
|
emptyAddressLabel: "Cleanup the empty address before n days",
|
||||||
cleanupNow: "Cleanup now",
|
cleanupNow: "Cleanup now",
|
||||||
autoCleanup: "Auto cleanup",
|
autoCleanup: "Auto cleanup",
|
||||||
cleanupSuccess: "Cleanup success",
|
cleanupSuccess: "Cleanup success",
|
||||||
@@ -45,6 +48,7 @@ const { t } = useI18n({
|
|||||||
addressCreateLabel: "清理 n 天前创建的地址",
|
addressCreateLabel: "清理 n 天前创建的地址",
|
||||||
inactiveAddressLabel: "清理 n 天前的未活跃地址",
|
inactiveAddressLabel: "清理 n 天前的未活跃地址",
|
||||||
unboundAddressLabel: "清理 n 天前的未绑定用户地址",
|
unboundAddressLabel: "清理 n 天前的未绑定用户地址",
|
||||||
|
emptyAddressLabel: "清理 n 天前空邮件的邮箱地址",
|
||||||
autoCleanup: "自动清理",
|
autoCleanup: "自动清理",
|
||||||
cleanupSuccess: "清理成功",
|
cleanupSuccess: "清理成功",
|
||||||
cleanupNow: "立即清理",
|
cleanupNow: "立即清理",
|
||||||
@@ -177,6 +181,18 @@ onMounted(async () => {
|
|||||||
{{ t('cleanupNow') }}
|
{{ t('cleanupNow') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-form-item-row>
|
</n-form-item-row>
|
||||||
|
<n-form-item-row :label="t('emptyAddressLabel')">
|
||||||
|
<n-checkbox v-model:checked="cleanupModel.enableEmptyAddressAutoCleanup">
|
||||||
|
{{ t('autoCleanup') }}
|
||||||
|
</n-checkbox>
|
||||||
|
<n-input-number v-model:value="cleanupModel.cleanEmptyAddressDays" :placeholder="t('tip')" />
|
||||||
|
<n-button @click="cleanup('emptyAddress', cleanupModel.cleanEmptyAddressDays)">
|
||||||
|
<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>
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"wrangler": "^4.46.0"
|
"wrangler": "^4.47.0"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^24.10.0",
|
"@types/node": "^24.10.1",
|
||||||
"vitepress": "^1.6.4",
|
"vitepress": "^1.6.4",
|
||||||
"wrangler": "^4.46.0"
|
"wrangler": "^4.47.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vitepress dev docs",
|
"dev": "vitepress dev docs",
|
||||||
|
|||||||
Generated
+357
-381
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -11,26 +11,26 @@
|
|||||||
"build": "wrangler deploy --dry-run --outdir dist --minify"
|
"build": "wrangler deploy --dry-run --outdir dist --minify"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cloudflare/workers-types": "^4.20251107.0",
|
"@cloudflare/workers-types": "^4.20251111.0",
|
||||||
"@eslint/js": "9.18.0",
|
"@eslint/js": "9.18.0",
|
||||||
"@simplewebauthn/types": "10.0.0",
|
"@simplewebauthn/types": "10.0.0",
|
||||||
"@types/node": "^22.19.0",
|
"@types/node": "^22.19.1",
|
||||||
"eslint": "9.18.0",
|
"eslint": "9.18.0",
|
||||||
"globals": "^15.15.0",
|
"globals": "^15.15.0",
|
||||||
"typescript-eslint": "^8.46.3",
|
"typescript-eslint": "^8.46.4",
|
||||||
"wrangler": "^4.46.0"
|
"wrangler": "^4.47.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.888.0",
|
"@aws-sdk/client-s3": "3.888.0",
|
||||||
"@aws-sdk/s3-request-presigner": "3.888.0",
|
"@aws-sdk/s3-request-presigner": "3.888.0",
|
||||||
"@simplewebauthn/server": "10.0.1",
|
"@simplewebauthn/server": "10.0.1",
|
||||||
"hono": "^4.10.4",
|
"hono": "^4.10.5",
|
||||||
"jsonpath-plus": "^10.3.0",
|
"jsonpath-plus": "^10.3.0",
|
||||||
"mimetext": "^3.0.27",
|
"mimetext": "^3.0.27",
|
||||||
"postal-mime": "^2.6.0",
|
"postal-mime": "^2.6.0",
|
||||||
"resend": "^4.8.0",
|
"resend": "^4.8.0",
|
||||||
"telegraf": "4.16.3",
|
"telegraf": "4.16.3",
|
||||||
"worker-mailer": "^1.1.5"
|
"worker-mailer": "^1.2.0"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
|
|||||||
Generated
+504
-528
File diff suppressed because it is too large
Load Diff
@@ -273,6 +273,13 @@ export const cleanup = async (
|
|||||||
DELETE FROM sendbox WHERE created_at < datetime('now', '-${cleanDays} day')`
|
DELETE FROM sendbox WHERE created_at < datetime('now', '-${cleanDays} day')`
|
||||||
).run();
|
).run();
|
||||||
break;
|
break;
|
||||||
|
case "emptyAddress":
|
||||||
|
// Delete addresses that have no emails and were created more than N days ago
|
||||||
|
await batchDeleteAddressWithData(
|
||||||
|
c,
|
||||||
|
`name NOT IN (SELECT DISTINCT address FROM raw_mails WHERE address IS NOT NULL) AND created_at < datetime('now', '-${cleanDays} day')`
|
||||||
|
)
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Invalid cleanType")
|
throw new Error("Invalid cleanType")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ export type CleanupSettings = {
|
|||||||
cleanInactiveAddressDays: number;
|
cleanInactiveAddressDays: number;
|
||||||
enableUnboundAddressAutoCleanup: boolean | undefined;
|
enableUnboundAddressAutoCleanup: boolean | undefined;
|
||||||
cleanUnboundAddressDays: number;
|
cleanUnboundAddressDays: number;
|
||||||
|
enableEmptyAddressAutoCleanup: boolean | undefined;
|
||||||
|
cleanEmptyAddressDays: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GeoData {
|
export class GeoData {
|
||||||
|
|||||||
@@ -57,4 +57,11 @@ export async function scheduled(event: ScheduledEvent, env: Bindings, ctx: any)
|
|||||||
autoCleanupSetting.cleanUnboundAddressDays
|
autoCleanupSetting.cleanUnboundAddressDays
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (autoCleanupSetting.enableEmptyAddressAutoCleanup) {
|
||||||
|
await cleanup(
|
||||||
|
{ env: env, } as Context<HonoCustomType>,
|
||||||
|
"emptyAddress",
|
||||||
|
autoCleanupSetting.cleanEmptyAddressDays
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user