Merge branch 'master' into amp.chat
Change-Id: I6141964157bcb7218e2e6368a3ca8d20eb4855e9
This commit is contained in:
		
						commit
						ab649fbf70
					
				| @ -4,6 +4,7 @@ | |||||||
|   "description": "Admin GUI for the Matrix.org server Synapse", |   "description": "Admin GUI for the Matrix.org server Synapse", | ||||||
|   "author": "Awesome Technologies Innovationslabor GmbH", |   "author": "Awesome Technologies Innovationslabor GmbH", | ||||||
|   "license": "Apache-2.0", |   "license": "Apache-2.0", | ||||||
|  |   "homepage": ".", | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|     "url": "https://github.com/Awesome-Technologies/synapse-admin" |     "url": "https://github.com/Awesome-Technologies/synapse-admin" | ||||||
|  | |||||||
| @ -48,6 +48,7 @@ const App = () => ( | |||||||
|       icon={RoomIcon} |       icon={RoomIcon} | ||||||
|     /> |     /> | ||||||
|     <Resource name="connections" /> |     <Resource name="connections" /> | ||||||
|  |     <Resource name="servernotices" /> | ||||||
|   </Admin> |   </Admin> | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,13 +1,17 @@ | |||||||
| import React, { useState } from "react"; | import React, { useState } from "react"; | ||||||
| import { | import { | ||||||
|  |   fetchUtils, | ||||||
|  |   FormDataConsumer, | ||||||
|   Notification, |   Notification, | ||||||
|   useLogin, |   useLogin, | ||||||
|   useNotify, |   useNotify, | ||||||
|   useLocale, |   useLocale, | ||||||
|   useSetLocale, |   useSetLocale, | ||||||
|   useTranslate, |   useTranslate, | ||||||
|  |   PasswordInput, | ||||||
|  |   TextInput, | ||||||
| } from "react-admin"; | } from "react-admin"; | ||||||
| import { Field, Form } from "react-final-form"; | import { Form, useForm } from "react-final-form"; | ||||||
| import { | import { | ||||||
|   Avatar, |   Avatar, | ||||||
|   Button, |   Button, | ||||||
| @ -34,7 +38,7 @@ const useStyles = makeStyles(theme => ({ | |||||||
|     backgroundSize: "cover", |     backgroundSize: "cover", | ||||||
|   }, |   }, | ||||||
|   card: { |   card: { | ||||||
|     minWidth: 300, |     minWidth: "30em", | ||||||
|     marginTop: "6em", |     marginTop: "6em", | ||||||
|   }, |   }, | ||||||
|   avatar: { |   avatar: { | ||||||
| @ -70,7 +74,7 @@ const LoginPage = ({ theme }) => { | |||||||
|   var locale = useLocale(); |   var locale = useLocale(); | ||||||
|   const setLocale = useSetLocale(); |   const setLocale = useSetLocale(); | ||||||
|   const translate = useTranslate(); |   const translate = useTranslate(); | ||||||
|   const homeserver = localStorage.getItem("base_url"); |   const base_url = localStorage.getItem("base_url"); | ||||||
| 
 | 
 | ||||||
|   const renderInput = ({ |   const renderInput = ({ | ||||||
|     meta: { touched, error } = {}, |     meta: { touched, error } = {}, | ||||||
| @ -88,15 +92,23 @@ const LoginPage = ({ theme }) => { | |||||||
| 
 | 
 | ||||||
|   const validate = values => { |   const validate = values => { | ||||||
|     const errors = {}; |     const errors = {}; | ||||||
|     if (!values.homeserver) { |  | ||||||
|       errors.homeserver = translate("ra.validation.required"); |  | ||||||
|     } |  | ||||||
|     if (!values.username) { |     if (!values.username) { | ||||||
|       errors.username = translate("ra.validation.required"); |       errors.username = translate("ra.validation.required"); | ||||||
|     } |     } | ||||||
|     if (!values.password) { |     if (!values.password) { | ||||||
|       errors.password = translate("ra.validation.required"); |       errors.password = translate("ra.validation.required"); | ||||||
|     } |     } | ||||||
|  |     if (!values.base_url) { | ||||||
|  |       errors.base_url = translate("ra.validation.required"); | ||||||
|  |     } else { | ||||||
|  |       if (!values.base_url.match(/^(http|https):\/\//)) { | ||||||
|  |         errors.base_url = translate("synapseadmin.auth.protocol_error"); | ||||||
|  |       } else if ( | ||||||
|  |         !values.base_url.match(/^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?$/) | ||||||
|  |       ) { | ||||||
|  |         errors.base_url = translate("synapseadmin.auth.url_error"); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|     return errors; |     return errors; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -115,9 +127,75 @@ const LoginPage = ({ theme }) => { | |||||||
|     }); |     }); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   const extractHomeServer = username => { | ||||||
|  |     const usernameRegex = /@[a-zA-Z0-9._=\-/]+:([a-zA-Z0-9\-.]+\.[a-zA-Z]+)/; | ||||||
|  |     if (!username) return null; | ||||||
|  |     const res = username.match(usernameRegex); | ||||||
|  |     if (res) return res[1]; | ||||||
|  |     return null; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   const UserData = ({ formData }) => { | ||||||
|  |     const form = useForm(); | ||||||
|  | 
 | ||||||
|  |     const handleUsernameChange = _ => { | ||||||
|  |       if (formData.base_url) return; | ||||||
|  |       // check if username is a full qualified userId then set base_url accordially
 | ||||||
|  |       const home_server = extractHomeServer(formData.username); | ||||||
|  |       const wellKnownUrl = `https://${home_server}/.well-known/matrix/client`; | ||||||
|  |       if (home_server) { | ||||||
|  |         // fetch .well-known entry to get base_url
 | ||||||
|  |         fetchUtils | ||||||
|  |           .fetchJson(wellKnownUrl, { method: "GET" }) | ||||||
|  |           .then(({ json }) => { | ||||||
|  |             form.change("base_url", json["m.homeserver"].base_url); | ||||||
|  |           }) | ||||||
|  |           .catch(_ => { | ||||||
|  |             // if there is no .well-known entry, try the home server name
 | ||||||
|  |             form.change("base_url", `https://${home_server}`); | ||||||
|  |           }); | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <div> | ||||||
|  |         <div className={classes.input}> | ||||||
|  |           <TextInput | ||||||
|  |             autoFocus | ||||||
|  |             name="username" | ||||||
|  |             component={renderInput} | ||||||
|  |             label={translate("ra.auth.username")} | ||||||
|  |             disabled={loading} | ||||||
|  |             onBlur={handleUsernameChange} | ||||||
|  |             fullWidth | ||||||
|  |           /> | ||||||
|  |         </div> | ||||||
|  |         <div className={classes.input}> | ||||||
|  |           <PasswordInput | ||||||
|  |             name="password" | ||||||
|  |             component={renderInput} | ||||||
|  |             label={translate("ra.auth.password")} | ||||||
|  |             type="password" | ||||||
|  |             disabled={loading} | ||||||
|  |             fullWidth | ||||||
|  |           /> | ||||||
|  |         </div> | ||||||
|  |         <div className={classes.input}> | ||||||
|  |           <TextInput | ||||||
|  |             name="base_url" | ||||||
|  |             component={renderInput} | ||||||
|  |             label={translate("synapseadmin.auth.base_url")} | ||||||
|  |             disabled={loading} | ||||||
|  |             fullWidth | ||||||
|  |           /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Form |     <Form | ||||||
|       initialValues={{ homeserver: homeserver }} |       initialValues={{ base_url: base_url }} | ||||||
|       onSubmit={handleSubmit} |       onSubmit={handleSubmit} | ||||||
|       validate={validate} |       validate={validate} | ||||||
|       render={({ handleSubmit }) => ( |       render={({ handleSubmit }) => ( | ||||||
| @ -146,32 +224,9 @@ const LoginPage = ({ theme }) => { | |||||||
|                     <MenuItem value="en">English</MenuItem> |                     <MenuItem value="en">English</MenuItem> | ||||||
|                   </Select> |                   </Select> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div className={classes.input}> |                 <FormDataConsumer> | ||||||
|                   <Field |                   {formDataProps => <UserData {...formDataProps} />} | ||||||
|                     autoFocus |                 </FormDataConsumer> | ||||||
|                     name="homeserver" |  | ||||||
|                     component={renderInput} |  | ||||||
|                     label={translate("synapseadmin.auth.homeserver")} |  | ||||||
|                     disabled={loading} |  | ||||||
|                   /> |  | ||||||
|                 </div> |  | ||||||
|                 <div className={classes.input}> |  | ||||||
|                   <Field |  | ||||||
|                     name="username" |  | ||||||
|                     component={renderInput} |  | ||||||
|                     label={translate("ra.auth.username")} |  | ||||||
|                     disabled={loading} |  | ||||||
|                   /> |  | ||||||
|                 </div> |  | ||||||
|                 <div className={classes.input}> |  | ||||||
|                   <Field |  | ||||||
|                     name="password" |  | ||||||
|                     component={renderInput} |  | ||||||
|                     label={translate("ra.auth.password")} |  | ||||||
|                     type="password" |  | ||||||
|                     disabled={loading} |  | ||||||
|                   /> |  | ||||||
|                 </div> |  | ||||||
|               </div> |               </div> | ||||||
|               <CardActions className={classes.actions}> |               <CardActions className={classes.actions}> | ||||||
|                 <Button |                 <Button | ||||||
|  | |||||||
							
								
								
									
										100
									
								
								src/components/ServerNotices.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/components/ServerNotices.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | |||||||
|  | import React, { Fragment, useState } from "react"; | ||||||
|  | import { | ||||||
|  |   Button, | ||||||
|  |   SaveButton, | ||||||
|  |   SimpleForm, | ||||||
|  |   TextInput, | ||||||
|  |   Toolbar, | ||||||
|  |   required, | ||||||
|  |   useCreate, | ||||||
|  |   useNotify, | ||||||
|  |   useTranslate, | ||||||
|  | } from "react-admin"; | ||||||
|  | import MessageIcon from "@material-ui/icons/Message"; | ||||||
|  | import IconCancel from "@material-ui/icons/Cancel"; | ||||||
|  | import Dialog from "@material-ui/core/Dialog"; | ||||||
|  | import DialogContent from "@material-ui/core/DialogContent"; | ||||||
|  | import DialogContentText from "@material-ui/core/DialogContentText"; | ||||||
|  | import DialogTitle from "@material-ui/core/DialogTitle"; | ||||||
|  | 
 | ||||||
|  | const ServerNoticeDialog = ({ open, loading, onClose, onSend }) => { | ||||||
|  |   const translate = useTranslate(); | ||||||
|  | 
 | ||||||
|  |   const ServerNoticeToolbar = props => ( | ||||||
|  |     <Toolbar {...props}> | ||||||
|  |       <SaveButton label="resources.servernotices.action.send" /> | ||||||
|  |       <Button label="ra.action.cancel" onClick={onClose}> | ||||||
|  |         <IconCancel /> | ||||||
|  |       </Button> | ||||||
|  |     </Toolbar> | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <Dialog open={open} onClose={onClose} loading={loading}> | ||||||
|  |       <DialogTitle> | ||||||
|  |         {translate("resources.servernotices.action.send")} | ||||||
|  |       </DialogTitle> | ||||||
|  |       <DialogContent> | ||||||
|  |         <DialogContentText> | ||||||
|  |           {translate("resources.servernotices.helper.send")} | ||||||
|  |         </DialogContentText> | ||||||
|  |         <SimpleForm | ||||||
|  |           toolbar={<ServerNoticeToolbar />} | ||||||
|  |           submitOnEnter={false} | ||||||
|  |           redirect={false} | ||||||
|  |           save={onSend} | ||||||
|  |         > | ||||||
|  |           <TextInput | ||||||
|  |             source="body" | ||||||
|  |             label="resources.servernotices.fields.body" | ||||||
|  |             fullWidth | ||||||
|  |             multiline | ||||||
|  |             rows="4" | ||||||
|  |             resettable | ||||||
|  |             validate={required()} | ||||||
|  |           /> | ||||||
|  |         </SimpleForm> | ||||||
|  |       </DialogContent> | ||||||
|  |     </Dialog> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const ServerNoticeButton = ({ record }) => { | ||||||
|  |   const [open, setOpen] = useState(false); | ||||||
|  |   const notify = useNotify(); | ||||||
|  |   const [create, { loading }] = useCreate("servernotices"); | ||||||
|  | 
 | ||||||
|  |   const handleDialogOpen = () => setOpen(true); | ||||||
|  |   const handleDialogClose = () => setOpen(false); | ||||||
|  | 
 | ||||||
|  |   const handleSend = values => { | ||||||
|  |     create( | ||||||
|  |       { payload: { data: { id: record.id, ...values } } }, | ||||||
|  |       { | ||||||
|  |         onSuccess: () => { | ||||||
|  |           notify("resources.servernotices.action.send_success"); | ||||||
|  |           handleDialogClose(); | ||||||
|  |         }, | ||||||
|  |         onFailure: () => | ||||||
|  |           notify("resources.servernotices.action.send_failure", "error"), | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <Fragment> | ||||||
|  |       <Button | ||||||
|  |         label="resources.servernotices.send" | ||||||
|  |         onClick={handleDialogOpen} | ||||||
|  |         disabled={loading} | ||||||
|  |       > | ||||||
|  |         <MessageIcon /> | ||||||
|  |       </Button> | ||||||
|  |       <ServerNoticeDialog | ||||||
|  |         open={open} | ||||||
|  |         onClose={handleDialogClose} | ||||||
|  |         onSend={handleSend} | ||||||
|  |       /> | ||||||
|  |     </Fragment> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
| @ -43,7 +43,7 @@ const validateDisplayName = fieldval => | |||||||
|     : undefined; |     : undefined; | ||||||
| 
 | 
 | ||||||
| function approximateAliasLength(alias, homeserver) { | function approximateAliasLength(alias, homeserver) { | ||||||
|   /* TODO maybe handle punycode in homeserver URL */ |   /* TODO maybe handle punycode in homeserver name */ | ||||||
| 
 | 
 | ||||||
|   var te; |   var te; | ||||||
| 
 | 
 | ||||||
| @ -69,7 +69,7 @@ const validateAlias = fieldval => { | |||||||
|   if (fieldval === undefined) { |   if (fieldval === undefined) { | ||||||
|     return undefined; |     return undefined; | ||||||
|   } |   } | ||||||
|   const homeserver = localStorage.getItem("home_server_url"); |   const homeserver = localStorage.getItem("home_server"); | ||||||
| 
 | 
 | ||||||
|   if (approximateAliasLength(fieldval, homeserver) > 255) { |   if (approximateAliasLength(fieldval, homeserver) > 255) { | ||||||
|     return "synapseadmin.rooms.alias_too_long"; |     return "synapseadmin.rooms.alias_too_long"; | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ import { | |||||||
|   Pagination, |   Pagination, | ||||||
| } from "react-admin"; | } from "react-admin"; | ||||||
| import SaveQrButton from "./SaveQrButton"; | import SaveQrButton from "./SaveQrButton"; | ||||||
|  | import { ServerNoticeButton } from "./ServerNotices"; | ||||||
| 
 | 
 | ||||||
| const UserPagination = props => ( | const UserPagination = props => ( | ||||||
|   <Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} /> |   <Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} /> | ||||||
| @ -82,7 +83,7 @@ export const UserList = props => ( | |||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| function generateRandomUser() { | function generateRandomUser() { | ||||||
|   const homeserver = localStorage.getItem("home_server_url"); |   const homeserver = localStorage.getItem("home_server"); | ||||||
|   const user_id = |   const user_id = | ||||||
|     "@" + |     "@" + | ||||||
|     Array(8) |     Array(8) | ||||||
| @ -175,6 +176,7 @@ const UserEditToolbar = props => { | |||||||
|         label="resources.users.action.erase" |         label="resources.users.action.erase" | ||||||
|         title={translate("resources.users.helper.erase")} |         title={translate("resources.users.helper.erase")} | ||||||
|       /> |       /> | ||||||
|  |       <ServerNoticeButton /> | ||||||
|     </Toolbar> |     </Toolbar> | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -4,8 +4,11 @@ export default { | |||||||
|   ...germanMessages, |   ...germanMessages, | ||||||
|   synapseadmin: { |   synapseadmin: { | ||||||
|     auth: { |     auth: { | ||||||
|       homeserver: "Heimserver", |       base_url: "Heimserver URL", | ||||||
|       welcome: "Willkommen bei Synapse-admin", |       welcome: "Willkommen bei Synapse-admin", | ||||||
|  |       username_error: "Bitte vollständigen Nutzernamen angeben: '@user:domain'", | ||||||
|  |       protocol_error: "Die URL muss mit 'http://' oder 'https://' beginnen", | ||||||
|  |       url_error: "Keine gültige Matrix Server URL", | ||||||
|     }, |     }, | ||||||
|     action: { |     action: { | ||||||
|       save_and_show: "Speichern und QR Code erzeugen", |       save_and_show: "Speichern und QR Code erzeugen", | ||||||
| @ -77,6 +80,41 @@ export default { | |||||||
|         user_agent: "User Agent", |         user_agent: "User Agent", | ||||||
|       }, |       }, | ||||||
|     }, |     }, | ||||||
|  |     servernotices: { | ||||||
|  |       name: "Serverbenachrichtigungen", | ||||||
|  |       send: "Servernachricht versenden", | ||||||
|  |       fields: { | ||||||
|  |         body: "Nachricht", | ||||||
|  |       }, | ||||||
|  |       action: { | ||||||
|  |         send: "Sende Nachricht", | ||||||
|  |         send_success: "Nachricht erfolgreich versendet.", | ||||||
|  |         send_failure: "Beim Versenden ist ein Fehler aufgetreten.", | ||||||
|  |       }, | ||||||
|  |       helper: { | ||||||
|  |         send: | ||||||
|  |           'Sendet eine Serverbenachrichtigung an die ausgewählten Nutzer. Hierfür muss das Feature "Server Notices" auf dem Server aktiviert sein.', | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   ra: { | ||||||
|  |     ...germanMessages.ra, | ||||||
|  |     auth: { | ||||||
|  |       ...germanMessages.ra.auth, | ||||||
|  |       auth_check_error: "Anmeldung fehlgeschlagen", | ||||||
|  |     }, | ||||||
|  |     input: { | ||||||
|  |       ...germanMessages.ra.input, | ||||||
|  |       password: { | ||||||
|  |         ...germanMessages.ra.input.password, | ||||||
|  |         toggle_hidden: "Anzeigen", | ||||||
|  |         toggle_visible: "Verstecken", | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     notification: { | ||||||
|  |       ...germanMessages.ra.notifiaction, | ||||||
|  |       logged_out: "Abgemeldet", | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
|   ra: { |   ra: { | ||||||
|     ...germanMessages.ra, |     ...germanMessages.ra, | ||||||
|  | |||||||
| @ -4,8 +4,11 @@ export default { | |||||||
|   ...englishMessages, |   ...englishMessages, | ||||||
|   synapseadmin: { |   synapseadmin: { | ||||||
|     auth: { |     auth: { | ||||||
|       homeserver: "Homeserver", |       base_url: "Homeserver URL", | ||||||
|       welcome: "Welcome to Synapse-admin", |       welcome: "Welcome to Synapse-admin", | ||||||
|  |       username_error: "Please enter fully qualified user ID: '@user:domain'", | ||||||
|  |       protocol_error: "URL has to start with 'http://' or 'https://'", | ||||||
|  |       url_error: "Not a valid Matrix server URL", | ||||||
|     }, |     }, | ||||||
|     action: { |     action: { | ||||||
|       save_and_show: "Create QR code", |       save_and_show: "Create QR code", | ||||||
| @ -78,5 +81,21 @@ export default { | |||||||
|         user_agent: "User agent", |         user_agent: "User agent", | ||||||
|       }, |       }, | ||||||
|     }, |     }, | ||||||
|  |     servernotices: { | ||||||
|  |       name: "Server Notices", | ||||||
|  |       send: "Send server notices", | ||||||
|  |       fields: { | ||||||
|  |         body: "Message", | ||||||
|  |       }, | ||||||
|  |       action: { | ||||||
|  |         send: "Send note", | ||||||
|  |         send_success: "Server notice successfully sent.", | ||||||
|  |         send_failure: "An error has occurred.", | ||||||
|  |       }, | ||||||
|  |       helper: { | ||||||
|  |         send: | ||||||
|  |           'Sends a server notice to the selected users. The feature "Server Notices" has to be activated at the server.', | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -1,23 +1,8 @@ | |||||||
| import { fetchUtils } from "react-admin"; | import { fetchUtils } from "react-admin"; | ||||||
| 
 | 
 | ||||||
| const ensureHttpsForUrl = url => { |  | ||||||
|   if (/^https:\/\//i.test(url)) { |  | ||||||
|     return url; |  | ||||||
|   } |  | ||||||
|   const domain = url.replace(/http.?:\/\//g, ""); |  | ||||||
|   return "https://" + domain; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const stripTrailingSlash = str => { |  | ||||||
|   if (!str) { |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   return str.endsWith("/") ? str.slice(0, -1) : str; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const authProvider = { | const authProvider = { | ||||||
|   // called when the user attempts to log in
 |   // called when the user attempts to log in
 | ||||||
|   login: ({ homeserver, username, password }) => { |   login: ({ base_url, username, password }) => { | ||||||
|     console.log("login "); |     console.log("login "); | ||||||
|     const options = { |     const options = { | ||||||
|       method: "POST", |       method: "POST", | ||||||
| @ -28,17 +13,16 @@ const authProvider = { | |||||||
|       }), |       }), | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     const url = window.decodeURIComponent(homeserver); |     // use the base_url from login instead of the well_known entry from the
 | ||||||
|     const trimmed_url = url.trim().replace(/\s/g, ""); |     // server, since the admin might want to access the admin API via some
 | ||||||
|     const login_api_url = |     // private address
 | ||||||
|       ensureHttpsForUrl(trimmed_url) + "/_matrix/client/r0/login"; |     localStorage.setItem("base_url", base_url); | ||||||
|  | 
 | ||||||
|  |     const decoded_base_url = window.decodeURIComponent(base_url); | ||||||
|  |     const login_api_url = decoded_base_url + "/_matrix/client/r0/login"; | ||||||
| 
 | 
 | ||||||
|     return fetchUtils.fetchJson(login_api_url, options).then(({ json }) => { |     return fetchUtils.fetchJson(login_api_url, options).then(({ json }) => { | ||||||
|       const normalized_base_url = stripTrailingSlash( |       localStorage.setItem("home_server", json.home_server); | ||||||
|         json.well_known["m.homeserver"].base_url |  | ||||||
|       ); |  | ||||||
|       localStorage.setItem("base_url", normalized_base_url); |  | ||||||
|       localStorage.setItem("home_server_url", json.home_server); |  | ||||||
|       localStorage.setItem("user_id", json.user_id); |       localStorage.setItem("user_id", json.user_id); | ||||||
|       localStorage.setItem("access_token", json.access_token); |       localStorage.setItem("access_token", json.access_token); | ||||||
|       localStorage.setItem("device_id", json.device_id); |       localStorage.setItem("device_id", json.device_id); | ||||||
|  | |||||||
| @ -27,6 +27,11 @@ const resourceMap = { | |||||||
|     }), |     }), | ||||||
|     data: "users", |     data: "users", | ||||||
|     total: json => json.total, |     total: json => json.total, | ||||||
|  |     create: data => ({ | ||||||
|  |       endpoint: `/_synapse/admin/v2/users/${data.id}`, | ||||||
|  |       body: data, | ||||||
|  |       method: "PUT", | ||||||
|  |     }), | ||||||
|     delete: id => ({ |     delete: id => ({ | ||||||
|       endpoint: `/_synapse/admin/v1/deactivate/${id}`, |       endpoint: `/_synapse/admin/v1/deactivate/${id}`, | ||||||
|       body: { erase: true }, |       body: { erase: true }, | ||||||
| @ -41,23 +46,19 @@ const resourceMap = { | |||||||
|     }), |     }), | ||||||
|     data: "rooms", |     data: "rooms", | ||||||
|     total: json => json.total_rooms, |     total: json => json.total_rooms, | ||||||
|     create: params => { |     create: data => ({ | ||||||
|       let invitees = params.data.invitees; |  | ||||||
|       return { |  | ||||||
|         method: "POST", |  | ||||||
|       endpoint: "/_matrix/client/r0/createRoom", |       endpoint: "/_matrix/client/r0/createRoom", | ||||||
|       body: { |       body: { | ||||||
|           name: params.data.name, |         name: data.name, | ||||||
|           room_alias_name: params.data.canonical_alias, |         room_alias_name: data.canonical_alias, | ||||||
|           visibility: params.data.public ? "public" : "private", |         visibility: data.public ? "public" : "private", | ||||||
|         invite: |         invite: | ||||||
|             Array.isArray(invitees) && invitees.length > 0 |           Array.isArray(data.invitees) && data.invitees.length > 0 | ||||||
|               ? invitees |             ? data.invitees | ||||||
|             : undefined, |             : undefined, | ||||||
|       }, |       }, | ||||||
|         map: r => ({ id: r.room_id }), |       method: "POST", | ||||||
|       }; |     }) | ||||||
|     }, |  | ||||||
|   }, |   }, | ||||||
|   connections: { |   connections: { | ||||||
|     path: "/_synapse/admin/v1/whois", |     path: "/_synapse/admin/v1/whois", | ||||||
| @ -67,6 +68,20 @@ const resourceMap = { | |||||||
|     }), |     }), | ||||||
|     data: "connections", |     data: "connections", | ||||||
|   }, |   }, | ||||||
|  |   servernotices: { | ||||||
|  |     map: n => ({ id: n.event_id }), | ||||||
|  |     create: data => ({ | ||||||
|  |       endpoint: "/_synapse/admin/v1/send_server_notice", | ||||||
|  |       body: { | ||||||
|  |         user_id: data.id, | ||||||
|  |         content: { | ||||||
|  |           msgtype: "m.text", | ||||||
|  |           body: data.body, | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |       method: "POST", | ||||||
|  |     }), | ||||||
|  |   }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function filterNullValues(key, value) { | function filterNullValues(key, value) { | ||||||
| @ -200,25 +215,16 @@ const dataProvider = { | |||||||
|     if (!homeserver || !(resource in resourceMap)) return Promise.reject(); |     if (!homeserver || !(resource in resourceMap)) return Promise.reject(); | ||||||
| 
 | 
 | ||||||
|     const res = resourceMap[resource]; |     const res = resourceMap[resource]; | ||||||
|  |     if (!("create" in res)) return Promise.reject(); | ||||||
| 
 | 
 | ||||||
|     if ("create" in res) { |     const create = res["create"](params.data); | ||||||
|       const create = res["create"](params); |  | ||||||
|     const endpoint_url = homeserver + create.endpoint; |     const endpoint_url = homeserver + create.endpoint; | ||||||
|     return jsonClient(endpoint_url, { |     return jsonClient(endpoint_url, { | ||||||
|       method: create.method, |       method: create.method, | ||||||
|       body: JSON.stringify(create.body, filterNullValues), |       body: JSON.stringify(create.body, filterNullValues), | ||||||
|       }).then(({ json }) => ({ |  | ||||||
|         data: create.map(json), |  | ||||||
|       })); |  | ||||||
|     } else { |  | ||||||
|       const endpoint_url = homeserver + res.path; |  | ||||||
|       return jsonClient(`${endpoint_url}/${params.data.id}`, { |  | ||||||
|         method: "PUT", |  | ||||||
|         body: JSON.stringify(params.data, filterNullValues), |  | ||||||
|     }).then(({ json }) => ({ |     }).then(({ json }) => ({ | ||||||
|       data: res.map(json), |       data: res.map(json), | ||||||
|     })); |     })); | ||||||
|     } |  | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   delete: (resource, params) => { |   delete: (resource, params) => { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Manuel Stahl
						Manuel Stahl