Handle own profile 404 (#11319)
							parent
							
								
									a47ee92094
								
							
						
					
					
						commit
						e33a7e41a4
					
				|  | @ -19,6 +19,7 @@ import { User, UserEvent } from "matrix-js-sdk/src/models/user"; | |||
| import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; | ||||
| import { throttle } from "lodash"; | ||||
| import { EventType } from "matrix-js-sdk/src/@types/event"; | ||||
| import { MatrixError } from "matrix-js-sdk/src/matrix"; | ||||
| 
 | ||||
| import { ActionPayload } from "../dispatcher/payloads"; | ||||
| import { AsyncStoreWithClient } from "./AsyncStoreWithClient"; | ||||
|  | @ -45,7 +46,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> { | |||
| 
 | ||||
|     private monitoredUser: User | null = null; | ||||
| 
 | ||||
|     private constructor() { | ||||
|     public constructor() { | ||||
|         // seed from localstorage because otherwise we won't get these values until a whole network
 | ||||
|         // round-trip after the client is ready, and we often load widgets in that time, and we'd
 | ||||
|         // and up passing them an incorrect display name
 | ||||
|  | @ -136,12 +137,32 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> { | |||
|             if (!this.matrixClient) return; | ||||
|             // We specifically do not use the User object we stored for profile info as it
 | ||||
|             // could easily be wrong (such as per-room instead of global profile).
 | ||||
|             const profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getSafeUserId()); | ||||
| 
 | ||||
|             let profileInfo: { displayname?: string; avatar_url?: string } = { | ||||
|                 displayname: undefined, | ||||
|                 avatar_url: undefined, | ||||
|             }; | ||||
| 
 | ||||
|             try { | ||||
|                 profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getSafeUserId()); | ||||
|             } catch (error: unknown) { | ||||
|                 if (!(error instanceof MatrixError) || error.errcode !== "M_NOT_FOUND") { | ||||
|                     /** | ||||
|                      * Raise any other error than M_NOT_FOUND. | ||||
|                      * M_NOT_FOUND could occur if there is no user profile. | ||||
|                      * {@link https://spec.matrix.org/v1.7/client-server-api/#get_matrixclientv3profileuserid}
 | ||||
|                      * We should then assume an empty profile, emit UPDATE_EVENT etc.. | ||||
|                      */ | ||||
|                     throw error; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (profileInfo.displayname) { | ||||
|                 window.localStorage.setItem(KEY_DISPLAY_NAME, profileInfo.displayname); | ||||
|             } else { | ||||
|                 window.localStorage.removeItem(KEY_DISPLAY_NAME); | ||||
|             } | ||||
| 
 | ||||
|             if (profileInfo.avatar_url) { | ||||
|                 window.localStorage.setItem(KEY_AVATAR_URL, profileInfo.avatar_url); | ||||
|             } else { | ||||
|  |  | |||
|  | @ -0,0 +1,87 @@ | |||
| /* | ||||
| Copyright 2023 The Matrix.org Foundation C.I.C. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import { MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; | ||||
| import { MockedObject, mocked } from "jest-mock"; | ||||
| 
 | ||||
| import { stubClient } from "../test-utils"; | ||||
| import { OwnProfileStore } from "../../src/stores/OwnProfileStore"; | ||||
| import { UPDATE_EVENT } from "../../src/stores/AsyncStore"; | ||||
| 
 | ||||
| describe("OwnProfileStore", () => { | ||||
|     let client: MockedObject<MatrixClient>; | ||||
|     let ownProfileStore: OwnProfileStore; | ||||
|     let onUpdate: ReturnType<typeof jest.fn>; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|         client = mocked(stubClient()); | ||||
|         onUpdate = jest.fn(); | ||||
|         ownProfileStore = new OwnProfileStore(); | ||||
|         ownProfileStore.addListener(UPDATE_EVENT, onUpdate); | ||||
|     }); | ||||
| 
 | ||||
|     afterEach(() => { | ||||
|         ownProfileStore.removeListener(UPDATE_EVENT, onUpdate); | ||||
|     }); | ||||
| 
 | ||||
|     it("if the client has not yet been started, the displayname and avatar should be null", () => { | ||||
|         expect(onUpdate).not.toHaveBeenCalled(); | ||||
|         expect(ownProfileStore.displayName).toBeNull(); | ||||
|         expect(ownProfileStore.avatarMxc).toBeNull(); | ||||
|     }); | ||||
| 
 | ||||
|     it("if the client has been started and there is a profile, it should return the profile display name and avatar", async () => { | ||||
|         client.getProfileInfo.mockResolvedValue({ | ||||
|             displayname: "Display Name", | ||||
|             avatar_url: "mxc://example.com/abc123", | ||||
|         }); | ||||
|         await ownProfileStore.start(); | ||||
| 
 | ||||
|         expect(onUpdate).toHaveBeenCalled(); | ||||
|         expect(ownProfileStore.displayName).toBe("Display Name"); | ||||
|         expect(ownProfileStore.avatarMxc).toBe("mxc://example.com/abc123"); | ||||
|     }); | ||||
| 
 | ||||
|     it("if there is a M_NOT_FOUND error, it should report ready, displayname = MXID and avatar = null", async () => { | ||||
|         client.getProfileInfo.mockRejectedValue( | ||||
|             new MatrixError({ | ||||
|                 error: "Not found", | ||||
|                 errcode: "M_NOT_FOUND", | ||||
|             }), | ||||
|         ); | ||||
|         await ownProfileStore.start(); | ||||
| 
 | ||||
|         expect(onUpdate).toHaveBeenCalled(); | ||||
|         expect(ownProfileStore.displayName).toBe(client.getSafeUserId()); | ||||
|         expect(ownProfileStore.avatarMxc).toBeNull(); | ||||
|     }); | ||||
| 
 | ||||
|     it("if there is any other error, it should not report ready, displayname = MXID and avatar = null", async () => { | ||||
|         client.getProfileInfo.mockRejectedValue( | ||||
|             new MatrixError({ | ||||
|                 error: "Forbidden", | ||||
|                 errcode: "M_FORBIDDEN", | ||||
|             }), | ||||
|         ); | ||||
|         try { | ||||
|             await ownProfileStore.start(); | ||||
|         } catch (ignore) {} | ||||
| 
 | ||||
|         expect(onUpdate).not.toHaveBeenCalled(); | ||||
|         expect(ownProfileStore.displayName).toBe(client.getSafeUserId()); | ||||
|         expect(ownProfileStore.avatarMxc).toBeNull(); | ||||
|     }); | ||||
| }); | ||||
		Loading…
	
		Reference in New Issue
	
	 Michael Weimann
						Michael Weimann