From efa5518234bc429f057e1c78edf8d2a7424d5a0e Mon Sep 17 00:00:00 2001 From: cuixiaorui Date: Sun, 21 Jul 2024 17:47:13 +0800 Subject: [PATCH] refactor: get user info --- apps/api/src/user/tests/user.service.spec.ts | 41 +++++++++++------ apps/api/src/user/user.controller.ts | 2 +- apps/api/src/user/user.service.ts | 46 +++++++++++++------- apps/client/api/user.ts | 14 +++++- apps/client/app.vue | 24 +++++----- apps/client/services/auth.ts | 4 ++ apps/client/types/api/user.ts | 12 ----- apps/client/types/models/user.ts | 7 ++- 8 files changed, 94 insertions(+), 56 deletions(-) diff --git a/apps/api/src/user/tests/user.service.spec.ts b/apps/api/src/user/tests/user.service.spec.ts index 372015c14..5e9932f2e 100644 --- a/apps/api/src/user/tests/user.service.spec.ts +++ b/apps/api/src/user/tests/user.service.spec.ts @@ -37,7 +37,7 @@ describe("UserService", () => { }); describe("findUser", () => { - it("should return user info with membership details when user is a member", async () => { + it("should return user info with membership details", async () => { const userId = "testUserId"; const logtoUserInfo = { id: userId, name: "Test User" }; const membershipDetails = { @@ -46,6 +46,7 @@ describe("UserService", () => { endDate: new Date(), isActive: true, }; + (logtoServiceMock.logtoApi.get as jest.Mock).mockResolvedValue({ data: logtoUserInfo }); membershipServiceMock.isMember.mockResolvedValue(true); membershipServiceMock.getMembershipDetails.mockResolvedValue(membershipDetails); @@ -61,30 +62,44 @@ describe("UserService", () => { }); }); - it("should return user info without membership details when user is not a member", async () => { + it("should return undefined on error", async () => { const userId = "testUserId"; - const logtoUserInfo = { id: userId, name: "Test User" }; - - (logtoServiceMock.logtoApi.get as jest.Mock).mockResolvedValue({ data: logtoUserInfo }); - membershipServiceMock.isMember.mockResolvedValue(false); + (logtoServiceMock.logtoApi.get as jest.Mock).mockRejectedValue(new Error("API Error")); const result = await userService.findUser(userId); + expect(result).toBeUndefined(); + }); + }); + + describe("findCurrentUser", () => { + it("should return membership info for current user", async () => { + const userId = "testUserId"; + const membershipDetails = { + type: "founder", + startDate: new Date(), + endDate: new Date(), + isActive: true, + }; + + membershipServiceMock.isMember.mockResolvedValue(true); + membershipServiceMock.getMembershipDetails.mockResolvedValue(membershipDetails); + + const result = await userService.findCurrentUser(userId); + expect(result).toEqual({ - ...logtoUserInfo, membership: { - isMember: false, - details: null, + isMember: true, + details: membershipDetails, }, }); }); - it("should return undefined when there's an error fetching user info", async () => { + it("should return undefined on error", async () => { const userId = "testUserId"; + membershipServiceMock.isMember.mockRejectedValue(new Error("Service Error")); - (logtoServiceMock.logtoApi.get as jest.Mock).mockRejectedValue(new Error("API Error")); - - const result = await userService.findUser(userId); + const result = await userService.findCurrentUser(userId); expect(result).toBeUndefined(); }); diff --git a/apps/api/src/user/user.controller.ts b/apps/api/src/user/user.controller.ts index cc1e96ab7..a8d3820cd 100644 --- a/apps/api/src/user/user.controller.ts +++ b/apps/api/src/user/user.controller.ts @@ -17,7 +17,7 @@ export class UserController { @UseGuards(AuthGuard) @Get() async getCurrentUser(@User() user: UserEntity) { - const userInfo = await this.userService.findUser(user.userId); + const userInfo = await this.userService.findCurrentUser(user.userId); return userInfo; } diff --git a/apps/api/src/user/user.service.ts b/apps/api/src/user/user.service.ts index 04df2f6f1..037b359be 100644 --- a/apps/api/src/user/user.service.ts +++ b/apps/api/src/user/user.service.ts @@ -22,29 +22,45 @@ export class UserService { async findUser(uId: string) { try { - const { data: logtoUserInfo } = await this.logtoService.logtoApi.get( - `/api/users/${uId}`, - ); - const isMember = await this.membershipService.isMember(uId); - - let membershipInfo: MembershipDetails = null; - if (isMember) { - membershipInfo = await this.membershipService.getMembershipDetails(uId); - } - + const { data: logtoUserInfo } = await this.logtoService.logtoApi.get(`/api/users/${uId}`); + const membershipInfo = await this.getMembershipInfo(uId); return { ...logtoUserInfo, - membership: { - isMember, - details: membershipInfo, - }, + membership: membershipInfo, }; } catch (error) { - // 考虑是否需要更详细的错误处理 console.error("Error fetching user info:", error); return undefined; } } + + /** + * 返回当前登录用户的信息 + * logto 相关的信息是在 client 获取得 + * 所以这里只需要返回 earthworm 服务相关的信息就可以了(比如是否为会员) + * @param uId + * @returns + */ + async findCurrentUser(uId: string) { + try { + return { + membership: await this.getMembershipInfo(uId), + }; + } catch (error) { + console.error("Error fetching current user info:", error); + return undefined; + } + } + + private async getMembershipInfo(uId: string) { + const isMember = await this.membershipService.isMember(uId); + let details: MembershipDetails = null; + if (isMember) { + details = await this.membershipService.getMembershipDetails(uId); + } + return { isMember, details }; + } + async updateUser(user: UserEntity, dto: UpdateUserDto) { try { const { data } = await this.logtoService.logtoApi.patch(`/api/users/${user.userId}`, dto); diff --git a/apps/client/api/user.ts b/apps/client/api/user.ts index cf4cfad47..cb3d0f9d6 100644 --- a/apps/client/api/user.ts +++ b/apps/client/api/user.ts @@ -1,4 +1,5 @@ -import type { SetupUserApiResponse, UserApiResponse } from "~/types"; +import type { SetupUserApiResponse, User, UserApiResponse } from "~/types"; +import { fetchUserInfo } from "~/services/auth"; import { http } from "./http"; export async function fetchSetupNewUser(data: { username: string; avatar: string }) { @@ -6,5 +7,14 @@ export async function fetchSetupNewUser(data: { username: string; avatar: string } export async function fetchCurrentUser() { - return await http.get("/user"); + // 这里必须在 client 获取 user info + // 他会触发 token 的刷新 + const logtoUserInfo = await fetchUserInfo(); + const extraInfo = await http.get("/user"); + + return { + ...logtoUserInfo, + ...extraInfo, + avatar: logtoUserInfo!.picture || "", // 添加 avatar 字段,默认值为 picture ( picture 这个属性不够清晰 不喜欢) + } as User; } diff --git a/apps/client/app.vue b/apps/client/app.vue index ac8e8c6a3..f9bcd0fdd 100644 --- a/apps/client/app.vue +++ b/apps/client/app.vue @@ -1,17 +1,17 @@