mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-06-22 06:03:49 +08:00
fix(account): ignore stale downloaded history
This commit is contained in:
+17
-1
@@ -419,6 +419,7 @@ const favoriteRequestGeneration = ref(0);
|
|||||||
const downloadedApps = ref<DownloadedAppRecord[]>([]);
|
const downloadedApps = ref<DownloadedAppRecord[]>([]);
|
||||||
const downloadedLoading = ref(false);
|
const downloadedLoading = ref(false);
|
||||||
const downloadedError = ref("");
|
const downloadedError = ref("");
|
||||||
|
const downloadedRequestGeneration = ref(0);
|
||||||
const systemInfo = ref<SystemInfo>({ distro: "unknown" });
|
const systemInfo = ref<SystemInfo>({ distro: "unknown" });
|
||||||
type PendingDownloadRecord = Omit<
|
type PendingDownloadRecord = Omit<
|
||||||
DownloadedAppRecord,
|
DownloadedAppRecord,
|
||||||
@@ -1411,6 +1412,7 @@ const clearFavoriteState = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const clearDownloadedState = () => {
|
const clearDownloadedState = () => {
|
||||||
|
downloadedRequestGeneration.value += 1;
|
||||||
downloadedApps.value = [];
|
downloadedApps.value = [];
|
||||||
downloadedLoading.value = false;
|
downloadedLoading.value = false;
|
||||||
downloadedError.value = "";
|
downloadedError.value = "";
|
||||||
@@ -1419,6 +1421,13 @@ const clearDownloadedState = () => {
|
|||||||
const isCurrentFavoriteRequest = (generation: number): boolean =>
|
const isCurrentFavoriteRequest = (generation: number): boolean =>
|
||||||
favoriteRequestGeneration.value === generation && isLoggedIn.value;
|
favoriteRequestGeneration.value === generation && isLoggedIn.value;
|
||||||
|
|
||||||
|
const isCurrentDownloadedRequest = (
|
||||||
|
generation: number,
|
||||||
|
userId: number,
|
||||||
|
): boolean =>
|
||||||
|
downloadedRequestGeneration.value === generation &&
|
||||||
|
currentUser.value?.id === userId;
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
logout();
|
logout();
|
||||||
pendingDownloadRecords.clear();
|
pendingDownloadRecords.clear();
|
||||||
@@ -1455,17 +1464,24 @@ const handleFlarumLogin = async (payload: FlarumLoginPayload) => {
|
|||||||
|
|
||||||
const loadDownloadedHistory = async (): Promise<void> => {
|
const loadDownloadedHistory = async (): Promise<void> => {
|
||||||
if (!requireLogin("请登录后查看和管理账号信息。")) return;
|
if (!requireLogin("请登录后查看和管理账号信息。")) return;
|
||||||
|
const userId = currentUser.value?.id;
|
||||||
|
if (userId === undefined) return;
|
||||||
|
const generation = downloadedRequestGeneration.value;
|
||||||
|
|
||||||
downloadedLoading.value = true;
|
downloadedLoading.value = true;
|
||||||
downloadedError.value = "";
|
downloadedError.value = "";
|
||||||
try {
|
try {
|
||||||
const result = await listDownloadedApps(1, 50);
|
const result = await listDownloadedApps(1, 50);
|
||||||
|
if (!isCurrentDownloadedRequest(generation, userId)) return;
|
||||||
downloadedApps.value = result.items;
|
downloadedApps.value = result.items;
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
if (!isCurrentDownloadedRequest(generation, userId)) return;
|
||||||
downloadedApps.value = [];
|
downloadedApps.value = [];
|
||||||
downloadedError.value = (error as Error)?.message || "读取下载历史失败";
|
downloadedError.value = (error as Error)?.message || "读取下载历史失败";
|
||||||
} finally {
|
} finally {
|
||||||
downloadedLoading.value = false;
|
if (isCurrentDownloadedRequest(generation, userId)) {
|
||||||
|
downloadedLoading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ import { fireEvent, render, screen, waitFor } from "@testing-library/vue";
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import App from "@/App.vue";
|
import App from "@/App.vue";
|
||||||
import { listFavoriteFolders } from "@/modules/backendApi";
|
import { listDownloadedApps, listFavoriteFolders } from "@/modules/backendApi";
|
||||||
import { setAuthSession } from "@/global/authState";
|
import { setAuthSession } from "@/global/authState";
|
||||||
import type { FavoriteFolder, FavoriteItem } from "@/global/typedefinition";
|
import type {
|
||||||
|
DownloadedAppList,
|
||||||
|
FavoriteFolder,
|
||||||
|
FavoriteItem,
|
||||||
|
} from "@/global/typedefinition";
|
||||||
|
|
||||||
const invoke = vi.fn();
|
const invoke = vi.fn();
|
||||||
|
|
||||||
@@ -39,6 +43,31 @@ const createDeferred = <T>() => {
|
|||||||
return { promise, resolve };
|
return { promise, resolve };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const downloadedList = (
|
||||||
|
items: DownloadedAppList["items"],
|
||||||
|
): DownloadedAppList => ({
|
||||||
|
items,
|
||||||
|
total: items.length,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setSecondUserSession = () => {
|
||||||
|
setAuthSession({
|
||||||
|
accessToken: "backend-token-b",
|
||||||
|
tokenType: "bearer",
|
||||||
|
user: {
|
||||||
|
id: 2,
|
||||||
|
flarumUserId: "84",
|
||||||
|
username: "second",
|
||||||
|
displayName: "Second User",
|
||||||
|
avatarUrl: "https://bbs.spark-app.store/avatar-b.png",
|
||||||
|
forumLevel: "用户",
|
||||||
|
forumGroups: ["用户"],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
vi.mock("axios", () => {
|
vi.mock("axios", () => {
|
||||||
const get = vi.fn(async (url: string) => {
|
const get = vi.fn(async (url: string) => {
|
||||||
if (url.includes("categories.json")) {
|
if (url.includes("categories.json")) {
|
||||||
@@ -109,6 +138,7 @@ vi.mock("@/modules/backendApi", () => ({
|
|||||||
bulkDeleteFavoriteItems: vi.fn(),
|
bulkDeleteFavoriteItems: vi.fn(),
|
||||||
createFavoriteFolder: vi.fn(),
|
createFavoriteFolder: vi.fn(),
|
||||||
exchangeFlarumToken: vi.fn(),
|
exchangeFlarumToken: vi.fn(),
|
||||||
|
listDownloadedApps: vi.fn(async () => downloadedList([])),
|
||||||
listFavoriteFolders: vi.fn(async () => favoriteFolders),
|
listFavoriteFolders: vi.fn(async () => favoriteFolders),
|
||||||
listFavoriteItems: vi.fn(async () => favoriteItems),
|
listFavoriteItems: vi.fn(async () => favoriteItems),
|
||||||
setBackendToken: vi.fn(),
|
setBackendToken: vi.fn(),
|
||||||
@@ -351,4 +381,60 @@ describe("App account placeholders", () => {
|
|||||||
expect(screen.queryByText("旧账号收藏夹")).toBeNull();
|
expect(screen.queryByText("旧账号收藏夹")).toBeNull();
|
||||||
expect(screen.queryByRole("dialog", { name: "选择收藏夹" })).toBeNull();
|
expect(screen.queryByRole("dialog", { name: "选择收藏夹" })).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("ignores downloaded history that resolves after switching users", async () => {
|
||||||
|
const firstHistory = createDeferred<DownloadedAppList>();
|
||||||
|
const secondHistory = createDeferred<DownloadedAppList>();
|
||||||
|
vi.mocked(listDownloadedApps)
|
||||||
|
.mockReturnValueOnce(firstHistory.promise)
|
||||||
|
.mockReturnValueOnce(secondHistory.promise);
|
||||||
|
render(App);
|
||||||
|
|
||||||
|
await fireEvent.click(await screen.findByRole("button", { name: /Momen/ }));
|
||||||
|
await fireEvent.click(screen.getByText("用户管理"));
|
||||||
|
expect(await screen.findByText("正在加载下载历史...")).toBeTruthy();
|
||||||
|
|
||||||
|
await fireEvent.click(
|
||||||
|
await screen.findByRole("button", { name: /^Momen$/ }),
|
||||||
|
);
|
||||||
|
if (!screen.queryByText("退出登录")) {
|
||||||
|
await fireEvent.click(
|
||||||
|
await screen.findByRole("button", { name: /^Momen$/ }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await fireEvent.click(screen.getByText("退出登录"));
|
||||||
|
setSecondUserSession();
|
||||||
|
|
||||||
|
const secondUserButton = await screen.findByRole("button", {
|
||||||
|
name: /^Second User$/,
|
||||||
|
});
|
||||||
|
if (!screen.queryByText("用户管理")) {
|
||||||
|
await fireEvent.click(secondUserButton);
|
||||||
|
}
|
||||||
|
await fireEvent.click(await screen.findByText("用户管理"));
|
||||||
|
secondHistory.resolve(downloadedList([]));
|
||||||
|
expect(await screen.findByText("暂无下载记录。")).toBeTruthy();
|
||||||
|
|
||||||
|
firstHistory.resolve(
|
||||||
|
downloadedList([
|
||||||
|
{
|
||||||
|
id: 77,
|
||||||
|
appKey: "app:office:old-account-app",
|
||||||
|
pkgname: "old-account-app",
|
||||||
|
name: "旧账号应用",
|
||||||
|
category: "office",
|
||||||
|
selectedOrigin: "apm",
|
||||||
|
version: "1.0.0",
|
||||||
|
packageArch: "amd64",
|
||||||
|
downloadedAt: "2026-05-18T00:00:00Z",
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
await firstHistory.promise;
|
||||||
|
await Promise.resolve();
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
expect(screen.queryByText("旧账号应用")).toBeNull();
|
||||||
|
expect(screen.getByText("暂无下载记录。")).toBeTruthy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user