merge upstream
Some checks failed
Build / build (pull_request) Failing after 1m2s

This commit is contained in:
2025-11-12 12:03:00 -08:00
13 changed files with 126 additions and 4 deletions

View File

@@ -0,0 +1,22 @@
import { getAccountIdForRequest } from "../../services/loginService.ts";
import { getInventory } from "../../services/inventoryService.ts";
import type { RequestHandler } from "express";
import { broadcastInventoryUpdate } from "../../services/wsService.ts";
export const setUmbraEchoesController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const request = req.body as ISetUmbraEchoesRequest;
const inventory = await getInventory(accountId, "Suits");
const suit = inventory.Suits.id(request.oid);
if (suit) {
suit.UmbraDate = request.UmbraDate ? new Date(request.UmbraDate) : undefined;
await inventory.save();
broadcastInventoryUpdate(req);
}
res.end();
};
interface ISetUmbraEchoesRequest {
oid: string;
UmbraDate: number;
}

View File

@@ -1,7 +1,7 @@
import { getLeaderboard } from "../../services/leaderboardService.ts";
import type { RequestHandler } from "express";
export const leaderboardController: RequestHandler = async (req, res) => {
export const leaderboardPostController: RequestHandler = async (req, res) => {
const payload = JSON.parse(String(req.body)) as ILeaderboardRequest;
res.json({
results: await getLeaderboard(
@@ -15,6 +15,33 @@ export const leaderboardController: RequestHandler = async (req, res) => {
});
};
export const leaderboardGetController: RequestHandler = async (req, res) => {
const payload: ILeaderboardRequest = {
field: "archived." + String(req.query.field),
before: Number(req.query.before),
after: Number(req.query.after),
pivotId: req.query.pivotAccountId ? String(req.query.pivotAccountId) : undefined,
guildId: undefined,
guildTier: undefined
};
res.json({
players: (
await getLeaderboard(
payload.field,
payload.before,
payload.after,
payload.pivotId,
payload.guildId,
payload.guildTier
)
).map(entry => ({
DisplayName: entry.n,
score: entry.s,
rank: entry.r
}))
});
};
interface ILeaderboardRequest {
field: string;
before: number;

View File

@@ -46,6 +46,7 @@ import { updateFingerprintController } from "../controllers/custom/updateFingerp
import { unlockLevelCapController } from "../controllers/custom/unlockLevelCapController.ts";
import { changeModularPartsController } from "../controllers/custom/changeModularPartsController.ts";
import { setInvigorationController } from "../controllers/custom/setInvigorationController.ts";
import { setUmbraEchoesController } from "../controllers/custom/setUmbraEchoesController.ts";
import { setAccountCheatController } from "../controllers/custom/setAccountCheatController.ts";
import { setGuildCheatController } from "../controllers/custom/setGuildCheatController.ts";
@@ -97,6 +98,7 @@ customRouter.post("/updateFingerprint", updateFingerprintController);
customRouter.post("/unlockLevelCap", unlockLevelCapController);
customRouter.post("/changeModularParts", changeModularPartsController);
customRouter.post("/setInvigoration", setInvigorationController);
customRouter.post("/setUmbraEchoes", setUmbraEchoesController);
customRouter.post("/setAccountCheat", setAccountCheatController);
customRouter.post("/setGuildCheat", setGuildCheatController);

View File

@@ -1,14 +1,15 @@
import express from "express";
import { viewController } from "../controllers/stats/viewController.ts";
import { uploadController } from "../controllers/stats/uploadController.ts";
import { leaderboardController } from "../controllers/stats/leaderboardController.ts";
import { leaderboardPostController, leaderboardGetController } from "../controllers/stats/leaderboardController.ts";
const statsRouter = express.Router();
statsRouter.get("/view.php", viewController);
statsRouter.get("/profileStats.php", viewController);
statsRouter.get("/leaderboard.php", leaderboardGetController);
statsRouter.post("/upload.php", uploadController);
statsRouter.post("/leaderboardWeekly.php", leaderboardController);
statsRouter.post("/leaderboardArchived.php", leaderboardController);
statsRouter.post("/leaderboardWeekly.php", leaderboardPostController);
statsRouter.post("/leaderboardArchived.php", leaderboardPostController);
export { statsRouter };

View File

@@ -822,6 +822,22 @@
</form>
</div>
</div>
<div id="umbraEchoes-card" class="card mb-3 d-none">
<h5 class="card-header" data-loc="detailedView_umbraEchoesLabel"></h5>
<div class="card-body">
<p data-loc="detailedView_umbraEchoesDescription"></p>
<form onsubmit="submitUmbraEchoes(event)">
<div class="mb-3">
<label for="umbraEchoes-expiry" class="form-label" data-loc="detailedView_umbraEchoesExpiryLabel"></label>
<input type="datetime-local" class="form-control" max="2038-01-19T03:14" id="umbraEchoes-expiry" onblur="this.value=new Date(this.value)>new Date(this.max)?new Date(this.max).toISOString().slice(0,16):this.value"/>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary" data-loc="general_setButton"></button>
<button type="button" class="btn btn-danger" onclick="setUmbraEchoes()" data-loc="code_remove"></button>
</div>
</form>
</div>
</div>
<div id="modularParts-card" class="card mb-3 d-none">
<h5 class="card-header" data-loc="detailedView_modularPartsLabel"></h5>
<div class="card-body">

View File

@@ -1652,6 +1652,12 @@ function updateInventory() {
formatDatetime("%Y-%m-%d %H:%M", Number(item.UpgradesExpiry?.$date.$numberLong)) || "";
}
if (item.ItemType != "/Lotus/Powersuits/Excalibur/ExcaliburUmbra") {
document.getElementById("umbraEchoes-card").classList.remove("d-none");
document.getElementById("umbraEchoes-expiry").value =
formatDatetime("%Y-%m-%d %H:%M", Number(item.UmbraDate?.$date.$numberLong)) || "";
}
{
document.getElementById("loadout-card").classList.remove("d-none");
const maxModConfigNum = Math.min(2 + (item.ModSlotPurchases ?? 0), 5);
@@ -3519,6 +3525,7 @@ single.getRoute("#detailedView-route").on("beforeload", function () {
document.getElementById("loadout-card").classList.add("d-none");
document.getElementById("archonShards-card").classList.add("d-none");
document.getElementById("edit-suit-invigorations-card").classList.add("d-none");
document.getElementById("umbraEchoes-card").classList.add("d-none");
document.getElementById("modularParts-card").classList.add("d-none");
document.getElementById("modularParts-form").innerHTML = "";
document.getElementById("valenceBonus-card").classList.add("d-none");
@@ -4257,6 +4264,25 @@ function setInvigoration(data) {
});
}
function submitUmbraEchoes(event) {
event.preventDefault();
const expiry = document.getElementById("umbraEchoes-expiry").value;
setUmbraEchoes({
UmbraDate: expiry ? new Date(expiry).getTime() : Date.now() + 1 * 24 * 60 * 60 * 1000
});
}
function setUmbraEchoes(data) {
const oid = new URLSearchParams(window.location.search).get("itemId");
$.post({
url: "/custom/setUmbraEchoes?" + window.authz,
contentType: "application/json",
data: JSON.stringify({ oid, ...data })
}).done(function () {
updateInventory();
});
}
function handleAbilityOverride(event, configIndex) {
event.preventDefault();
const urlParams = new URLSearchParams(window.location.search);

View File

@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Kräftigung`,
detailedView_loadoutLabel: `Loadouts`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% Fähigkeitsstärke`,
invigorations_offensive_AbilityRange: `+100% Fähigkeitsreichweite`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Fähigkeitsüberschreibung`,
abilityOverride_onSlot: `auf Slot`,
detailedView_umbraEchoesDescription: `Wird ein Warframe mit dieser Flüssigkeit injiziert, kann er selbstständig an der Seite des Operators kämpfen.`,
detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
mods_addRiven: `Riven hinzufügen`,
mods_fingerprint: `Fingerabdruck`,
mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,

View File

@@ -162,6 +162,7 @@ dict = {
detailedView_invigorationLabel: `Invigoration`,
detailedView_loadoutLabel: `Loadouts`,
detailedView_equipmentFeaturesLabel: `Equipment Features`,
detailedView_umbraEchoesLabel: `Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% Ability Strength`,
invigorations_offensive_AbilityRange: `+100% Ability Range`,
@@ -192,6 +193,9 @@ dict = {
abilityOverride_label: `Ability Override`,
abilityOverride_onSlot: `on slot`,
detailedView_umbraEchoesDescription: `Injecting this fluid into a Warframe will imbue it with the ability to fight autonomously alongside the Operator.`,
detailedView_umbraEchoesExpiryLabel: `Echo Expiry (optional)`,
mods_addRiven: `Add Riven`,
mods_fingerprint: `Fingerprint`,
mods_fingerprintHelp: `Need help with the fingerprint?`,

View File

@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Fortalecimiento`,
detailedView_loadoutLabel: `Equipamientos`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% Fuerza de Habilidad`,
invigorations_offensive_AbilityRange: `+100% Alcance de Habilidad`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Intercambio de Habilidad`,
abilityOverride_onSlot: `en el espacio`,
detailedView_umbraEchoesDescription: `Inyectar este fluido en un warframe lo imbuirá con la capacidad para luchar autónomamente junto a su operador.`,
detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
mods_addRiven: `Agregar Agrietado`,
mods_fingerprint: `Huella digital`,
mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`,

View File

@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Dynamisation`,
detailedView_loadoutLabel: `Équipements`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% de puissance de pouvoir`,
invigorations_offensive_AbilityRange: `+100% de portée de pouvoir`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Remplacement de pouvoir`,
abilityOverride_onSlot: `Sur l'emplacement`,
detailedView_umbraEchoesDescription: `L'injection de ce fluide dans une Warframe lui donnera la possibilité de se battre de manière autonome aux côtés de l'Opérateur.`,
detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
mods_addRiven: `Ajouter un riven`,
mods_fingerprint: `Empreinte`,
mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`,

View File

@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Воодушевление`,
detailedView_loadoutLabel: `Конфигурации`,
detailedView_equipmentFeaturesLabel: `Модификаторы снаряжения`,
detailedView_umbraEchoesLabel: `Эхо Умбры`,
invigorations_offensive_AbilityStrength: `+200% к силе способностей.`,
invigorations_offensive_AbilityRange: `+100% к зоне поражения способностей.`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Переопределение способности`,
abilityOverride_onSlot: `в ячейке`,
detailedView_umbraEchoesDescription: `Введение этой жидкости в варфрейм позволит ему автономно сражаться бок о бок с оператором.`,
detailedView_umbraEchoesExpiryLabel: `Срок действия Эха (необязательно)`,
mods_addRiven: `Добавить мод Разлома`,
mods_fingerprint: `Отпечаток`,
mods_fingerprintHelp: `Нужна помощь с отпечатком?`,

View File

@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `Зміцнення`,
detailedView_loadoutLabel: `Конфігурації`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200% до потужності здібностей.`,
invigorations_offensive_AbilityRange: `+100% до досяжності здібностей.`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `Перевизначення здібностей`,
abilityOverride_onSlot: `у комірці`,
detailedView_umbraEchoesDescription: `Рідина, яка після введення дозволяє ворфрейму використовувати єдність і битися самостійно пліч-о-пліч з оператором.`,
detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
mods_addRiven: `Добавити модифікатор Розколу`,
mods_fingerprint: `Відбиток`,
mods_fingerprintHelp: `Потрібна допомога з відбитком?`,

View File

@@ -163,6 +163,7 @@ dict = {
detailedView_invigorationLabel: `活化`,
detailedView_loadoutLabel: `配置`,
detailedView_equipmentFeaturesLabel: `[UNTRANSLATED] Equipment Features`,
detailedView_umbraEchoesLabel: `[UNTRANSLATED] Echoes Of Umbra`,
invigorations_offensive_AbilityStrength: `+200%技能强度`,
invigorations_offensive_AbilityRange: `+100%技能范围`,
@@ -193,6 +194,9 @@ dict = {
abilityOverride_label: `技能替换`,
abilityOverride_onSlot: `槽位`,
detailedView_umbraEchoesDescription: `将这种液体注入战甲内,使其具有与指挥官并肩作战的能力。`,
detailedView_umbraEchoesExpiryLabel: `[UNTRANSLATED] Echo Expiry (optional)`,
mods_addRiven: `添加裂罅MOD`,
mods_fingerprint: `印记`,
mods_fingerprintHelp: `需要印记相关的帮助?`,