diff --git a/README.md b/README.md index 6acfb2c..06148a2 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ The following changes are already implemented: * 🎞️ [Add "Media" tab for rooms](https://github.com/etkecc/synapse-admin/pull/196) * 📞 [Support E.164-based Matrix IDs (MSC4009)](https://github.com/etkecc/synapse-admin/pull/214) * 🛑 [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) #### exclusive for [etke.cc](https://etke.cc) customers diff --git a/src/components/media.tsx b/src/components/media.tsx index 63b729c..8696a01 100644 --- a/src/components/media.tsx +++ b/src/components/media.tsx @@ -124,6 +124,80 @@ export const DeleteMediaButton = (props: ButtonProps) => { ); }; +const PurgeRemoteMediaDialog = ({ open, onClose, onSubmit }) => { + const translate = useTranslate(); + + const PurgeRemoteMediaToolbar = (props: ToolbarProps) => ( + + } /> + + + ); + + return ( + + {translate("purge_remote_media.action.send")} + + {translate("purge_remote_media.helper.send")} + } onSubmit={onSubmit}> + + + + + ); +}; + +export const PurgeRemoteMediaButton = (props: ButtonProps) => { + const theme = useTheme(); + const [open, setOpen] = useState(false); + const notify = useNotify(); + const dataProvider = useDataProvider(); + const { mutate: purgeRemoteMedia, isPending } = useMutation({ + mutationFn: (values: DeleteMediaParams) => dataProvider.purgeRemoteMedia(values), + onSuccess: () => { + notify("purge_remote_media.action.send_success"); + closeDialog(); + }, + onError: () => { + notify("purge_remote_media.action.send_failure", { + type: "error", + }); + }, + }); + + const openDialog = () => setOpen(true); + const closeDialog = () => setOpen(false); + + return ( + <> + + + + ); +}; + export const ProtectMediaButton = (props: ButtonProps) => { const record = useRecordContext(); const translate = useTranslate(); diff --git a/src/i18n/de.ts b/src/i18n/de.ts index e72f8b1..1cef0ad 100644 --- a/src/i18n/de.ts +++ b/src/i18n/de.ts @@ -147,6 +147,20 @@ const de: SynapseTranslationMessages = { send: "Diese API löscht die lokalen Medien von der Festplatte des eigenen Servers. Dies umfasst alle lokalen Miniaturbilder und Kopien von Medien. Diese API wirkt sich nicht auf Medien aus, die sich in externen Medien-Repositories befinden.", }, }, + purge_remote_media: { + name: "Externe Medien", + fields: { + before_ts: "letzter Zugriff vor", + }, + action: { + send: "Externe Medien löschen", + send_success: "Die Anfrage zum Löschen externer Medien wurde gesendet.", + send_failure: "Bei der Anfrage zum Löschen externer Medien ist ein Fehler aufgetreten.", + }, + helper: { + send: "Diese API löscht den externen Medien-Cache von der Festplatte Ihres eigenen Servers. Dazu gehören alle lokalen Thumbnails und Kopien heruntergeladener Medien. Diese API beeinflusst nicht die Medien, die in das eigene Medienarchiv des Servers hochgeladen wurden.", + }, + }, resources: { users: { name: "Benutzer", diff --git a/src/i18n/en.ts b/src/i18n/en.ts index f355712..8d3dab7 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -120,6 +120,20 @@ const en: SynapseTranslationMessages = { send: "This API deletes the local media from the disk of your own server. This includes any local thumbnails and copies of media downloaded. This API will not affect media that has been uploaded to external media repositories.", }, }, + purge_remote_media: { + name: "Remote Media", + fields: { + before_ts: "last access before", + }, + action: { + send: "Purge remote media", + send_success: "Purge remote media request has been sent.", + send_failure: "An error has occurred with the purge remote media request.", + }, + helper: { + send: "This API purges the remote media cache from the disk of your own server. This includes any local thumbnails and copies of media downloaded. This API will not affect media that has been uploaded to the server's own media repository.", + }, + }, resources: { users: { name: "User |||| Users", diff --git a/src/i18n/fa.ts b/src/i18n/fa.ts index 5dc1ff3..676570d 100644 --- a/src/i18n/fa.ts +++ b/src/i18n/fa.ts @@ -114,6 +114,20 @@ const fa: SynapseTranslationMessages = { send: "این API رسانه های محلی را از دیسک سرور خود حذف می کند. این شامل هر تصویر کوچک محلی و کپی از رسانه دانلود شده است. این API بر رسانه‌هایی که در مخازن رسانه خارجی آپلود شده‌اند تأثیری نخواهد گذاشت.", }, }, + purge_remote_media: { + name: "رسانه‌های از راه دور", + fields: { + before_ts: "آخرین دسترسی قبل از", + }, + action: { + send: "پاک کردن رسانه‌های از راه دور", + send_success: "درخواست پاک کردن رسانه‌های از راه دور ارسال شد.", + send_failure: "درخواست برای پاک کردن رسانه‌های از راه دور با خطا مواجه شد.", + }, + helper: { + send: "این API کش رسانه‌های از راه دور را از دیسک سرور شما پاک می‌کند. این شامل هر گونه بندانگشتی محلی و نسخه‌های رسانه‌های دانلود شده می‌شود. این API بر رسانه‌های آپلود شده به مخزن رسانه سرور تأثیری نخواهد داشت.", + }, + }, resources: { users: { name: "کاربر |||| کاربران", diff --git a/src/i18n/fr.ts b/src/i18n/fr.ts index 218e2b5..b2de5d5 100644 --- a/src/i18n/fr.ts +++ b/src/i18n/fr.ts @@ -117,6 +117,20 @@ const fr: SynapseTranslationMessages = { send: "Cette API supprime les médias locaux du disque de votre propre serveur. Cela inclut toutes les vignettes locales et les copies des médias téléchargés. Cette API n'affectera pas les médias qui ont été téléversés dans des dépôts de médias externes.", }, }, + purge_remote_media: { + name: "Médias distants", + fields: { + before_ts: "dernier accès avant", + }, + action: { + send: "Purger les médias distants", + send_success: "La demande de purge des médias distants a été envoyée.", + send_failure: "Une erreur est survenue lors de la demande de purge des médias distants.", + }, + helper: { + send: "Cette API purge le cache des médias distants du disque de votre propre serveur. Cela inclut toutes les vignettes locales et les copies des médias téléchargés. Cette API n'affectera pas les médias qui ont été téléchargés dans le dépôt de médias du serveur.", + }, + }, resources: { users: { name: "Utilisateur |||| Utilisateurs", diff --git a/src/i18n/index.d.ts b/src/i18n/index.d.ts index f124718..08a7518 100644 --- a/src/i18n/index.d.ts +++ b/src/i18n/index.d.ts @@ -112,6 +112,20 @@ interface SynapseTranslationMessages extends TranslationMessages { send: string; }; }; + purge_remote_media: { + name: string; + fields: { + before_ts: string; + }; + action: { + send: string; + send_success: string; + send_failure: string; + }; + helper: { + send: string; + }; + }; resources: { users: { name: string; diff --git a/src/i18n/it.ts b/src/i18n/it.ts index abd8b0d..3fc1ec7 100644 --- a/src/i18n/it.ts +++ b/src/i18n/it.ts @@ -114,6 +114,20 @@ const it: SynapseTranslationMessages = { send: "Questa API cancella i media locali dal disco del tuo server. Questo include anche ogni miniatura e copia del media scaricato. Questa API non inciderà sui media che sono stati caricati nei repository esterni.", }, }, + purge_remote_media: { + name: "Media Remoti", + fields: { + before_ts: "ultimo accesso prima di", + }, + action: { + send: "Elimina media remoti", + send_success: "La richiesta per eliminare i media remoti è stata inviata.", + send_failure: "Si è verificato un errore con la richiesta di eliminazione dei media remoti.", + }, + helper: { + send: "Questa API elimina la cache dei media remoti dal disco del tuo server. Questo include qualsiasi miniatura locale e copie di media scaricati. Questa API non influirà sui media che sono stati caricati nel repository multimediale del server.", + }, + }, resources: { users: { name: "Utente |||| Utenti", diff --git a/src/i18n/ru.ts b/src/i18n/ru.ts index e669c1f..dde66cb 100644 --- a/src/i18n/ru.ts +++ b/src/i18n/ru.ts @@ -150,6 +150,20 @@ const ru: SynapseTranslationMessages = { Данный API не затрагивает файлы, загруженные во внешние хранилища.", }, }, + purge_remote_media: { + name: "Внешние медиа", + fields: { + before_ts: "последний доступ до", + }, + action: { + send: "Очистить внешние медиа", + send_success: "Запрос на очистку внешних медиа был отправлен.", + send_failure: "Произошла ошибка при запросе очистки внешних медиа.", + }, + helper: { + send: "Этот API очищает кэш внешних медиа с диска вашего сервера. Это включает любые локальные миниатюры и копии загруженных медиа. Этот API не повлияет на медиа, которые были загружены в собственное медиа-хранилище сервера.", + }, + }, resources: { users: { name: "Пользователь |||| Пользователи", diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts index a9d6e09..88f89f9 100644 --- a/src/i18n/zh.ts +++ b/src/i18n/zh.ts @@ -142,6 +142,20 @@ const zh: SynapseTranslationMessages = { send: "这个API会删除您硬盘上的本地媒体。包含了任何的本地缓存和下载的媒体备份。这个API不会影响上传到外部媒体存储库上的媒体文件。", }, }, + purge_remote_media: { + name: "远程媒体", + fields: { + before_ts: "最后访问于之前", + }, + action: { + send: "清除远程媒体", + send_success: "远程媒体清除请求已发送。", + send_failure: "发生错误,远程媒体清除请求未成功。", + }, + helper: { + send: "此API清除您服务器磁盘上的远程媒体缓存。这包括任何本地缩略图和下载的媒体副本。此API不会影响已经上传到服务器媒体存储库的媒体。", + }, + }, resources: { users: { name: "用户", diff --git a/src/resources/user_media_statistics.tsx b/src/resources/user_media_statistics.tsx index a77ccd0..fcf678e 100644 --- a/src/resources/user_media_statistics.tsx +++ b/src/resources/user_media_statistics.tsx @@ -14,13 +14,14 @@ import { useListContext, } from "react-admin"; -import { DeleteMediaButton } from "../components/media"; +import { DeleteMediaButton, PurgeRemoteMediaButton } from "../components/media"; const ListActions = () => { const { isLoading, total } = useListContext(); return ( + ); diff --git a/src/synapse/dataProvider.ts b/src/synapse/dataProvider.ts index 898c628..c163781 100644 --- a/src/synapse/dataProvider.ts +++ b/src/synapse/dataProvider.ts @@ -293,6 +293,7 @@ export interface ServerProcessResponse { export interface SynapseDataProvider extends DataProvider { deleteMedia: (params: DeleteMediaParams) => Promise; + purgeRemoteMedia: (params: DeleteMediaParams) => Promise; uploadMedia: (params: UploadMediaParams) => Promise; updateFeatures: (id: Identifier, features: ExperimentalFeaturesModel) => Promise; getRateLimits: (id: Identifier) => Promise; @@ -849,6 +850,23 @@ const baseDataProvider: SynapseDataProvider = { return json as DeleteMediaResult; }, + /** + * Purge remote media by date + * + * @link https://element-hq.github.io/synapse/latest/admin_api/media_admin_api.html#purge-remote-media-api + * + * @param before_ts Unix timestamp in milliseconds. Files that were last used before this timestamp will be deleted. It is the timestamp of last access, not the timestamp when the file was created. + * @returns + */ + purgeRemoteMedia: async ({ before_ts }) => { + const endpoint = `/_synapse/admin/v1/purge_media_cache?before_ts=${before_ts}`; + + const base_url = localStorage.getItem("base_url"); + const endpoint_url = base_url + endpoint; + const { json } = await jsonClient(endpoint_url, { method: "POST" }); + return json as DeleteMediaResult; + }, + uploadMedia: async ({ file, filename, content_type }: UploadMediaParams) => { const base_url = localStorage.getItem("base_url"); const uploadMediaURL = `${base_url}/_matrix/media/v3/upload`; diff --git a/src/utils/mxid.ts b/src/utils/mxid.ts index a46e266..900a428 100644 --- a/src/utils/mxid.ts +++ b/src/utils/mxid.ts @@ -16,7 +16,11 @@ export const isMXID = (id: string | Identifier): boolean => mxidPattern.test(id * @returns Whether the user is managed by an application service */ export const isASManaged = (id: string | Identifier): boolean => { - return GetConfig().asManagedUsers.some(regex => regex.test(id as string)); + const managedUsers = GetConfig().asManagedUsers; + if (!managedUsers) { + return false; + } + return managedUsers.some(regex => regex.test(id as string)); }; /**