feat: save opening booster inventory independently
This commit is contained in:
@@ -46,13 +46,22 @@ export default async function (ctx: FunctionContext) {
|
||||
data.infiniteRocketTime = user.data?.infiniteRocketTime || 0;
|
||||
let propType = Number(ctx.body.propType);
|
||||
let propData = ctx.body.propData;
|
||||
const boosterField = propType === 2004 ? "hourglassAmount" : propType === 2005 ? "rocketAmount" : null;
|
||||
if (!propType && propType != 0) {
|
||||
return { code: 0, data: null, msg: "未获取到propType" };
|
||||
}
|
||||
if (!propData) {
|
||||
if (!propData && !(boosterField && propData === 0)) {
|
||||
return { code: 0, data: null, msg: "未获取到propData" }
|
||||
}
|
||||
if (propType === 2001) {
|
||||
if (boosterField) {
|
||||
const amount = Number(propData);
|
||||
if ((typeof propData !== "number" && typeof propData !== "string")
|
||||
|| (typeof propData === "string" && !propData.trim())
|
||||
|| !Number.isSafeInteger(amount) || amount < 0) {
|
||||
return { code: 0, data: null, msg: "道具数量必须是非负整数" };
|
||||
}
|
||||
data[boosterField] = amount;
|
||||
} else if (propType === 2001) {
|
||||
data.freezeAmount = Number(propData);
|
||||
} else if (propType === 2002) {
|
||||
data.hammerAmount = Number(propData);
|
||||
@@ -75,7 +84,9 @@ export default async function (ctx: FunctionContext) {
|
||||
if (propData.infinite_hourglass !== undefined) data.infiniteHourglassTime = Number(propData.infinite_hourglass);
|
||||
if (propData.infinite_rocket !== undefined) data.infiniteRocketTime = Number(propData.infinite_rocket);
|
||||
}
|
||||
let ret = await db.collection(dbname).where({ _id: uid }).update(data);
|
||||
let ret = await db.collection(dbname).where({ _id: uid }).update(boosterField
|
||||
? { [boosterField]: data[boosterField], timestamp: data.timestamp }
|
||||
: data);
|
||||
return {
|
||||
code: 1, data: {
|
||||
freeze: data.freezeAmount,
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { registerHooks } from "node:module";
|
||||
|
||||
let user;
|
||||
let writes;
|
||||
let beforeUpdate;
|
||||
globalThis.__boosterPropCloudMock = {
|
||||
database: () => ({
|
||||
collection: () => ({
|
||||
where: () => ({
|
||||
getOne: async () => ({ data: { ...user } }),
|
||||
async update(update) {
|
||||
beforeUpdate?.();
|
||||
writes.push({ ...update });
|
||||
Object.assign(user, update);
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
};
|
||||
registerHooks({
|
||||
load(url, context, next) {
|
||||
return next(url, url.endsWith(".ts") ? { ...context, format: "module-typescript" } : context);
|
||||
},
|
||||
resolve(specifier, context, next) {
|
||||
if (specifier === "@lafjs/cloud") {
|
||||
return { url: "data:text/javascript,export default globalThis.__boosterPropCloudMock", shortCircuit: true };
|
||||
}
|
||||
if (specifier === "@/Utils") {
|
||||
return { url: "data:text/javascript,export default {checkToken:(actual,expected)=>actual===expected}", shortCircuit: true };
|
||||
}
|
||||
return next(specifier, context);
|
||||
},
|
||||
});
|
||||
const { default: userProp } = await import("../functions/userProp.ts");
|
||||
|
||||
function reset() {
|
||||
user = {
|
||||
token: "valid", freezeAmount: 1, hammerAmount: 2, magicAmount: 3,
|
||||
hourglassAmount: 4, rocketAmount: 5, infiniteHourglassTime: 100, infiniteRocketTime: 200,
|
||||
};
|
||||
writes = [];
|
||||
beforeUpdate = null;
|
||||
}
|
||||
|
||||
function save(propType, propData, extra = {}) {
|
||||
return userProp({ body: { uid: "u1", token: "valid", action: "save", propType, propData, ...extra } });
|
||||
}
|
||||
|
||||
for (const [propType, field, responseField] of [[2004, "hourglassAmount", "hourglass"], [2005, "rocketAmount", "rocket"]]) {
|
||||
test(`${propType} saves only its own count and timestamp`, async () => {
|
||||
reset();
|
||||
const original = { ...user };
|
||||
const result = await save(propType, JSON.stringify(7));
|
||||
assert.equal(result.code, 1);
|
||||
assert.equal(result.data[responseField], 7);
|
||||
assert.deepEqual(Object.keys(writes[0]).sort(), [field, "timestamp"].sort());
|
||||
assert.deepEqual(user, { ...original, [field]: 7, timestamp: writes[0].timestamp });
|
||||
});
|
||||
|
||||
test(`${propType} can consume the last item using string or numeric zero`, async () => {
|
||||
for (const value of ["0", 0]) {
|
||||
reset();
|
||||
assert.equal((await save(propType, value)).code, 1);
|
||||
assert.equal(user[field], 0);
|
||||
}
|
||||
});
|
||||
|
||||
test(`${propType} does not undo concurrent changes to another prop or infinite entitlement`, async () => {
|
||||
reset();
|
||||
const otherField = propType === 2004 ? "rocketAmount" : "hourglassAmount";
|
||||
beforeUpdate = () => Object.assign(user, { hammerAmount: 8, [otherField]: 9, infiniteRocketTime: 999 });
|
||||
await save(propType, "2");
|
||||
assert.equal(user[field], 2);
|
||||
assert.equal(user.hammerAmount, 8);
|
||||
assert.equal(user[otherField], 9);
|
||||
assert.equal(user.infiniteRocketTime, 999);
|
||||
});
|
||||
|
||||
test(`${propType} rejects invalid inventory amounts without writing`, async () => {
|
||||
for (const value of [undefined, null, "", " ", -1, "-1", 1.5, "NaN", Infinity, true, {}, []]) {
|
||||
reset();
|
||||
assert.equal((await save(propType, value)).code, 0);
|
||||
assert.deepEqual(writes, []);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test("invalid token cannot change either new prop", async () => {
|
||||
for (const propType of [2004, 2005]) {
|
||||
reset();
|
||||
assert.equal((await save(propType, "3", { token: "invalid" })).code, 0);
|
||||
assert.deepEqual(writes, []);
|
||||
}
|
||||
});
|
||||
|
||||
test("legacy single-prop and all-prop requests retain their existing behavior", async () => {
|
||||
reset();
|
||||
assert.equal((await save(2001, "0")).code, 1);
|
||||
assert.equal(user.freezeAmount, 0);
|
||||
assert.equal((await save(2001, 0)).code, 0);
|
||||
assert.equal((await save(0, JSON.stringify({ hourglass: 6, rocket: 0, infinite_hourglass: 123 }))).code, 1);
|
||||
assert.equal(user.hourglassAmount, 6);
|
||||
assert.equal(user.rocketAmount, 0);
|
||||
assert.equal(user.infiniteHourglassTime, 123);
|
||||
assert.equal(user.hammerAmount, 2);
|
||||
});
|
||||
Reference in New Issue
Block a user