feat: add account deletion, announcements and subscription renewal

Support personal records and persistent smoking visibility. Add upload quota preflight, file cleanup, privacy entry, image caching and revision-based page refresh across the backend, admin and mini program.
This commit is contained in:
2026-11-03 22:06:47 +08:00
parent 4c9708b562
commit 8be6d9b1ab
98 changed files with 1679 additions and 372 deletions
+6 -2
View File
@@ -9,7 +9,7 @@ function setup() {
let app;
const wx = {
getStorageSync: key => storage.get(key), setStorageSync: (key,value) => storage.set(key,value),
removeStorageSync: key => storage.delete(key), getStorageInfoSync: () => ({keys:[...storage.keys()]}),
clearStorageSync:()=>storage.clear(), removeStorageSync: key => storage.delete(key), getStorageInfoSync: () => ({keys:[...storage.keys()]}),
login: options => logins.push(options), request: options => requests.push(options),
getNetworkType: options => options.success({networkType:'wifi'}), onNetworkStatusChange(){},
hideLoading(){}, showToast(){}
@@ -19,7 +19,7 @@ function setup() {
module:{exports:{}}, require: name => loadModule(path.join(__dirname,'../utils', name + '.js'))};
vm.runInNewContext(fs.readFileSync(path.join(__dirname,'../utils/request.js'),'utf8'),ctx);
const request = ctx.module.exports;
ctx.require = () => request;
ctx.require = name => name === './utils/request' ? request : loadModule(path.join(__dirname,'..', name + '.js'));
ctx.App = definition => {app=definition;};
vm.runInNewContext('(function(){' + fs.readFileSync(path.join(__dirname,'../app.js'),'utf8') + '\n})()',ctx);
return {app,wx,storage,logins,requests,api:request.api};
@@ -70,3 +70,7 @@ test('parallel 401 responses share token refresh and retry at most once',async()
retried[0].success({statusCode:401,data:{error:'still unauthorized'}});retried[1].success({statusCode:200,data:[]});
await failed;await two;assert.equal(env.logins.length,2);
});
test('account deletion clears drafts and credentials and prevents automatic account recreation',async()=>{
const env=setup();env.storage.set('token','private');env.storage.set('publishDraft','private draft');env.app.finishAccountDeletion();assert.equal(env.storage.has('publishDraft'),false);assert.equal(env.storage.has('token'),false);assert.equal(env.storage.get('accountDeleted'),true);assert.equal(env.app.globalData.authState,'error');await assert.rejects(env.app.refreshAuth('private'));assert.equal(env.logins.length,0);
});