From 2a5b59002ef58bc03c5d03384f610a0e5f9272d1 Mon Sep 17 00:00:00 2001 From: Borislav Pantaleev Date: Thu, 16 Jan 2025 11:00:59 +0200 Subject: [PATCH] Add Users' Account Data tab (#276) * Add Account Data tab in User edit * update readme --- README.md | 1 + src/components/UserAccountData.tsx | 65 ++++++++++++++++++++++++++++++ src/i18n/de.ts | 7 +++- src/i18n/en.ts | 6 +++ src/i18n/fa.ts | 7 +++- src/i18n/fr.ts | 7 +++- src/i18n/index.d.ts | 7 +++- src/i18n/it.ts | 7 +++- src/i18n/ru.ts | 7 +++- src/i18n/zh.ts | 7 +++- src/resources/users.tsx | 6 +++ src/synapse/dataProvider.ts | 18 +++++++++ 12 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 src/components/UserAccountData.tsx diff --git a/README.md b/README.md index cf0aa6f..b5779c8 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ The following changes are already implemented: * 🛑 [Add support for Account Suspension (MSC3823)](https://github.com/etkecc/synapse-admin/pull/195) * 🗑️ [Add "Purge Remote Media" button](https://github.com/etkecc/synapse-admin/pull/237) * [Respect base url (`BASE_PATH` / `vite build --base`) when loading `config.json`](https://github.com/etkecc/synapse-admin/pull/274) +* [Add Users' Account Data tab](https://github.com/etkecc/synapse-admin/pull/276) #### exclusive for [etke.cc](https://etke.cc) customers diff --git a/src/components/UserAccountData.tsx b/src/components/UserAccountData.tsx new file mode 100644 index 0000000..28cfec5 --- /dev/null +++ b/src/components/UserAccountData.tsx @@ -0,0 +1,65 @@ +import { useDataProvider, useRecordContext, useTranslate } from "react-admin"; +import { useEffect, useState } from "react"; +import { Typography, Box, Stack, Accordion, AccordionSummary, AccordionDetails } from "@mui/material"; +import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'; +import { SynapseDataProvider } from "../synapse/dataProvider"; + +const UserAccountData = () => { + const dataProvider = useDataProvider() as SynapseDataProvider; + const record = useRecordContext(); + const translate = useTranslate(); + const [globalAccountData, setGlobalAccountData] = useState({}); + const [roomsAccountData, setRoomsAccountData] = useState({}); + + if (!record) { + return null; + } + + useEffect(() => { + const fetchAccountData = async () => { + const accountData = await dataProvider.getAccountData(record.id); + setGlobalAccountData(accountData.account_data.global); + setRoomsAccountData(accountData.account_data.rooms); + }; + fetchAccountData(); + }, []); + + if (Object.keys(globalAccountData).length === 0 && Object.keys(roomsAccountData).length === 0) { + return {translate('ra.navigation.no_results', { + resource: 'Account Data', + _: 'No results found.', + })}; + } + + return <> + + {translate('resources.users.account_data.title')} + + + + }> + {translate('resources.users.account_data.global')} + + + {JSON.stringify(globalAccountData, null, 4)} + + + + }> + {translate('resources.users.account_data.rooms')} + + + {JSON.stringify(roomsAccountData, null, 4)} + + + + + + +} + +export default UserAccountData; \ No newline at end of file diff --git a/src/i18n/de.ts b/src/i18n/de.ts index 1cef0ad..97933b4 100644 --- a/src/i18n/de.ts +++ b/src/i18n/de.ts @@ -55,7 +55,7 @@ const de: SynapseTranslationMessages = { }, users: { invalid_user_id: "Lokaler Anteil der Matrix Benutzer-ID ohne Homeserver.", - tabs: { sso: "SSO", experimental: "Experimentell", limits: "Rate Limits" }, + tabs: { sso: "SSO", experimental: "Experimentell", limits: "Rate Limits", account_data: "Kontodaten" }, }, rooms: { details: "Raumdetails", @@ -229,6 +229,11 @@ const de: SynapseTranslationMessages = { messages_per_second_text: "Die Anzahl der Aktionen, die in einer Sekunde durchgeführt werden können.", burst_count: "Burst-Anzahl", burst_count_text: "Die Anzahl der Aktionen, die vor der Begrenzung durchgeführt werden können.", + }, + account_data: { + title: "Kontodaten", + global: "Globale", + rooms: "Räume", } }, rooms: { diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 8d3dab7..de50026 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -29,6 +29,7 @@ const en: SynapseTranslationMessages = { sso: "SSO", experimental: "Experimental", limits: "Rate Limits", + account_data: "Account Data", }, }, rooms: { @@ -202,6 +203,11 @@ const en: SynapseTranslationMessages = { messages_per_second_text: "The number of actions that can be performed in a second.", burst_count: "Burst count", burst_count_text: "How many actions that can be performed before being limited.", + }, + account_data: { + title: "Account Data", + global: "Global", + rooms: "Rooms", } }, rooms: { diff --git a/src/i18n/fa.ts b/src/i18n/fa.ts index 676570d..c7f6a7f 100644 --- a/src/i18n/fa.ts +++ b/src/i18n/fa.ts @@ -24,7 +24,7 @@ const fa: SynapseTranslationMessages = { }, users: { invalid_user_id: "بخش محلی یک شناسه کاربری ماتریکس بدون سرور خانگی.", - tabs: { sso: "SSO", experimental: "تجربی", limits: "محدودیت ها" }, + tabs: { sso: "SSO", experimental: "تجربی", limits: "محدودیت ها", account_data: "داده های کاربر" }, }, rooms: { tabs: { @@ -195,6 +195,11 @@ const fa: SynapseTranslationMessages = { messages_per_second_text: "تعداد عملیاتی که می تواند در یک ثانیه انجام شود.", burst_count: "تعداد پیچیدگی", burst_count_text: "تعداد عملیاتی که می تواند قبل از محدودیت انجام شود.", + }, + account_data: { + title: "داده های کاربر", + global: "عمومی", + rooms: "اتاق ها", } }, rooms: { diff --git a/src/i18n/fr.ts b/src/i18n/fr.ts index b2de5d5..2158d87 100644 --- a/src/i18n/fr.ts +++ b/src/i18n/fr.ts @@ -24,7 +24,7 @@ const fr: SynapseTranslationMessages = { }, users: { invalid_user_id: "Partie locale d'un identifiant utilisateur Matrix sans le nom du serveur d’accueil.", - tabs: { sso: "Authentification unique", experimental: "Expérimental", limits: "Limites" }, + tabs: { sso: "Authentification unique", experimental: "Expérimental", limits: "Limites", account_data: "Données du compte" }, }, rooms: { tabs: { @@ -197,6 +197,11 @@ const fr: SynapseTranslationMessages = { messages_per_second_text: "Le nombre d'actions que l'utilisateur peut effectuer par seconde.", burst_count: "Compteur de pics", burst_count_text: "Le nombre d'actions que l'utilisateur peut effectuer avant d'être limité.", + }, + account_data: { + title: "Données du compte", + global: "Globales", + rooms: "Salons", } }, rooms: { diff --git a/src/i18n/index.d.ts b/src/i18n/index.d.ts index 08a7518..4024118 100644 --- a/src/i18n/index.d.ts +++ b/src/i18n/index.d.ts @@ -22,7 +22,7 @@ interface SynapseTranslationMessages extends TranslationMessages { }; users: { invalid_user_id: string; - tabs: { sso: string; experimental: string; limits: string; }; + tabs: { sso: string; experimental: string; limits: string; account_data: string; }; }; rooms: { details?: string; // TODO: fa, fr, it, zh @@ -195,6 +195,11 @@ interface SynapseTranslationMessages extends TranslationMessages { burst_count: string; burst_count_text: string; }; + account_data: { + title: string; + global: string; + rooms: string; + } }; rooms: { name: string; diff --git a/src/i18n/it.ts b/src/i18n/it.ts index 3fc1ec7..204d26a 100644 --- a/src/i18n/it.ts +++ b/src/i18n/it.ts @@ -24,7 +24,7 @@ const it: SynapseTranslationMessages = { }, users: { invalid_user_id: "ID utente non valido su questo homeserver.", - tabs: { sso: "SSO", experimental: "Sperimentale", limits: "Limiti" }, + tabs: { sso: "SSO", experimental: "Sperimentale", limits: "Limiti", account_data: "Dati del profilo" }, }, rooms: { tabs: { @@ -195,6 +195,11 @@ const it: SynapseTranslationMessages = { messages_per_second_text: "Il numero di azioni che l'utente può eseguire al secondo.", burst_count: "Burst-conteggio", burst_count_text: "Il numero di azioni che l'utente può eseguire prima di essere limitato.", + }, + account_data: { + title: "Dati del profilo", + global: "Globale", + rooms: "Stanza", } }, rooms: { diff --git a/src/i18n/ru.ts b/src/i18n/ru.ts index dde66cb..918db16 100644 --- a/src/i18n/ru.ts +++ b/src/i18n/ru.ts @@ -50,7 +50,7 @@ const ru: SynapseTranslationMessages = { }, users: { invalid_user_id: "Локальная часть ID пользователя Matrix без адреса домашнего сервера.", - tabs: { sso: "SSO", experimental: "Экспериментальные", limits: "Ограничения" }, + tabs: { sso: "SSO", experimental: "Экспериментальные", limits: "Ограничения", account_data: "Данные пользователя" }, }, rooms: { details: "Данные комнаты", @@ -232,6 +232,11 @@ const ru: SynapseTranslationMessages = { messages_per_second_text: "Количество действий, которые могут быть выполнены в секунду.", burst_count: "Burst-счётчик", burst_count_text: "Количество действий, которые могут быть выполнены до ограничения.", + }, + account_data: { + title: "Данные пользователя", + global: "Глобальные", + rooms: "Комнаты", } }, rooms: { diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts index 88f89f9..6b3dd94 100644 --- a/src/i18n/zh.ts +++ b/src/i18n/zh.ts @@ -52,7 +52,7 @@ const zh: SynapseTranslationMessages = { }, users: { invalid_user_id: "必须要是一个有效的 Matrix 用户 ID ,例如 @user_id:homeserver", - tabs: { sso: "SSO", experimental: "实验性", limits: "限制" }, + tabs: { sso: "SSO", experimental: "实验性", limits: "限制", account_data: "账户数据" }, }, rooms: { tabs: { @@ -221,6 +221,11 @@ const zh: SynapseTranslationMessages = { messages_per_second_text: "每秒可以执行的操作数。", burst_count: "Burst-计数", burst_count_text: "在限制之前可以执行的操作数。", + }, + account_data: { + title: "账户数据", + global: "全局", + rooms: "房间", } }, rooms: { diff --git a/src/resources/users.tsx b/src/resources/users.tsx index bbf2851..e04be10 100644 --- a/src/resources/users.tsx +++ b/src/resources/users.tsx @@ -10,6 +10,7 @@ import SettingsInputComponentIcon from "@mui/icons-material/SettingsInputCompone import ScienceIcon from "@mui/icons-material/Science"; import LockClockIcon from '@mui/icons-material/LockClock'; import ViewListIcon from "@mui/icons-material/ViewList"; +import DocumentScannerIcon from "@mui/icons-material/DocumentScanner"; import { useEffect, useState } from "react"; import { Alert, Typography } from "@mui/material"; import { useTheme } from "@mui/material/styles"; @@ -81,6 +82,7 @@ import ExperimentalFeaturesList from "../components/ExperimentalFeatures"; import UserRateLimits from "../components/UserRateLimits"; import { User, UsernameAvailabilityResult } from "../synapse/dataProvider"; import { MakeAdminBtn } from "./rooms"; +import UserAccountData from "../components/UserAccountData"; const choices_medium = [ { id: "email", name: "resources.users.email" }, @@ -556,6 +558,10 @@ export const UserEdit = (props: EditProps) => { } path="limits"> + + } path="accountdata"> + + ); diff --git a/src/synapse/dataProvider.ts b/src/synapse/dataProvider.ts index cd51e65..5cade98 100644 --- a/src/synapse/dataProvider.ts +++ b/src/synapse/dataProvider.ts @@ -260,6 +260,17 @@ export interface RateLimitsModel { burst_count?: number; } +export interface AccountDataModel { + account_data: { + global: { + [key: string]: object; + }, + rooms: { + [key: string]: object; + }; + } +} + export interface UsernameAvailabilityResult { available?: boolean; error?: string; @@ -309,6 +320,7 @@ export interface SynapseDataProvider extends DataProvider { updateFeatures: (id: Identifier, features: ExperimentalFeaturesModel) => Promise; getRateLimits: (id: Identifier) => Promise; setRateLimits: (id: Identifier, rateLimits: RateLimitsModel) => Promise; + getAccountData: (id: Identifier) => Promise; checkUsernameAvailability: (username: string) => Promise; makeRoomAdmin: (room_id: string, user_id: string) => Promise<{ success: boolean; error?: string; errcode?: string }>; getServerRunningProcess: (etkeAdminUrl: string) => Promise; @@ -911,6 +923,12 @@ const baseDataProvider: SynapseDataProvider = { const { json } = await jsonClient(endpoint_url); return json as RateLimitsModel; }, + getAccountData: async (id: Identifier) => { + const base_url = localStorage.getItem("base_url"); + const endpoint_url = `${base_url}/_synapse/admin/v1/users/${encodeURIComponent(returnMXID(id))}/accountdata`; + const { json } = await jsonClient(endpoint_url); + return json as AccountDataModel; + }, setRateLimits: async (id: Identifier, rateLimits: RateLimitsModel) => { const filtered = Object.entries(rateLimits). filter(([key, value]) => value !== null && value !== undefined).