mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-01 19:38:13 +03:00
fix: better error handling on failed imports
This commit is contained in:
@@ -126,7 +126,7 @@ export async function PerformScoreImport(
|
||||
authToken,
|
||||
);
|
||||
|
||||
if (pollRes.success) {
|
||||
if (pollRes.success && pollRes.statusCode < 400) {
|
||||
if (pollRes.body.importStatus === "completed") {
|
||||
// is there even a nice way around this --
|
||||
// why *are* we nested so deeply?
|
||||
@@ -138,15 +138,27 @@ export async function PerformScoreImport(
|
||||
return pollRes.body.import;
|
||||
}
|
||||
|
||||
if (interaction) {
|
||||
void interaction.editReply(
|
||||
`Importing Scores: ${pollRes.body.progress.description}..`,
|
||||
);
|
||||
}
|
||||
if (pollRes.body.importStatus === "ongoing") {
|
||||
const progress = pollRes.body.progress;
|
||||
const description =
|
||||
progress &&
|
||||
typeof progress === "object" &&
|
||||
"description" in progress &&
|
||||
typeof progress.description === "string"
|
||||
? progress.description
|
||||
: "Importing.";
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Sleep(1000);
|
||||
} else {
|
||||
if (interaction) {
|
||||
void interaction.editReply(`Importing Scores: ${description}..`);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Sleep(1000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pollRes.success || pollRes.statusCode >= 400) {
|
||||
// silly kai bug they won't ever fix. hacking around it in the bot here.
|
||||
if (/attempting reauthentication/u.exec(pollRes.description)) {
|
||||
throw new Error(`Failed to import scores.
|
||||
@@ -157,6 +169,10 @@ Please go to ${Env.TACHI_SERVER_LOCATION}/u/me/integrations/services to un-link
|
||||
|
||||
throw new Error(`Failed to import scores. ${pollRes.description}.`);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Failed to import scores. ${pollRes.description ?? "Unexpected poll response."}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export default function ImportStateRenderer({ state: s }: { state: ImportStates
|
||||
have, this might take a while.
|
||||
</div>
|
||||
<Divider />
|
||||
<div>{s.progressInfo.description ?? "Importing."}..</div>
|
||||
<div>{s.progressInfo?.description ?? "Importing."}..</div>
|
||||
</>
|
||||
) : s.state === "done" ? (
|
||||
<>
|
||||
|
||||
@@ -64,27 +64,44 @@ export default function useImport(url: string, options: RequestInit) {
|
||||
`/imports/${initRes.body.importID}/poll-status`,
|
||||
);
|
||||
|
||||
if (pollRes.success) {
|
||||
if (pollRes.body.importStatus === "completed") {
|
||||
isImportFinished = true;
|
||||
if (importState.state === "done") {
|
||||
setImportState({ ...importState, import: pollRes.body.import });
|
||||
} else {
|
||||
setImportState({ state: "done", import: pollRes.body.import });
|
||||
}
|
||||
} else {
|
||||
setImportState({
|
||||
state: "waiting_processing",
|
||||
progressInfo: pollRes.body.progress,
|
||||
});
|
||||
|
||||
await Sleep(1000);
|
||||
}
|
||||
} else {
|
||||
if (!pollRes.success || pollRes.statusCode >= 400) {
|
||||
setImportState({ state: "failed", error: pollRes.description });
|
||||
isImportFinished = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pollRes.body.importStatus === "completed") {
|
||||
isImportFinished = true;
|
||||
setImportState({ state: "done", import: pollRes.body.import });
|
||||
} else if (pollRes.body.importStatus === "ongoing") {
|
||||
const progress = pollRes.body.progress;
|
||||
const description =
|
||||
progress &&
|
||||
typeof progress === "object" &&
|
||||
"description" in progress &&
|
||||
typeof progress.description === "string"
|
||||
? progress.description
|
||||
: "Importing.";
|
||||
|
||||
setImportState({
|
||||
state: "waiting_processing",
|
||||
progressInfo: { description },
|
||||
});
|
||||
|
||||
await Sleep(1000);
|
||||
} else {
|
||||
setImportState({
|
||||
state: "failed",
|
||||
error: pollRes.description ?? "Import failed.",
|
||||
});
|
||||
isImportFinished = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setImportState({
|
||||
state: "failed",
|
||||
error: initRes.description ?? "Import failed.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -285,4 +285,25 @@ describe("GET /api/v1/imports/:importID/poll-status", () => {
|
||||
expect(res.body.body.importStatus).toBe("completed");
|
||||
expect(res.body.body.import.importID).toBe(FakeImport.importID);
|
||||
});
|
||||
|
||||
it("returns 400 with success false when import_tracker records a failure", async () => {
|
||||
const { id: userID } = await seedUser({ username: "poll_failed_user" });
|
||||
|
||||
await DB.insertInto("import_tracker")
|
||||
.values({
|
||||
import_id: "failed-import",
|
||||
user_id: userID,
|
||||
import_type: "file/batch-manual",
|
||||
user_intent: true,
|
||||
time_started: new Date().toISOString(),
|
||||
error: { message: "Invalid score file.", statusCode: 400 },
|
||||
})
|
||||
.execute();
|
||||
|
||||
const res = await mockApi.get("/api/v1/imports/failed-import/poll-status");
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.success).toBe(false);
|
||||
expect(res.body.description).toBe("Invalid score file.");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -210,15 +210,16 @@ API_V1_ROUTER.add("GET /imports/:importID/poll-status", async ({ params }) => {
|
||||
|
||||
switch (tracker.type) {
|
||||
case "ONGOING":
|
||||
return success("Import is ongoing.", { importStatus: "ongoing", progress: 0 });
|
||||
return success("Import is ongoing.", {
|
||||
importStatus: "ongoing",
|
||||
progress: { description: "Importing scores." },
|
||||
});
|
||||
|
||||
case "FAILED":
|
||||
return {
|
||||
$status: tracker.error.statusCode ?? 500,
|
||||
body: {},
|
||||
description: tracker.error.message,
|
||||
success: true as const,
|
||||
};
|
||||
throw new ExpectedErr(
|
||||
tracker.error.statusCode ?? 500,
|
||||
tracker.error.message,
|
||||
);
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -242,15 +243,13 @@ API_V1_ROUTER.add("GET /imports/:importID/poll-status", async ({ params }) => {
|
||||
const tracker = await GetImportTrackerByImportId(params.importID);
|
||||
|
||||
if (tracker?.type === "FAILED") {
|
||||
return {
|
||||
$status: tracker.error.statusCode ?? 500,
|
||||
body: {},
|
||||
description: tracker.error.message,
|
||||
success: true as const,
|
||||
};
|
||||
throw new ExpectedErr(tracker.error.statusCode ?? 500, tracker.error.message);
|
||||
}
|
||||
|
||||
return success("Import is ongoing.", { importStatus: "ongoing", progress: 0 });
|
||||
return success("Import is ongoing.", {
|
||||
importStatus: "ongoing",
|
||||
progress: { description: "Importing scores." },
|
||||
});
|
||||
}
|
||||
|
||||
throw new ExpectedErr(500, "Unrecognised job queue state.");
|
||||
|
||||
Reference in New Issue
Block a user