From 9bde468e303bbf7cebbb25fa83b76ad59e8b4e83 Mon Sep 17 00:00:00 2001
From: David Baker <dave@matrix.org>
Date: Wed, 15 Aug 2018 17:03:54 +0100
Subject: [PATCH] Shift to M_RESOURCE_LIMIT_EXCEEDED errors

With support for admin_contact and limit_type fields

For https://github.com/vector-im/riot-web/issues/7091
---
 src/components/structures/LoggedInView.js     | 16 +++++---
 src/components/structures/RoomStatusBar.js    | 25 ++++++++++--
 src/components/structures/login/Login.js      | 18 +++++++--
 .../structures/login/Registration.js          | 18 +++++++--
 .../views/globals/ServerLimitBar.js           | 40 ++++++++++++++-----
 src/i18n/strings/en_EN.json                   | 25 +++++++++---
 6 files changed, 111 insertions(+), 31 deletions(-)

diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js
index 5b617feb68..6217a91b2e 100644
--- a/src/components/structures/LoggedInView.js
+++ b/src/components/structures/LoggedInView.js
@@ -434,17 +434,21 @@ const LoggedInView = React.createClass({
         }
 
         const mauLimitEvent = this.state.serverNoticeEvents.find((e) => {
-            return e && e.getType() === 'm.server_notice.usage_limit_reached' &&
-                e.getContent().limit_type &&
-                e.getContent().limit_type === 'monthly_active_user'
+            return e && e.getType() === 'm.server_notice.usage_limit_reached';
         });
 
         let topBar;
         const isGuest = this.props.matrixClient.isGuest();
-        if (this.state.syncErrorData && this.state.syncErrorData.error.errcode === 'M_MAU_LIMIT_EXCEEDED') {
-            topBar = <ServerLimitBar kind='hard' />;
+        if (this.state.syncErrorData && this.state.syncErrorData.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED') {
+            topBar = <ServerLimitBar kind='hard'
+                adminContact={this.state.syncErrorData.error.data.admin_contact}
+                limitType={this.state.syncErrorData.error.data.limit_type}
+            />;
         } else if (mauLimitEvent) {
-            topBar = <ServerLimitBar kind='soft' adminContact={mauLimitEvent.getContent().admin_contact} />;
+            topBar = <ServerLimitBar kind='soft'
+                adminContact={mauLimitEvent.getContent().admin_contact}
+                limitType={mauLimitEvent.getContent().limit_type}
+            />;
         } else if (this.props.showCookieBar &&
             this.props.config.piwik
         ) {
diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js
index ef82ed4bad..260aec81ea 100644
--- a/src/components/structures/RoomStatusBar.js
+++ b/src/components/structures/RoomStatusBar.js
@@ -293,11 +293,11 @@ module.exports = React.createClass({
         // It also trumps the "some not sent" msg since you can't resend without
         // a connection!
         // There's one situation in which we don't show this 'no connection' bar, and that's
-        // if it's a monthly-active-user limit error: those are shown in the top bar.
+        // if it's a resource limit exceeded error: those are shown in the top bar.
         const errorIsMauError = Boolean(
             this.state.syncStateData &&
             this.state.syncStateData.error &&
-            this.state.syncStateData.error.errcode === 'M_MAU_LIMIT_EXCEEDED'
+            this.state.syncStateData.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED'
         );
         return this.state.syncState === "ERROR" && !errorIsMauError;
     },
@@ -327,11 +327,18 @@ module.exports = React.createClass({
         } else {
             let consentError = null;
             let mauError = null;
+            const translateMauError = sub => {
+                if (mauError.data.admin_contact) {
+                    return <a href={mauError.data.admin_contact} target="_blank" rel="noopener">{sub}</a>;
+                } else {
+                    return sub;
+                }
+            };
             for (const m of unsentMessages) {
                 if (m.error && m.error.errcode === 'M_CONSENT_NOT_GIVEN') {
                     consentError = m.error;
                     break;
-                } else if (m.error && m.error.errcode === 'M_MAU_LIMIT_EXCEEDED') {
+                } else if (m.error && m.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED') {
                     mauError = m.error;
                     break;
                 }
@@ -348,8 +355,18 @@ module.exports = React.createClass({
                             </a>,
                     },
                 );
+            } else if (mauError && mauError.data.limit_type === 'monthly_active_user') {
+                title = _t(
+                    "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. " +
+                    "Please <a>contact your service administrator</a> to continue using the service.",
+                    {}, { 'a' : translateMauError },
+                );
             } else if (mauError) {
-                title = _t("Your message wasn’t sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.");
+                title = _t(
+                    "Your message wasn't sent because this homeserver has exceeded a resource limit. " +
+                    "Please <a>contact your service administrator</a> to continue using the service.",
+                    {}, { 'a' : translateMauError },
+                );
             } else if (
                 unsentMessages.length === 1 &&
                 unsentMessages[0].error &&
diff --git a/src/components/structures/login/Login.js b/src/components/structures/login/Login.js
index cac1c99f24..77db6ea444 100644
--- a/src/components/structures/login/Login.js
+++ b/src/components/structures/login/Login.js
@@ -121,12 +121,24 @@ module.exports = React.createClass({
             const usingEmail = username.indexOf("@") > 0;
             if (error.httpStatus === 400 && usingEmail) {
                 errorText = _t('This Home Server does not support login using email address.');
-            } else if (error.errcode == 'M_MAU_LIMIT_EXCEEDED') {
+            } else if (error.errcode == 'M_RESOURCE_LIMIT_EXCEEDED') {
                 errorText = (
                     <div>
-                        <div>{ _t('This homeserver has hit its Monthly Active User limit') }</div>
+                        <div>{error.data.error ? error.data.error : _t("This server has exceeded its available resources")}</div>
                         <div className="mx_Login_smallError">
-                            { _t('Please contact your service administrator to continue using this service.') }
+                            {_t(
+                                "Please <a>contact your service administrator</a> to continue using this service.",
+                                {},
+                                {
+                                    a: (sub) => {
+                                        if (error.data.admin_contact) {
+                                            return <a rel="noopener" target="_blank" href={error.data.admin_contact}>{sub}</a>;
+                                        } else {
+                                            return sub;
+                                        }
+                                    },
+                                },
+                            )}
                         </div>
                     </div>
                 );
diff --git a/src/components/structures/login/Registration.js b/src/components/structures/login/Registration.js
index 1f6a2fbcdb..3e2b3c2bdc 100644
--- a/src/components/structures/login/Registration.js
+++ b/src/components/structures/login/Registration.js
@@ -164,10 +164,22 @@ module.exports = React.createClass({
         if (!success) {
             let msg = response.message || response.toString();
             // can we give a better error message?
-            if (response.errcode == 'M_MAU_LIMIT_EXCEEDED') {
+            if (response.errcode == 'M_RESOURCE_LIMIT_EXCEEDED') {
                 msg = <div>
-                    <p>{_t("This homeserver has hit its Monthly Active User limit")}</p>
-                    <p>{_t("Please contact your service administrator to continue using this service.")}</p>
+                    <p>{response.data.error ? response.data.error : _t("This server has exceeded its available resources")}</p>
+                    <p>{_t(
+                        "Please <a>contact your service administrator</a> to continue using this service.",
+                        {},
+                        {
+                            a: (sub) => {
+                                if (response.data.admin_contact) {
+                                    return <a rel="noopener" target="_blank" href={response.data.admin_contact}>{sub}</a>;
+                                } else {
+                                    return sub;
+                                }
+                            },
+                        },
+                    )}</p>
                 </div>;
             } else if (response.required_stages && response.required_stages.indexOf('m.login.msisdn') > -1) {
                 let msisdnAvailable = false;
diff --git a/src/components/views/globals/ServerLimitBar.js b/src/components/views/globals/ServerLimitBar.js
index c0a7376bd6..375d52bbe4 100644
--- a/src/components/views/globals/ServerLimitBar.js
+++ b/src/components/views/globals/ServerLimitBar.js
@@ -23,7 +23,9 @@ export default React.createClass({
     propTypes: {
         // 'hard' if the logged in user has been locked out, 'soft' if they haven't
         kind: PropTypes.string,
-        adminContent: PropTypes.string,
+        adminContact: PropTypes.string,
+        // The type of limit that has been hit.
+        limitType: PropTypes.string.isRequired,
     },
 
     getDefaultProps: function() {
@@ -36,42 +38,60 @@ export default React.createClass({
         const toolbarClasses = {
             'mx_MatrixToolbar': true,
         };
-        let content;
 
         const translateLink = (sub) => {
-            if (this.props.adminContent) {
-                return <a href={this.props.adminContent}>{sub}</a>;
+            if (this.props.adminContact) {
+                return <a rel="noopener" target="_blank" href={this.props.adminContact}>{sub}</a>;
             } else {
                 return sub;
             }
         };
 
+        let adminContact;
+        let limitError;
         if (this.props.kind === 'hard') {
             toolbarClasses['mx_MatrixToolbar_error'] = true;
-            content = _t(
-                "This homeserver has hit its Monthly Active User limit. " +
+            adminContact = _t(
                 "Please <a>contact your service administrator</a> to continue using the service.",
                 {},
                 {
                     'a': translateLink,
                 },
             );
+            if (this.props.limitType === 'monthly_active_user') {
+                limitError = _t("This homeserver has hit its Monthly Active User limit.");
+            } else {
+                limitError = _t("This homeserver has exceeded one of its resource limits.");
+            }
         } else {
             toolbarClasses['mx_MatrixToolbar_info'] = true;
-            content = _t(
-                "This homeserver has hit its Monthly Active User " +
-                "limit so some users will not be able to log in. " +
+            adminContact = _t(
                 "Please <a>contact your service administrator</a> to get this limit increased.",
                 {},
                 {
                     'a': translateLink,
                 },
             );
+            if (this.props.limitType === 'monthly_active_user') {
+                limitError = _t(
+                    "This homeserver has hit its Monthly Active User limit so " +
+                    "<b>some users will not be able to log in</b>.", {},
+                    {'b': sub => <b>{sub}</b>},
+                );
+            } else {
+                limitError = _t(
+                    "This homeserver has exceeded one of its resource limits so " +
+                    "<b>some users will not be able to log in</b>.", {},
+                    {'b': sub => <b>{sub}</b>},
+                );
+            }
         }
         return (
             <div className={classNames(toolbarClasses)}>
                 <div className="mx_MatrixToolbar_content">
-                    { content }
+                    {limitError}
+                    {' '}
+                    {adminContact}
                 </div>
             </div>
         );
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 08c7ae086d..68a4ce1508 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -543,6 +543,10 @@
     "Internal room ID: ": "Internal room ID: ",
     "Room version number: ": "Room version number: ",
     "Add a topic": "Add a topic",
+    "There is a known vulnerability affecting this room.": "There is a known vulnerability affecting this room.",
+    "This room version is vulnerable to malicious modification of room state.": "This room version is vulnerable to malicious modification of room state.",
+    "Click here to upgrade to the latest room version and ensure room integrity is protected.": "Click here to upgrade to the latest room version and ensure room integrity is protected.",
+    "Only room administrators will see this warning": "Only room administrators will see this warning",
     "Search…": "Search…",
     "This Room": "This Room",
     "All Rooms": "All Rooms",
@@ -679,8 +683,12 @@
     "A new version of Riot is available.": "A new version of Riot is available.",
     "To return to your account in future you need to <u>set a password</u>": "To return to your account in future you need to <u>set a password</u>",
     "Set Password": "Set Password",
-    "This homeserver has hit its Monthly Active User limit. Please <a>contact your service administrator</a> to continue using the service.": "This homeserver has hit its Monthly Active User limit. Please <a>contact your service administrator</a> to continue using the service.",
-    "This homeserver has hit its Monthly Active User limit so some users will not be able to log in. Please <a>contact your service administrator</a> to get this limit increased.": "This homeserver has hit its Monthly Active User limit so some users will not be able to log in. Please <a>contact your service administrator</a> to get this limit increased.",
+    "Please <a>contact your service administrator</a> to continue using the service.": "Please <a>contact your service administrator</a> to continue using the service.",
+    "This homeserver has hit its Monthly Active User limit.": "This homeserver has hit its Monthly Active User limit.",
+    "This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.",
+    "Please <a>contact your service administrator</a> to get this limit increased.": "Please <a>contact your service administrator</a> to get this limit increased.",
+    "This homeserver has hit its Monthly Active User limit so <b>some users will not be able to log in</b>.": "This homeserver has hit its Monthly Active User limit so <b>some users will not be able to log in</b>.",
+    "This homeserver has exceeded one of its resource limits so <b>some users will not be able to log in</b>.": "This homeserver has exceeded one of its resource limits so <b>some users will not be able to log in</b>.",
     "Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
     "Checking for an update...": "Checking for an update...",
     "No update available.": "No update available.",
@@ -857,6 +865,12 @@
     "Ignore request": "Ignore request",
     "Loading device info...": "Loading device info...",
     "Encryption key request": "Encryption key request",
+    "Upgrade Room Version": "Upgrade Room Version",
+    "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:",
+    "Create a new room with the same name, description and avatar": "Create a new room with the same name, description and avatar",
+    "Update any local room aliases to point to the new room": "Update any local room aliases to point to the new room",
+    "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room",
+    "Put a link back to the old room at the start of the new room so people can see old messages": "Put a link back to the old room at the start of the new room so people can see old messages",
     "Sign out": "Sign out",
     "Log out and remove encryption keys?": "Log out and remove encryption keys?",
     "Clear Storage and Sign Out": "Clear Storage and Sign Out",
@@ -1039,7 +1053,8 @@
     "Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present",
     "<showDevicesText>Show devices</showDevicesText>, <sendAnywayText>send anyway</sendAnywayText> or <cancelText>cancel</cancelText>.": "<showDevicesText>Show devices</showDevicesText>, <sendAnywayText>send anyway</sendAnywayText> or <cancelText>cancel</cancelText>.",
     "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.",
-    "Your message wasn’t sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Your message wasn’t sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.",
+    "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.": "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.",
+    "Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.": "Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.",
     "%(count)s of your messages have not been sent.|other": "Some of your messages have not been sent.",
     "%(count)s of your messages have not been sent.|one": "Your message was not sent.",
     "%(count)s <resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. You can also select individual messages to resend or cancel.|other": "<resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. You can also select individual messages to resend or cancel.",
@@ -1156,8 +1171,8 @@
     "Send Reset Email": "Send Reset Email",
     "Create an account": "Create an account",
     "This Home Server does not support login using email address.": "This Home Server does not support login using email address.",
-    "This homeserver has hit its Monthly Active User limit": "This homeserver has hit its Monthly Active User limit",
-    "Please contact your service administrator to continue using this service.": "Please contact your service administrator to continue using this service.",
+    "This server has exceeded its available resources": "This server has exceeded its available resources",
+    "Please <a>contact your service administrator</a> to continue using this service.": "Please <a>contact your service administrator</a> to continue using this service.",
     "Incorrect username and/or password.": "Incorrect username and/or password.",
     "Please note you are logging into the %(hs)s server, not matrix.org.": "Please note you are logging into the %(hs)s server, not matrix.org.",
     "Guest access is disabled on this Home Server.": "Guest access is disabled on this Home Server.",