feat: 2.3.1

This commit is contained in:
2026-05-12 17:55:53 +08:00
parent 13f3c3d591
commit 7ca11c6534
28 changed files with 1328 additions and 578 deletions
+230
View File
@@ -52,9 +52,13 @@ function InitModule(ctx, logger, nk, initializer) {
// Inbox System RPCs
initializer.registerRpc("admin_send_mail", rpcAdminSendMail);
initializer.registerRpc("admin_list_mail", rpcAdminListMail);
initializer.registerRpc("admin_update_mail", rpcAdminUpdateMail);
initializer.registerRpc("admin_delete_mail_server", rpcAdminDeleteMailServer);
initializer.registerRpc("get_mail", rpcGetMail);
initializer.registerRpc("claim_mail_reward", rpcClaimMailReward);
initializer.registerRpc("delete_mail", rpcDeleteMail);
initializer.registerRpc("save_mail_state", rpcSaveMailState);
// Steam auth hooks
initializer.registerAfterAuthenticateSteam(afterAuthenticateSteam);
@@ -1712,3 +1716,229 @@ function rpcDeleteMail(ctx, logger, nk, payload) {
return JSON.stringify({ success: true, deleted_ids: state.deleted_ids });
}
function rpcSaveMailState(ctx, logger, nk, payload) {
if (!ctx.userId) throw new Error("Not authenticated");
var request = JSON.parse(payload || "{}");
// Load existing state to merge (don't clobber claimed_ids from client)
var stateObjs = nk.storageRead([{ collection: "inbox", key: "state", userId: ctx.userId }]);
var state = { claimed_ids: [], deleted_ids: [], read_ids: [] };
if (stateObjs && stateObjs.length > 0) {
var val = stateObjs[0].value;
state.claimed_ids = val.claimed_ids || [];
state.deleted_ids = val.deleted_ids || [];
state.read_ids = val.read_ids || [];
}
// Merge read_ids from client (add any new ones)
var newReadIds = request.read_ids || [];
for (var i = 0; i < newReadIds.length; i++) {
if (state.read_ids.indexOf(newReadIds[i]) === -1) {
state.read_ids.push(newReadIds[i]);
}
}
nk.storageWrite([{
collection: "inbox",
key: "state",
userId: ctx.userId,
value: state,
permissionRead: 1,
permissionWrite: 0
}]);
return JSON.stringify({ success: true });
}
// =============================================================================
// Admin Mail Management RPCs
// =============================================================================
function rpcAdminListMail(ctx, logger, nk, payload) {
requireAdmin(ctx, nk);
// --- Global mails ---
var globalObjs = nk.storageRead([{ collection: "config", key: "global_mail", userId: "00000000-0000-0000-0000-000000000000" }]);
var globalMails = (globalObjs && globalObjs.length > 0) ? (globalObjs[0].value.mails || []) : [];
for (var i = 0; i < globalMails.length; i++) {
globalMails[i].type = "global";
}
// --- Personal mails: scan ALL users' inbox/personal objects ---
var personalMails = [];
var cursor = null;
try {
do {
// storageList(userId, collection, limit, cursor)
// Using empty string userId means list across all users for this collection
var listResult = nk.storageList("", "inbox", 100, cursor);
var objects = listResult.objects || [];
for (var j = 0; j < objects.length; j++) {
var obj = objects[j];
if (obj.key !== "personal") continue;
var ownerUserId = obj.userId;
var mails = obj.value.mails || [];
for (var k = 0; k < mails.length; k++) {
var m = mails[k];
m.type = "personal";
m.target_user_id = ownerUserId;
personalMails.push(m);
}
}
cursor = listResult.cursor || null;
} while (cursor);
} catch (e) {
logger.warn("admin_list_mail: could not list personal inboxes: " + e);
}
var allMails = globalMails.concat(personalMails);
// Sort newest first
allMails.sort(function(a, b) {
return (b.date || "").localeCompare(a.date || "");
});
return JSON.stringify({ mails: allMails });
}
function rpcAdminUpdateMail(ctx, logger, nk, payload) {
requireAdmin(ctx, nk);
var request = JSON.parse(payload || "{}");
var mailId = request.mail_id;
if (!mailId) throw new Error("mail_id required");
var isGlobal = request.type !== "personal";
var targetUserId = request.target_user_id || "";
var newTargetUserId = request.new_target_user_id;
var hasNewTarget = (newTargetUserId !== undefined && newTargetUserId !== null);
// Step 1: Find and extract the mail object from its current location
var mailObj = null;
if (isGlobal) {
var globalObjs = nk.storageRead([{ collection: "config", key: "global_mail", userId: "00000000-0000-0000-0000-000000000000" }]);
var globalMails = (globalObjs && globalObjs.length > 0) ? (globalObjs[0].value.mails || []) : [];
for (var i = 0; i < globalMails.length; i++) {
if (globalMails[i].id === mailId) {
mailObj = globalMails.splice(i, 1)[0];
break;
}
}
if (!mailObj) throw new Error("Mail not found in global");
// Write back without this mail (it may move)
nk.storageWrite([{
collection: "config",
key: "global_mail",
userId: "00000000-0000-0000-0000-000000000000",
value: { mails: globalMails },
permissionRead: 2,
permissionWrite: 0
}]);
} else {
if (!targetUserId) throw new Error("target_user_id required for personal mail");
var pObjs = nk.storageRead([{ collection: "inbox", key: "personal", userId: targetUserId }]);
var personalMails = (pObjs && pObjs.length > 0) ? (pObjs[0].value.mails || []) : [];
for (var j = 0; j < personalMails.length; j++) {
if (personalMails[j].id === mailId) {
mailObj = personalMails.splice(j, 1)[0];
break;
}
}
if (!mailObj) throw new Error("Mail not found in personal inbox");
// Write back without this mail
nk.storageWrite([{
collection: "inbox",
key: "personal",
userId: targetUserId,
value: { mails: personalMails },
permissionRead: 1,
permissionWrite: 0
}]);
}
// Step 2: Apply field updates to the mail object
if (request.title !== undefined) mailObj.title = request.title;
if (request.content !== undefined) mailObj.content = request.content;
if (request.end_date !== undefined) mailObj.end_date = request.end_date;
if (request.expiry_date !== undefined) mailObj.expiry_date = request.expiry_date;
// Step 3: Determine destination
var destUserId = hasNewTarget ? newTargetUserId : (isGlobal ? "" : targetUserId);
if (destUserId === "") {
// Write to global
mailObj.type = "global";
var gObjs = nk.storageRead([{ collection: "config", key: "global_mail", userId: "00000000-0000-0000-0000-000000000000" }]);
var gMails = (gObjs && gObjs.length > 0) ? (gObjs[0].value.mails || []) : [];
gMails.push(mailObj);
nk.storageWrite([{
collection: "config",
key: "global_mail",
userId: "00000000-0000-0000-0000-000000000000",
value: { mails: gMails },
permissionRead: 2,
permissionWrite: 0
}]);
} else {
// Write to personal inbox of destUserId
mailObj.type = "personal";
var dObjs = nk.storageRead([{ collection: "inbox", key: "personal", userId: destUserId }]);
var dMails = (dObjs && dObjs.length > 0) ? (dObjs[0].value.mails || []) : [];
dMails.push(mailObj);
nk.storageWrite([{
collection: "inbox",
key: "personal",
userId: destUserId,
value: { mails: dMails },
permissionRead: 1,
permissionWrite: 0
}]);
}
logger.info("Admin updated mail " + mailId + " by " + ctx.userId + (hasNewTarget ? " (moved to " + destUserId + ")" : ""));
return JSON.stringify({ success: true });
}
function rpcAdminDeleteMailServer(ctx, logger, nk, payload) {
requireAdmin(ctx, nk);
var request = JSON.parse(payload || "{}");
var mailId = request.mail_id;
if (!mailId) throw new Error("mail_id required");
var isGlobal = request.type !== "personal";
var targetUserId = request.target_user_id || "";
if (isGlobal) {
var globalObjs = nk.storageRead([{ collection: "config", key: "global_mail", userId: "00000000-0000-0000-0000-000000000000" }]);
var globalMails = (globalObjs && globalObjs.length > 0) ? (globalObjs[0].value.mails || []) : [];
var before = globalMails.length;
globalMails = globalMails.filter(function(m) { return m.id !== mailId; });
if (globalMails.length === before) throw new Error("Mail not found");
nk.storageWrite([{
collection: "config",
key: "global_mail",
userId: "00000000-0000-0000-0000-000000000000",
value: { mails: globalMails },
permissionRead: 2,
permissionWrite: 0
}]);
} else {
if (!targetUserId) throw new Error("target_user_id required for personal mail");
var pObjs = nk.storageRead([{ collection: "inbox", key: "personal", userId: targetUserId }]);
var personalMails = (pObjs && pObjs.length > 0) ? (pObjs[0].value.mails || []) : [];
var pBefore = personalMails.length;
personalMails = personalMails.filter(function(m) { return m.id !== mailId; });
if (personalMails.length === pBefore) throw new Error("Mail not found");
nk.storageWrite([{
collection: "inbox",
key: "personal",
userId: targetUserId,
value: { mails: personalMails },
permissionRead: 1,
permissionWrite: 0
}]);
}
logger.info("Admin deleted mail " + mailId + " from server by " + ctx.userId);
return JSON.stringify({ success: true });
}