From 2ab434397069e7995fabe8ffc536d818aacd0523 Mon Sep 17 00:00:00 2001 From: Dirk Klimpel <5740567+dklimpel@users.noreply.github.com> Date: Tue, 4 May 2021 13:52:43 +0200 Subject: [PATCH] Add the lists of public rooms on the server (#105) * Add room directory and the switches to rooms settings * Fix react admin version --- src/App.js | 7 + src/components/RoomDirectory.js | 252 ++++++++++++++++++++++++++++++++ src/components/rooms.js | 43 ++++-- src/components/users.js | 31 ++-- src/i18n/de.js | 33 ++++- src/i18n/en.js | 31 +++- src/synapse/dataProvider.js | 24 +++ 7 files changed, 381 insertions(+), 40 deletions(-) create mode 100644 src/components/RoomDirectory.js diff --git a/src/App.js b/src/App.js index 3afdff8..2ab6161 100644 --- a/src/App.js +++ b/src/App.js @@ -12,7 +12,9 @@ import EqualizerIcon from "@material-ui/icons/Equalizer"; import { UserMediaStatsList } from "./components/statistics"; import RoomIcon from "@material-ui/icons/ViewList"; import ReportIcon from "@material-ui/icons/Warning"; +import FolderSharedIcon from "@material-ui/icons/FolderShared"; import { ImportFeature } from "./components/ImportFeature"; +import { RoomDirectoryList } from "./components/RoomDirectory"; import { Route } from "react-router-dom"; import germanMessages from "./i18n/de"; import englishMessages from "./i18n/en"; @@ -57,6 +59,11 @@ const App = () => ( show={ReportShow} icon={ReportIcon} /> + diff --git a/src/components/RoomDirectory.js b/src/components/RoomDirectory.js new file mode 100644 index 0000000..654c824 --- /dev/null +++ b/src/components/RoomDirectory.js @@ -0,0 +1,252 @@ +import React, { Fragment } from "react"; +import Avatar from "@material-ui/core/Avatar"; +import { Chip } from "@material-ui/core"; +import { connect } from "react-redux"; +import FolderSharedIcon from "@material-ui/icons/FolderShared"; +import { makeStyles } from "@material-ui/core/styles"; +import { + BooleanField, + BulkDeleteButton, + Button, + Datagrid, + DeleteButton, + Filter, + List, + NumberField, + Pagination, + TextField, + useCreate, + useMutation, + useNotify, + useTranslate, + useRefresh, + useUnselectAll, +} from "react-admin"; + +const useStyles = makeStyles({ + small: { + height: "40px", + width: "40px", + }, +}); + +const RoomDirectoryPagination = props => ( + +); + +export const RoomDirectoryDeleteButton = props => { + const translate = useTranslate(); + + return ( + } + /> + ); +}; + +export const RoomDirectoryBulkDeleteButton = props => ( + } + /> +); + +export const RoomDirectoryBulkSaveButton = ({ selectedIds }) => { + const notify = useNotify(); + const refresh = useRefresh(); + const unselectAll = useUnselectAll(); + const [createMany, { loading }] = useMutation(); + + const handleSend = values => { + createMany( + { + type: "createMany", + resource: "room_directory", + payload: { ids: selectedIds, data: {} }, + }, + { + onSuccess: ({ data }) => { + notify("resources.room_directory.action.send_success"); + unselectAll("rooms"); + refresh(); + }, + onFailure: error => + notify("resources.room_directory.action.send_failure", "error"), + } + ); + }; + + return ( + + ); +}; + +export const RoomDirectorySaveButton = ({ record }) => { + const notify = useNotify(); + const refresh = useRefresh(); + const [create, { loading }] = useCreate("room_directory"); + + const handleSend = values => { + create( + { + payload: { data: { id: record.id } }, + }, + { + onSuccess: ({ data }) => { + notify("resources.room_directory.action.send_success"); + refresh(); + }, + onFailure: error => + notify("resources.room_directory.action.send_failure", "error"), + } + ); + }; + + return ( + + ); +}; + +const RoomDirectoryBulkActionButtons = props => ( + + + +); + +const AvatarField = ({ source, className, record = {} }) => ( + +); + +const RoomDirectoryFilter = ({ ...props }) => { + const translate = useTranslate(); + return ( + + + + + + ); +}; + +export const FilterableRoomDirectoryList = ({ ...props }) => { + const classes = useStyles(); + const translate = useTranslate(); + const filter = props.roomDirectoryFilters; + const roomIdFilter = filter && filter.room_id ? true : false; + const topicFilter = filter && filter.topic ? true : false; + const canonicalAliasFilter = filter && filter.canonical_alias ? true : false; + + return ( + } + bulkActionButtons={} + filters={} + perPage={100} + > + + + + {roomIdFilter && ( + + )} + {canonicalAliasFilter && ( + + )} + {topicFilter && ( + + )} + + + + + + ); +}; + +function mapStateToProps(state) { + return { + roomDirectoryFilters: + state.admin.resources.room_directory.list.params.displayedFilters, + }; +} + +export const RoomDirectoryList = connect(mapStateToProps)( + FilterableRoomDirectoryList +); diff --git a/src/components/rooms.js b/src/components/rooms.js index e1a44e6..0c2c514 100644 --- a/src/components/rooms.js +++ b/src/components/rooms.js @@ -2,7 +2,7 @@ import React, { Fragment } from "react"; import { connect } from "react-redux"; import { BooleanField, - BulkDeleteWithConfirmButton, + BulkDeleteButton, Datagrid, DeleteButton, Filter, @@ -27,6 +27,12 @@ import PageviewIcon from "@material-ui/icons/Pageview"; import UserIcon from "@material-ui/icons/Group"; import ViewListIcon from "@material-ui/icons/ViewList"; import VisibilityIcon from "@material-ui/icons/Visibility"; +import { + RoomDirectoryBulkDeleteButton, + RoomDirectoryBulkSaveButton, + RoomDirectoryDeleteButton, + RoomDirectorySaveButton, +} from "./RoomDirectory"; const RoomPagination = props => ( @@ -73,16 +79,26 @@ const RoomTitle = ({ record }) => { }; const RoomShowActions = ({ basePath, data, resource }) => { - const translate = useTranslate(); + var roomDirectoryStatus = ""; + if (data) { + roomDirectoryStatus = data.public; + } + return ( + {roomDirectoryStatus === false && ( + + )} + {roomDirectoryStatus === true && ( + + )} ); @@ -205,7 +221,14 @@ export const RoomShow = props => { const RoomBulkActionButtons = props => ( - + + + ); @@ -249,7 +272,6 @@ const FilterableRoomList = ({ ...props }) => { const stateEventsFilter = filter && filter.state_events ? true : false; const versionFilter = filter && filter.version ? true : false; const federateableFilter = filter && filter.federatable ? true : false; - const translate = useTranslate(); return ( { pagination={} sort={{ field: "name", order: "ASC" }} filters={} - bulkActionButtons={ - - } + bulkActionButtons={} > ( ); -const UserBulkActionButtons = props => { - const translate = useTranslate(); - return ( - - - - - ); -}; +const UserBulkActionButtons = props => ( + + + + +); const AvatarField = ({ source, className, record = {} }) => ( @@ -238,7 +236,10 @@ const UserEditToolbar = props => { @@ -453,7 +454,7 @@ export const UserEdit = props => { - + diff --git a/src/i18n/de.js b/src/i18n/de.js index f75f2b0..a1a57e3 100644 --- a/src/i18n/de.js +++ b/src/i18n/de.js @@ -23,11 +23,6 @@ export default { detail: "Details", permission: "Berechtigungen", }, - delete: { - title: "Raum löschen", - message: - "Sind Sie sicher dass Sie den Raum löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. Alle Nachrichten und Medien, die der Raum beinhaltet werden vom Server gelöscht!", - }, }, reports: { tabs: { basic: "Allgemein", detail: "Details" } }, }, @@ -149,11 +144,13 @@ export default { is_encrypted: "Verschlüsselt", encryption: "Verschlüsselungs-Algorithmus", federatable: "Fö­de­rierbar", - public: "Öffentlich", + public: "Sichtbar im Raumverzeichnis", creator: "Ersteller", join_rules: "Beitrittsregeln", guest_access: "Gastzugriff", history_visibility: "Historie-Sichtbarkeit", + topic: "Thema", + avatar: "Avatar", }, enums: { join_rules: { @@ -174,6 +171,13 @@ export default { }, unencrypted: "Nicht verschlüsselt", }, + action: { + erase: { + title: "Raum löschen", + content: + "Sind Sie sicher dass Sie den Raum löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. Alle Nachrichten und Medien, die der Raum beinhaltet werden vom Server gelöscht!", + }, + }, }, reports: { name: "Ereignisbericht |||| Ereignisberichte", @@ -291,6 +295,23 @@ export default { media_length: "Größe der Dateien", }, }, + room_directory: { + name: "Raumverzeichnis", + fields: { + world_readable: "Gastbenutzer dürfen ohne Beitritt lesen", + guest_can_join: "Gastbenutzer dürfen beitreten", + }, + action: { + title: + "Raum aus Verzeichnis löschen |||| %{smart_count} Räume aus Verzeichnis löschen", + content: + "Möchten Sie den Raum wirklich aus dem Raumverzeichnis löschen? |||| Möchten Sie die %{smart_count} Räume wirklich aus dem Raumverzeichnis löschen?", + erase: "Lösche aus Verzeichnis", + create: "Eintragen ins Verzeichnis", + send_success: "Raum erfolgreich eingetragen.", + send_failure: "Beim Entfernen ist ein Fehler aufgetreten.", + }, + }, }, ra: { ...germanMessages.ra, diff --git a/src/i18n/en.js b/src/i18n/en.js index 50cba01..ec7f9b4 100644 --- a/src/i18n/en.js +++ b/src/i18n/en.js @@ -22,11 +22,6 @@ export default { detail: "Details", permission: "Permissions", }, - delete: { - title: "Delete room", - message: - "Are you sure you want to delete the room? This cannot be undone. All messages and shared media in the room will be deleted from the server!", - }, }, reports: { tabs: { basic: "Basic", detail: "Details" } }, }, @@ -147,11 +142,13 @@ export default { is_encrypted: "Encrypted", encryption: "Encryption", federatable: "Federatable", - public: "Public", + public: "Visible in room directory", creator: "Creator", join_rules: "Join rules", guest_access: "Guest access", history_visibility: "History visibility", + topic: "Topic", + avatar: "Avatar", }, enums: { join_rules: { @@ -172,6 +169,11 @@ export default { }, unencrypted: "Unencrypted", }, + erase: { + title: "Delete room", + content: + "Are you sure you want to delete the room? This cannot be undone. All messages and shared media in the room will be deleted from the server!", + }, }, reports: { name: "Reported event |||| Reported events", @@ -289,5 +291,22 @@ export default { media_length: "Media length", }, }, + room_directory: { + name: "Room directory", + fields: { + world_readable: "guest users may view without joining", + guest_can_join: "guest users may join", + }, + action: { + title: + "Delete room from directory |||| Delete %{smart_count} rooms from directory", + content: + "Are you sure you want to remove this room from directory? |||| Are you sure you want to remove these %{smart_count} rooms from directory", + erase: "Delete from room directory", + create: "Publish in room directory", + send_success: "Room successfully published.", + send_failure: "An error has occurred.", + }, + }, }, }; diff --git a/src/synapse/dataProvider.js b/src/synapse/dataProvider.js index 2dae5dc..245852c 100644 --- a/src/synapse/dataProvider.js +++ b/src/synapse/dataProvider.js @@ -195,6 +195,30 @@ const resourceMap = { return json.total; }, }, + room_directory: { + path: "/_matrix/client/r0/publicRooms", + map: rd => ({ + ...rd, + id: rd.room_id, + public: !!rd.public, + guest_access: !!rd.guest_access, + avatar_src: mxcUrlToHttp(rd.avatar_url), + }), + data: "chunk", + total: json => { + return json.total_room_count_estimate; + }, + create: params => ({ + endpoint: `/_matrix/client/r0/directory/list/room/${params.id}`, + body: { visibility: "public" }, + method: "PUT", + }), + delete: params => ({ + endpoint: `/_matrix/client/r0/directory/list/room/${params.id}`, + body: { visibility: "private" }, + method: "PUT", + }), + }, }; function filterNullValues(key, value) {