feat: 2.3.1
This commit is contained in:
@@ -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 });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user