@xuda.io/account_module 1.2.2299 → 1.2.2301
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 +89 -24
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -55,6 +55,18 @@ const module_path = path.join(process.env.XUDA_HOME, 'cpi') + (!_conf.is_debug ?
|
|
|
55
55
|
|
|
56
56
|
const db_module = await import(`${module_path}/db_module/index.mjs`);
|
|
57
57
|
|
|
58
|
+
// Sort keys for the dashboard list tabs, per docType. Each entry is a fallback
|
|
59
|
+
// chain (first defined value wins) because doc shapes differ. A profile keeps
|
|
60
|
+
// its display name under profile_name, a contact under name. See
|
|
61
|
+
// db_module.find_app_couch_sorted_page.
|
|
62
|
+
const LIST_SORT_PATHS = {
|
|
63
|
+
contact: { created: ['date_created_ts', 'date_created', 'ts'], updated: ['ts', 'date_created_ts'], name: ['name', 'contact_name', 'email'] },
|
|
64
|
+
account_profile: { created: ['date_created_ts', 'date_created', 'ts'], updated: ['ts', 'date_created_ts'], name: ['profile_name', 'name'] },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Dashboard list tabs whose sort preference is remembered per profile.
|
|
68
|
+
const LIST_SORT_TABS = ['ai_chats', 'apps', 'contacts', 'ai_agents', 'account_profiles'];
|
|
69
|
+
|
|
58
70
|
const ai_ms = await import(`${module_path}/ai_module/index_ms.mjs`);
|
|
59
71
|
const drive_ms = await import(`${module_path}/drive_module/index_ms.mjs`);
|
|
60
72
|
|
|
@@ -307,7 +319,6 @@ export const update_account_info = async function (req, job_id, headers) {
|
|
|
307
319
|
|
|
308
320
|
if (account_obj.account_info?.profile_picture) {
|
|
309
321
|
if (!account_obj.account_info?.profile_avatar && account_obj.account_info.profile_avatar_stat !== 2) {
|
|
310
|
-
debugger;
|
|
311
322
|
set_account_profile_picture(uid, uid, account_obj.account_info, job_id, headers, account_profile_info);
|
|
312
323
|
}
|
|
313
324
|
}
|
|
@@ -371,7 +382,7 @@ export const update_account_info = async function (req, job_id, headers) {
|
|
|
371
382
|
return save_ret;
|
|
372
383
|
};
|
|
373
384
|
export const update_account_preferences = async function (req) {
|
|
374
|
-
const { uid, hide_create_button, default_dashboard, sidebar_style, enable_thumbnail_avatar_generation, sidenav_mode, newsletter_opt_in } = req;
|
|
385
|
+
const { uid, hide_create_button, default_dashboard, sidebar_style, enable_thumbnail_avatar_generation, sidenav_mode, newsletter_opt_in, dashboard_sort } = req;
|
|
375
386
|
try {
|
|
376
387
|
let account_doc = await db_module.get_couch_doc_native('xuda_accounts', uid);
|
|
377
388
|
account_doc.ts = Date.now();
|
|
@@ -387,6 +398,32 @@ export const update_account_preferences = async function (req) {
|
|
|
387
398
|
// flag via router /newsletter/unsubscribe. Only touched when the caller sends it.
|
|
388
399
|
if (newsletter_opt_in !== undefined) account_doc.preferences.newsletter_opt_in = !!newsletter_opt_in;
|
|
389
400
|
|
|
401
|
+
// Dashboard list sort, remembered per PROFILE and per tab so switching
|
|
402
|
+
// profiles brings back that profile's own order:
|
|
403
|
+
// preferences.dashboard_sort[<account_profile_id>][<tab>] = { by, dir }
|
|
404
|
+
// Callers send one tab at a time ({ tab, sort_by, sort_dir, profile_id })
|
|
405
|
+
// and the merge below is surgical, so saving the Contacts order can never
|
|
406
|
+
// drop the one saved for AI Chats or for another profile. Sending
|
|
407
|
+
// sort_by:null clears that tab back to the default order.
|
|
408
|
+
if (dashboard_sort !== undefined) {
|
|
409
|
+
const { tab, sort_by, sort_dir } = dashboard_sort || {};
|
|
410
|
+
if (LIST_SORT_TABS.includes(tab)) {
|
|
411
|
+
const profile_info = await get_active_account_profile_info(uid, dashboard_sort?.profile_id);
|
|
412
|
+
const profile_key = profile_info?.account_profile_id || 'default';
|
|
413
|
+
const all = { ...(account_doc.preferences.dashboard_sort || {}) };
|
|
414
|
+
const for_profile = { ...(all[profile_key] || {}) };
|
|
415
|
+
|
|
416
|
+
if (['date', 'updated', 'name'].includes(sort_by)) {
|
|
417
|
+
for_profile[tab] = { by: sort_by, dir: sort_dir === 'asc' ? 'asc' : 'desc' };
|
|
418
|
+
} else {
|
|
419
|
+
delete for_profile[tab];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
all[profile_key] = for_profile;
|
|
423
|
+
account_doc.preferences.dashboard_sort = all;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
390
427
|
const save_ret = await db_module.save_couch_doc('xuda_accounts', account_doc);
|
|
391
428
|
if (save_ret.code < 0) {
|
|
392
429
|
throw new Error(save_ret.data);
|
|
@@ -3222,7 +3259,6 @@ export const get_hosting_plan = function (req) {
|
|
|
3222
3259
|
if (_conf.PRICE_OBJ.server_slugs[app_obj.app_hosting.app_server_type]) {
|
|
3223
3260
|
return _conf.PRICE_OBJ.server_slugs[app_obj.app_hosting.app_server_type];
|
|
3224
3261
|
}
|
|
3225
|
-
debugger;
|
|
3226
3262
|
console.error('error: ' + app_obj.app_hosting.app_server_type + ' not found in PRICE_OBJ.server_slugs');
|
|
3227
3263
|
return { cpu: 0, price: 0 };
|
|
3228
3264
|
}
|
|
@@ -5468,17 +5504,25 @@ export const get_contacts = async function (req, job_id, headers) {
|
|
|
5468
5504
|
let contacts = { docs: [], total_docs: 0 };
|
|
5469
5505
|
|
|
5470
5506
|
if (filter_type !== 'pending') {
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5507
|
+
// User-picked order from the dashboard list controls, see
|
|
5508
|
+
// db_module.find_app_couch_sorted_page. Null when none was asked for,
|
|
5509
|
+
// which leaves the default newest-first path below untouched.
|
|
5510
|
+
const sorted = contact_id ? null : await db_module.find_app_couch_sorted_page(account_profile_info.app_id, opt, req, LIST_SORT_PATHS.contact);
|
|
5511
|
+
if (sorted) {
|
|
5512
|
+
contacts = sorted;
|
|
5474
5513
|
} else {
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5514
|
+
contacts = await find_contact_query(account_profile_info.uid, opt);
|
|
5515
|
+
if (!limit || contact_id) {
|
|
5516
|
+
contacts.total_docs = contacts.docs.length;
|
|
5517
|
+
} else {
|
|
5518
|
+
delete opt.sort;
|
|
5519
|
+
delete opt.skip;
|
|
5520
|
+
opt.limit = 9999;
|
|
5521
|
+
opt.fields = ['_id'];
|
|
5479
5522
|
|
|
5480
|
-
|
|
5481
|
-
|
|
5523
|
+
const counter = await find_contact_query(account_profile_info.uid, opt);
|
|
5524
|
+
contacts.total_docs = counter.docs.length;
|
|
5525
|
+
}
|
|
5482
5526
|
}
|
|
5483
5527
|
}
|
|
5484
5528
|
|
|
@@ -5943,13 +5987,26 @@ export const get_account_profile_info = async function (uid, contact_profile_doc
|
|
|
5943
5987
|
if (account_info_ret.code < 0) {
|
|
5944
5988
|
return;
|
|
5945
5989
|
}
|
|
5946
|
-
|
|
5990
|
+
// The main profile IS the account's own face: always mirror the account
|
|
5991
|
+
// avatar/picture on it, so the main-profile card matches the account avatar.
|
|
5992
|
+
// A divergent value stored on the main profile doc (e.g. a stale AI-generated
|
|
5993
|
+
// avatar) must not win. Non-main profiles keep their own, falling back to the
|
|
5994
|
+
// account avatar only when they have none.
|
|
5995
|
+
if (doc.main || !doc.profile_avatar) {
|
|
5947
5996
|
doc.profile_avatar = account_info_ret.data.profile_avatar;
|
|
5948
5997
|
}
|
|
5949
|
-
if (!doc.profile_picture) {
|
|
5998
|
+
if (doc.main || !doc.profile_picture) {
|
|
5950
5999
|
doc.profile_picture = account_info_ret.data.profile_picture;
|
|
5951
6000
|
}
|
|
5952
6001
|
|
|
6002
|
+
// The main profile is the account's OWN identity: it must never auto-respond
|
|
6003
|
+
// (you don't auto-reply to yourself). Force it off in the read model so the
|
|
6004
|
+
// card hides the control and no read-based consumer treats it as on. The
|
|
6005
|
+
// runtime (ai_module.auto_response) also hard-skips the main profile.
|
|
6006
|
+
if (doc.main) {
|
|
6007
|
+
doc.auto_respond = false;
|
|
6008
|
+
}
|
|
6009
|
+
|
|
5953
6010
|
if (!doc.account_type) {
|
|
5954
6011
|
doc.account_type = account_info_ret.data.account_type;
|
|
5955
6012
|
}
|
|
@@ -6146,17 +6203,26 @@ export const get_account_profiles = async function (req) {
|
|
|
6146
6203
|
let profiles = { docs: [], total_docs: 0 };
|
|
6147
6204
|
|
|
6148
6205
|
if (filter_type !== 'pending') {
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6206
|
+
// User-picked order from the dashboard list controls, see
|
|
6207
|
+
// db_module.find_app_couch_sorted_page. Null when none was asked for,
|
|
6208
|
+
// which leaves the default newest-first path below untouched. The main
|
|
6209
|
+
// profile is still floated to the top of the page after enrichment.
|
|
6210
|
+
const sorted = profile_id ? null : await db_module.find_app_couch_sorted_page(app_id, opt, req, LIST_SORT_PATHS.account_profile);
|
|
6211
|
+
if (sorted) {
|
|
6212
|
+
profiles = sorted;
|
|
6152
6213
|
} else {
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6214
|
+
profiles = await db_module.find_app_couch_query(app_id, opt);
|
|
6215
|
+
if (!limit || profile_id) {
|
|
6216
|
+
profiles.total_docs = profiles.docs.length;
|
|
6217
|
+
} else {
|
|
6218
|
+
delete opt.sort;
|
|
6219
|
+
delete opt.skip;
|
|
6220
|
+
opt.limit = 9999;
|
|
6221
|
+
opt.fields = ['_id'];
|
|
6157
6222
|
|
|
6158
|
-
|
|
6159
|
-
|
|
6223
|
+
const counter = await db_module.find_app_couch_query(app_id, opt);
|
|
6224
|
+
profiles.total_docs = counter.docs.length;
|
|
6225
|
+
}
|
|
6160
6226
|
}
|
|
6161
6227
|
}
|
|
6162
6228
|
|
|
@@ -7092,7 +7158,6 @@ export const get_account_ai_usage_old = async function (req, job_id, headers) {
|
|
|
7092
7158
|
group_level: 999,
|
|
7093
7159
|
});
|
|
7094
7160
|
// console.log('ai_usage', ai_usage.rows);
|
|
7095
|
-
debugger;
|
|
7096
7161
|
let total_usage = 0;
|
|
7097
7162
|
let profile = {};
|
|
7098
7163
|
|