diff --git a/src/components/EventReports.jsx b/src/components/EventReports.jsx index 0f0810d..6ee3baf 100644 --- a/src/components/EventReports.jsx +++ b/src/components/EventReports.jsx @@ -15,6 +15,7 @@ import { useRecordContext, useTranslate, } from "react-admin"; +import { MXCField } from "./media"; import PageviewIcon from "@mui/icons-material/Pageview"; import ReportIcon from "@mui/icons-material/Warning"; import ViewListIcon from "@mui/icons-material/ViewList"; @@ -89,6 +90,8 @@ export const ReportShow = props => { + + diff --git a/src/components/media.jsx b/src/components/media.jsx index cc06a0b..1da27b9 100644 --- a/src/components/media.jsx +++ b/src/components/media.jsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import get from "lodash/get"; import { BooleanInput, Button, @@ -14,10 +15,12 @@ import { useRefresh, useTranslate, } from "react-admin"; +import { Link } from "react-router-dom"; import BlockIcon from "@mui/icons-material/Block"; import ClearIcon from "@mui/icons-material/Clear"; import DeleteSweepIcon from "@mui/icons-material/DeleteSweep"; import { + Box, Dialog, DialogContent, DialogContentText, @@ -27,7 +30,9 @@ import { import IconCancel from "@mui/icons-material/Cancel"; import LockIcon from "@mui/icons-material/Lock"; import LockOpenIcon from "@mui/icons-material/LockOpen"; +import FileOpenIcon from "@mui/icons-material/FileOpen"; import { alpha, useTheme } from "@mui/material/styles"; +import { getMediaUrl } from "../synapse/synapse"; const DeleteMediaDialog = ({ open, loading, onClose, onSubmit }) => { const translate = useTranslate(); @@ -333,3 +338,49 @@ export const QuarantineMediaButton = props => { ); }; + +export const ViewMediaButton = ({ media_id, label }) => { + const translate = useTranslate(); + const url = getMediaUrl(media_id); + return ( + + + + + + + {label} + + ); +}; + +export const MediaIDField = ({ source }) => { + const homeserver = localStorage.getItem("home_server"); + const record = useRecordContext(); + if (!record) return null; + + const src = get(record, source)?.toString(); + if (!src) return null; + + return ; +}; + +export const MXCField = ({ source }) => { + const record = useRecordContext(); + if (!record) return null; + + const src = get(record, source)?.toString(); + if (!src) return null; + + const media_id = src.replace("mxc://", ""); + + return ; +}; diff --git a/src/components/users.jsx b/src/components/users.jsx index f1744cc..683482d 100644 --- a/src/components/users.jsx +++ b/src/components/users.jsx @@ -51,7 +51,11 @@ import { Link } from "react-router-dom"; import AvatarField from "./AvatarField"; import { ServerNoticeButton, ServerNoticeBulkButton } from "./ServerNotices"; import { DeviceRemoveButton } from "./devices"; -import { ProtectMediaButton, QuarantineMediaButton } from "./media"; +import { + MediaIDField, + ProtectMediaButton, + QuarantineMediaButton, +} from "./media"; const choices_medium = [ { id: "email", name: "resources.users.email" }, @@ -449,13 +453,13 @@ export const UserEdit = props => { sort={{ field: "created_ts", order: "DESC" }} > + - diff --git a/src/i18n/de.js b/src/i18n/de.js index c7d8014..bd5f2a6 100644 --- a/src/i18n/de.js +++ b/src/i18n/de.js @@ -208,6 +208,9 @@ const de = { format: "Nachrichtenformat", formatted_body: "Formatierter Nachrichteninhalt", algorithm: "Verschlüsselungsalgorithmus", + info: { + mimetype: "Typ", + }, }, }, }, @@ -256,6 +259,9 @@ const de = { created_ts: "Erstellt", last_access_ts: "Letzter Zugriff", }, + action: { + open: "Mediendatei in neuem Fenster öffnen", + }, }, delete_media: { name: "Medien", diff --git a/src/i18n/en.js b/src/i18n/en.js index af5c58a..27a6d17 100644 --- a/src/i18n/en.js +++ b/src/i18n/en.js @@ -205,6 +205,10 @@ const en = { format: "format", formatted_body: "formatted content", algorithm: "algorithm", + url: "URL", + info: { + mimetype: "Type", + }, }, }, }, @@ -253,6 +257,9 @@ const en = { created_ts: "Created", last_access_ts: "Last access", }, + action: { + open: "Open media file in new window", + }, }, delete_media: { name: "Media", diff --git a/src/synapse/synapse.js b/src/synapse/synapse.js index ddd4136..915144c 100644 --- a/src/synapse/synapse.js +++ b/src/synapse/synapse.js @@ -53,3 +53,8 @@ export const getSupportedLoginFlows = async baseUrl => { const response = await fetchUtils.fetchJson(loginFlowsUrl, { method: "GET" }); return response.json.flows; }; + +export const getMediaUrl = media_id => { + const baseUrl = localStorage.getItem("base_url"); + return `${baseUrl}/_matrix/media/v1/download/${media_id}?allow_redirect=true`; +};