mirror of
https://github.com/TautvydasDerzinskas/Thingport.git
synced 2026-10-20 21:59:53 -05:00
fix: skip a stale MakerWorld defaultInstanceId when picking the print profile (#15)
MakerWorld can leave a design's defaultInstanceId pointing at a print profile that no longer exists. pickMakerworldInstanceId (extension) and makerworldInstanceIdFromNextData (backend) returned it unchecked, so the download-link request went to the dead profile and MakerWorld answered 403 "The client does not have access rights to the content." Use the default only when it is still one of the design's instances, otherwise the first, as selectMakerworldProfiles already does. Fixes #14 Claude-Session: https://claude.ai/code/session_01KGCb65Zhzwd3daF862ZE6R Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
76907212d4
commit
d5ae80951c
3 files changed
+42
-7
No files matched your search
@@ -536,13 +536,15 @@ export function extractPageMetadata(html: string, pageHost: string): ImportedPag
|
||||
return meta;
|
||||
}
|
||||
|
||||
/** The profile named in the URL hash (if the design has it), then the default, then the first. */
|
||||
function makerworldInstanceIdFromNextData(data: unknown, requestedInstanceId: string | null): string | null {
|
||||
/** The profile named in the URL hash (if the design has it), then the default (if the design still
|
||||
* has it), then the first. MakerWorld can leave `defaultInstanceId` pointing at a deleted profile,
|
||||
* whose download answers 403 "The client does not have access rights to the content." */
|
||||
export function makerworldInstanceIdFromNextData(data: unknown, requestedInstanceId: string | null): string | null {
|
||||
const design = getPath(data, "props", "pageProps", "design") as Record<string, unknown> | undefined;
|
||||
if (!design) return null;
|
||||
if (requestedInstanceId && makerworldDesignHasInstance(design, requestedInstanceId)) return requestedInstanceId;
|
||||
const defaultInstance = design.defaultInstanceId;
|
||||
if (defaultInstance) return String(defaultInstance);
|
||||
if (defaultInstance && makerworldDesignHasInstance(design, String(defaultInstance))) return String(defaultInstance);
|
||||
const instances = design.instances;
|
||||
if (Array.isArray(instances)) {
|
||||
for (const inst of instances) {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { makerworldInstanceIdFromNextData } from "../src/services/importResolvers";
|
||||
|
||||
function nextData(design: Record<string, unknown>) {
|
||||
return { props: { pageProps: { design } } };
|
||||
}
|
||||
|
||||
describe("makerworldInstanceIdFromNextData", () => {
|
||||
const design = { defaultInstanceId: 2, instances: [{ id: 1 }, { id: 2 }, { id: 3 }] };
|
||||
|
||||
it("takes the link's profile, else the default, else the first", () => {
|
||||
expect(makerworldInstanceIdFromNextData(nextData(design), "3")).toBe("3");
|
||||
expect(makerworldInstanceIdFromNextData(nextData(design), null)).toBe("2");
|
||||
expect(makerworldInstanceIdFromNextData(nextData(design), "999")).toBe("2");
|
||||
expect(makerworldInstanceIdFromNextData(nextData({ instances: [{ id: 7 }] }), null)).toBe("7");
|
||||
});
|
||||
|
||||
// Seen on MakerWorld model 1106505: defaultInstanceId 1102432, but the only profile is 1113369.
|
||||
// Downloading the stale default answers 403 "The client does not have access rights to the content."
|
||||
it("skips a default that is no longer one of the design's profiles", () => {
|
||||
const stale = { defaultInstanceId: 1102432, instances: [{ id: 1113369 }] };
|
||||
expect(makerworldInstanceIdFromNextData(nextData(stale), null)).toBe("1113369");
|
||||
});
|
||||
|
||||
it("answers null without a design or profiles", () => {
|
||||
expect(makerworldInstanceIdFromNextData({}, null)).toBeNull();
|
||||
expect(makerworldInstanceIdFromNextData(nextData({ defaultInstanceId: 5, instances: [] }), null)).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -100,12 +100,16 @@ export async function loadMakerworldCollectionTotal(pageUrl: string): Promise<nu
|
||||
);
|
||||
}
|
||||
|
||||
/** The requested profile (if the design has it), then the default, then the first. */
|
||||
/** The requested profile (if the design has it), then the default (if the design still has it),
|
||||
* then the first. MakerWorld can leave `defaultInstanceId` pointing at a profile that was since
|
||||
* deleted, and asking for that one's download answers 403 "The client does not have access rights
|
||||
* to the content." */
|
||||
export function pickMakerworldInstanceId(design: MakerworldDesign, requestedInstanceId: string | null): string | null {
|
||||
const instances = Array.isArray(design.instances) ? design.instances.filter((inst) => inst && inst.id) : [];
|
||||
if (requestedInstanceId && instances.some((inst) => String(inst.id) === requestedInstanceId))
|
||||
return requestedInstanceId;
|
||||
if (design.defaultInstanceId) return String(design.defaultInstanceId);
|
||||
const has = (id: string) => instances.some((inst) => String(inst.id) === id);
|
||||
if (requestedInstanceId && has(requestedInstanceId)) return requestedInstanceId;
|
||||
const defaultId = design.defaultInstanceId ? String(design.defaultInstanceId) : null;
|
||||
if (defaultId && has(defaultId)) return defaultId;
|
||||
return instances.length ? String(instances[0].id) : null;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user