mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-05 07:27:27 +08:00
fix: auto initialize default send balance (#985)
* fix: auto initialize default send balance * fix: tighten send access auto init flow * refactor: centralize send balance state * fix: separate legacy repair from admin control in send balance Add an `address_sender.source` column to distinguish legacy / auto / user / admin rows. `ensureDefaultSendBalance` now only repairs rows with `source IS NULL`, so admin-disabled and user-requested rows are never overwritten. Admin POST writes tag `source = 'admin'`; new auto-init inserts tag `'auto'`; `requestSendMailAccess` inserts tag `'user'`. Bumps DB_VERSION to v0.0.8 with the usual `PRAGMA table_info` guarded ALTER, plus a standalone SQL patch under db/. Adds E2E regressions: legacy repair path, admin-disabled rows stay disabled across settings and send, send after admin deletion auto-initializes a fresh row. * fix: drop runtime legacy repair; backfill source='legacy' on migrate Pre-v0.0.8 schema cannot distinguish legacy request-send-access remnants from admin-disabled rows — both share `balance = 0, enabled = 0`. Letting ensureDefaultSendBalance repair that shape on upgrade could silently re-enable an admin-disabled row. Remove the runtime repair path entirely: - `ensureDefaultSendBalance` now uses `ON CONFLICT(address) DO NOTHING`; existing rows are never touched. - The v0.0.8 migration (and the matching SQL patch) backfills every pre-existing row with `source = 'legacy'`, making pre-migration state explicitly off-limits to runtime auto-init. - E2E: flip the legacy test to the negative direction — a `source='legacy'` zero-balance row stays untouched by settings reads and send attempts. Harden `resetSenderToLegacy` to return 404 when `meta.changes < 1`. - Update changelog and docs: legacy/admin-disabled rows must be restored manually via the admin UI. * refactor: collapse send balance auto-init to missing-row insert Per review feedback: the runtime guarantee we actually need is "create an address_sender row when one is missing, leave existing rows alone". Once `ensureDefaultSendBalance` switched to `ON CONFLICT DO NOTHING`, the `source` column, the v0.0.8 migration, and the `resetSenderToLegacy` test endpoint became dead weight — the DO NOTHING path already protects admin-disabled and admin-edited rows without any provenance metadata. - Drop `address_sender.source` and the v0.0.8 migration; revert DB_VERSION to v0.0.7. No schema change ships with this PR. - Strip the `source` field from `ensureDefaultSendBalance`, `requestSendMailAccess`, and the admin-update path. - Remove the `/admin/test/reset_sender_to_legacy` test endpoint and its E2E helper; the negative legacy-repair test it served is no longer needed because the runtime no longer touches existing rows. - E2E coverage stays focused on the three guardrails: missing-row auto-init, admin-disabled rows stay disabled, admin deletion triggers a fresh re-insert. - Tighten changelog and docs to "auto-initialize missing rows". * docs: align common-issues with missing-row-only auto-init The FAQ entries for "DEFAULT_SEND_BALANCE set but still No balance" still described the old behaviour of repairing legacy `balance = 0 && enabled = 0` rows. Rewrite both zh and en rows to match the current runtime: only addresses with no existing `address_sender` row get auto-initialised; legacy, admin-disabled, and admin-edited rows must be restored manually through the admin console.
This commit is contained in:
@@ -183,8 +183,9 @@ export function onMailpitMessage(
|
||||
|
||||
/**
|
||||
* Request send mail access for an address.
|
||||
* Must be called before sending mail — creates the address_sender row
|
||||
* with the DEFAULT_SEND_BALANCE configured in the worker.
|
||||
* Kept for backward compatibility and manual-request flows. When
|
||||
* DEFAULT_SEND_BALANCE > 0, send balance may already be auto-initialized
|
||||
* before this endpoint is called.
|
||||
*/
|
||||
export async function requestSendAccess(
|
||||
ctx: APIRequestContext,
|
||||
@@ -198,6 +199,62 @@ export async function requestSendAccess(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the sender access row for an address from the admin API.
|
||||
*/
|
||||
export async function getAddressSender(
|
||||
ctx: APIRequestContext,
|
||||
address: string,
|
||||
workerUrl: string = WORKER_URL
|
||||
): Promise<any> {
|
||||
const res = await ctx.get(
|
||||
`${workerUrl}/admin/address_sender?limit=1&offset=0&address=${encodeURIComponent(address)}`,
|
||||
);
|
||||
if (!res.ok()) {
|
||||
throw new Error(`Failed to get address sender: ${res.status()} ${await res.text()}`);
|
||||
}
|
||||
const body = await res.json();
|
||||
if (!Array.isArray(body.results) || body.results.length < 1) {
|
||||
throw new Error(`address_sender row not found for ${address}`);
|
||||
}
|
||||
return body.results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a sender access row through the admin API.
|
||||
*/
|
||||
export async function updateAddressSender(
|
||||
ctx: APIRequestContext,
|
||||
opts: {
|
||||
address: string;
|
||||
address_id: number;
|
||||
balance: number;
|
||||
enabled: boolean;
|
||||
},
|
||||
workerUrl: string = WORKER_URL
|
||||
): Promise<void> {
|
||||
const res = await ctx.post(`${workerUrl}/admin/address_sender`, {
|
||||
data: opts,
|
||||
});
|
||||
if (!res.ok()) {
|
||||
throw new Error(`Failed to update address sender: ${res.status()} ${await res.text()}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a sender access row through the admin API by its id.
|
||||
*/
|
||||
export async function deleteAddressSender(
|
||||
ctx: APIRequestContext,
|
||||
id: number,
|
||||
workerUrl: string = WORKER_URL
|
||||
): Promise<void> {
|
||||
const res = await ctx.delete(`${workerUrl}/admin/address_sender/${id}`);
|
||||
if (!res.ok()) {
|
||||
throw new Error(`Failed to delete address sender: ${res.status()} ${await res.text()}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a test address via its JWT.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user