@xuda.io/account_module 1.2.2278 → 1.2.2280
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/index.mjs
CHANGED
|
@@ -367,7 +367,13 @@ export const increment_account_usage = async function (req) {
|
|
|
367
367
|
|
|
368
368
|
if (Date.now() - doc.ts >= interval) {
|
|
369
369
|
const plan = _conf.PLAN_OBJ[account_data.membership_plan];
|
|
370
|
-
if (!plan)
|
|
370
|
+
if (!plan) {
|
|
371
|
+
// Only report missing plans for stat 3 (verified) accounts. Stat 1/2
|
|
372
|
+
// (unverified stubs, temp-pass invites, widget signups) have no plan
|
|
373
|
+
// until their first real login by design — skip silently.
|
|
374
|
+
if (account_data.stat === 3) throw new Error(`${account_data.account_info.first_name + ' ' + account_data.account_info.last_name} has no plan in file`);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
371
377
|
const drive_size_total = account_data.user_drive_size + account_data.studio_drive_size + account_data.workspace_drive_size + account_data.builds_drive_size + account_data.plugins_drive_size;
|
|
372
378
|
if (bytesToGB(drive_size_total) > plan.features.drive) {
|
|
373
379
|
var price_per_hour = (bytesToGB(drive_size_total) * _conf.PRICE_OBJ.price_per_gb_drive) / _conf.PRICE_OBJ.avg_hours_in_month;
|
package/package.json
CHANGED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// One-off cleanup: soft-delete orphan account-project shells.
|
|
2
|
+
//
|
|
3
|
+
// A half-provisioned account can accumulate multiple `is_account_project`
|
|
4
|
+
// projects — login_maintenance creates a fresh one on every retry but only ever
|
|
5
|
+
// adopts ONE as the account doc's `account_project_id`. The non-adopted shells
|
|
6
|
+
// are empty orphans (the "4 Jonathan's Project" pileup). This soft-deletes the
|
|
7
|
+
// orphans (app_status_code = 4) so they drop out of the sidebar, keeping the
|
|
8
|
+
// adopted/live one untouched.
|
|
9
|
+
//
|
|
10
|
+
// The create_project resilience fix stops the pileup from happening again; this
|
|
11
|
+
// just cleans up accounts that already accumulated shells.
|
|
12
|
+
//
|
|
13
|
+
// Usage (from XUDA_HOME, same env the cpi workers run with — XUDA_HOME +
|
|
14
|
+
// XUDA_CONFIG set):
|
|
15
|
+
// node cpi/account_module/scripts/cleanup_orphan_account_projects.mjs <uid> # DRY RUN (lists, writes nothing)
|
|
16
|
+
// node cpi/account_module/scripts/cleanup_orphan_account_projects.mjs <uid> --apply # actually soft-delete
|
|
17
|
+
//
|
|
18
|
+
// Idempotent — re-running skips already-deleted docs. Hard-aborts if the
|
|
19
|
+
// account has no account_project_id (so it can never delete EVERY project).
|
|
20
|
+
|
|
21
|
+
import path from 'path';
|
|
22
|
+
|
|
23
|
+
if (!global._conf) {
|
|
24
|
+
global._conf = (await import(path.join(process.env.XUDA_HOME, "common", "load_conf.mjs"))).loadConf();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const uid = process.argv[2];
|
|
28
|
+
const apply = process.argv.includes('--apply');
|
|
29
|
+
if (!uid || uid.startsWith('--')) {
|
|
30
|
+
console.error('usage: node cleanup_orphan_account_projects.mjs <uid> [--apply]');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const module_path = path.join(process.env.XUDA_HOME, 'cpi') + (!_conf.is_debug ? '/node_modules/@xuda.io' : '');
|
|
35
|
+
const db_module = await import(`${module_path}/db_module/index.mjs`);
|
|
36
|
+
|
|
37
|
+
// 1. The account doc tells us which project is the live one to KEEP.
|
|
38
|
+
const acct = await db_module.get_couch_doc('xuda_accounts', uid);
|
|
39
|
+
if (acct.code < 0) {
|
|
40
|
+
console.error('account not found:', uid, acct.data);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const keep = acct.data.account_project_id;
|
|
44
|
+
console.log('account', uid, '→ keep account_project_id:', keep || '(NONE SET)');
|
|
45
|
+
|
|
46
|
+
// 2. Every is_account_project project owned by this account (full scan — fine on
|
|
47
|
+
// the small set an account owns; ignore_warning silences the no-index notice).
|
|
48
|
+
const found = await db_module.find_couch_query(
|
|
49
|
+
'xuda_master',
|
|
50
|
+
{ selector: { app_uId: uid, is_account_project: true }, limit: 9999 },
|
|
51
|
+
true,
|
|
52
|
+
);
|
|
53
|
+
const docs = found?.data?.docs || found?.docs || [];
|
|
54
|
+
console.log(
|
|
55
|
+
'found',
|
|
56
|
+
docs.length,
|
|
57
|
+
'is_account_project doc(s):',
|
|
58
|
+
docs.map((d) => `${d._id}${d._id === keep ? ' (KEEP)' : ''}${d.app_status_code === 4 ? ' (already deleted)' : ''}`),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Safety: never run blind on an account that hasn't adopted a project yet —
|
|
62
|
+
// otherwise every project would look like an orphan and we'd wipe them all.
|
|
63
|
+
if (!keep) {
|
|
64
|
+
console.error('\nABORT: account has no account_project_id set. Re-provision it first (re-login so login_maintenance adopts one), then re-run.');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 3. Orphans = not the adopted one + not already soft-deleted.
|
|
69
|
+
const orphans = docs.filter((d) => d._id !== keep && d.app_status_code !== 4);
|
|
70
|
+
console.log('\norphans to soft-delete (' + orphans.length + '):', orphans.map((d) => d._id));
|
|
71
|
+
|
|
72
|
+
if (!orphans.length) {
|
|
73
|
+
console.log('\nnothing to clean. done.');
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!apply) {
|
|
78
|
+
console.log('\nDRY RUN — re-run with --apply to soft-delete the above. Nothing was written.');
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const d of orphans) {
|
|
83
|
+
d.app_status_code = 4;
|
|
84
|
+
d.stat_reason = 'orphan account-project cleanup';
|
|
85
|
+
d.date_updated_ts = Date.now();
|
|
86
|
+
const r = await db_module.save_couch_doc('xuda_master', d);
|
|
87
|
+
console.log('soft-deleted', d._id, '→ code', r.code);
|
|
88
|
+
}
|
|
89
|
+
console.log('\ndone — soft-deleted', orphans.length, 'orphan(s). The live project', keep, 'was kept.');
|
|
90
|
+
process.exit(0);
|