diff --git a/README.md b/README.md index 5dda21d..01c9ec2 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ The following changes are already implemented: * [Login with access token](https://github.com/etkecc/synapse-admin/pull/58) * [Fix footer causing vertical scrollbar](https://github.com/etkecc/synapse-admin/pull/60) * [Custom Menu Items](https://github.com/etkecc/synapse-admin/pull/79) +* [Add user profile to the top menu](https://github.com/etkecc/synapse-admin/pull/80) _the list will be updated as new changes are added_ diff --git a/src/components/AdminLayout.tsx b/src/components/AdminLayout.tsx index 2799693..c85c999 100644 --- a/src/components/AdminLayout.tsx +++ b/src/components/AdminLayout.tsx @@ -52,7 +52,11 @@ const AdminMenu = (props) => { useEffect(() => { const menuConfig = localStorage.getItem('menu'); if (menuConfig) { - setMenu(JSON.parse(menuConfig)); + try { + setMenu(JSON.parse(menuConfig)); + } catch (e) { + console.error('Error parsing menu configuration', e); + } } }, []); diff --git a/src/synapse/authProvider.test.ts b/src/synapse/authProvider.test.ts index 16cf298..b2e89d6 100644 --- a/src/synapse/authProvider.test.ts +++ b/src/synapse/authProvider.test.ts @@ -30,7 +30,7 @@ describe("authProvider", () => { }); expect(ret).toEqual({redirectTo: "/"}); - expect(fetch).toHaveBeenCalledWith("http://example.com/_matrix/client/r0/login", { + expect(fetch).toHaveBeenCalledWith("http://example.com/_matrix/client/v3/login", { body: '{"device_id":null,"initial_device_display_name":"Synapse Admin","type":"m.login.password","identifier":{"type":"m.id.user","user":"@user:example.com"},"password":"secret"}', headers: new Headers({ Accept: "application/json", @@ -61,7 +61,7 @@ describe("authProvider", () => { }); expect(ret).toEqual({redirectTo: "/"}); - expect(fetch).toHaveBeenCalledWith("https://example.com/_matrix/client/r0/login", { + expect(fetch).toHaveBeenCalledWith("https://example.com/_matrix/client/v3/login", { body: '{"device_id":null,"initial_device_display_name":"Synapse Admin","type":"m.login.token","token":"login_token"}', headers: new Headers({ Accept: "application/json", @@ -83,7 +83,7 @@ describe("authProvider", () => { await authProvider.logout(null); - expect(fetch).toHaveBeenCalledWith("example.com/_matrix/client/r0/logout", { + expect(fetch).toHaveBeenCalledWith("example.com/_matrix/client/v3/logout", { headers: new Headers({ Accept: "application/json", Authorization: "Bearer foo", diff --git a/src/synapse/authProvider.ts b/src/synapse/authProvider.ts index f1c673c..112a610 100644 --- a/src/synapse/authProvider.ts +++ b/src/synapse/authProvider.ts @@ -2,6 +2,7 @@ import { AuthProvider, HttpError, Options, fetchUtils } from "react-admin"; import storage from "../storage"; import { MatrixError, displayError } from "../components/error"; +import { fetchAuthenticatedMedia } from "../utils/fetchMedia"; const authProvider: AuthProvider = { // called when the user attempts to log in @@ -57,7 +58,7 @@ const authProvider: AuthProvider = { storage.setItem("base_url", base_url); const decoded_base_url = window.decodeURIComponent(base_url); - let login_api_url = decoded_base_url + (accessToken ? "/_matrix/client/v3/account/whoami" : "/_matrix/client/r0/login"); + let login_api_url = decoded_base_url + (accessToken ? "/_matrix/client/v3/account/whoami" : "/_matrix/client/v3/login"); let response; @@ -95,11 +96,48 @@ const authProvider: AuthProvider = { ); } }, + getIdentity: async () => { + const access_token = storage.getItem("access_token"); + const user_id = storage.getItem("user_id"); + const base_url = storage.getItem("base_url"); + + if (typeof access_token !== "string" || typeof user_id !== "string" || typeof base_url !== "string") { + return Promise.reject(); + } + + const options: Options = { + headers: new Headers({ + Accept: "application/json", + Authorization: `Bearer ${access_token}`, + }), + }; + + const whoami_api_url = base_url + `/_matrix/client/v3/profile/${user_id}`; + + try { + let avatar_url = ""; + const response = await fetchUtils.fetchJson(whoami_api_url, options); + if (response.json.avatar_url) { + const mediaresp = await fetchAuthenticatedMedia(response.json.avatar_url, "thumbnail"); + const blob = await mediaresp.blob(); + avatar_url = URL.createObjectURL(blob); + } + + return Promise.resolve({ + id: user_id, + fullName: response.json.displayname, + avatar: avatar_url, + }); + } catch (err) { + console.log("Error getting identity", err); + return Promise.reject(); + } + }, // called when the user clicks on the logout button logout: async () => { console.log("logout"); - const logout_api_url = storage.getItem("base_url") + "/_matrix/client/r0/logout"; + const logout_api_url = storage.getItem("base_url") + "/_matrix/client/v3/logout"; const access_token = storage.getItem("access_token"); const options: Options = {