Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 831da69

Browse files
authored
Merge pull request #3301 from matrix-org/travis/integs/base
Refactor integration manager handling into a common place
2 parents 12eeb20 + 3a4c6f3 commit 831da69

File tree

13 files changed

+275
-151
lines changed

13 files changed

+275
-151
lines changed

src/CallHandler.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ import SdkConfig from './SdkConfig';
6363
import { showUnknownDeviceDialogForCalls } from './cryptodevices';
6464
import WidgetUtils from './utils/WidgetUtils';
6565
import WidgetEchoStore from './stores/WidgetEchoStore';
66-
import ScalarAuthClient from './ScalarAuthClient';
66+
import {IntegrationManagers} from "./integrations/IntegrationManagers";
6767

6868
global.mxCalls = {
6969
//room_id: MatrixCall
@@ -348,14 +348,20 @@ async function _startCallApp(roomId, type) {
348348
// the state event in anyway, but the resulting widget would then not
349349
// work for us. Better that the user knows before everyone else in the
350350
// room sees it.
351-
const scalarClient = new ScalarAuthClient();
352-
let haveScalar = false;
353-
try {
354-
await scalarClient.connect();
355-
haveScalar = scalarClient.hasCredentials();
356-
} catch (e) {
357-
// fall through
351+
const managers = IntegrationManagers.sharedInstance();
352+
let haveScalar = true;
353+
if (managers.hasManager()) {
354+
try {
355+
const scalarClient = managers.getPrimaryManager().getScalarClient();
356+
await scalarClient.connect();
357+
haveScalar = scalarClient.hasCredentials();
358+
} catch (e) {
359+
// ignore
360+
}
361+
} else {
362+
haveScalar = false;
358363
}
364+
359365
if (!haveScalar) {
360366
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
361367

@@ -421,7 +427,8 @@ async function _startCallApp(roomId, type) {
421427
// URL, but this will at least allow the integration manager to not be hardcoded.
422428
widgetUrl = SdkConfig.get().integrations_jitsi_widget_url + '?' + queryString;
423429
} else {
424-
widgetUrl = SdkConfig.get().integrations_rest_url + '/widgets/jitsi.html?' + queryString;
430+
const apiUrl = IntegrationManagers.sharedInstance().getPrimaryManager().apiUrl;
431+
widgetUrl = apiUrl + '/widgets/jitsi.html?' + queryString;
425432
}
426433

427434
const widgetData = { widgetSessionId };

src/FromWidgetPostMessageApi.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import WidgetMessagingEndpoint from './WidgetMessagingEndpoint';
2222
import ActiveWidgetStore from './stores/ActiveWidgetStore';
2323
import MatrixClientPeg from "./MatrixClientPeg";
2424
import RoomViewStore from "./stores/RoomViewStore";
25-
import { showIntegrationsManager } from './integrations/integrations';
25+
import {IntegrationManagers} from "./integrations/IntegrationManagers";
2626

2727
const WIDGET_API_VERSION = '0.0.2'; // Current API version
2828
const SUPPORTED_WIDGET_API_VERSIONS = [
@@ -193,11 +193,12 @@ export default class FromWidgetPostMessageApi {
193193
const integType = (data && data.integType) ? data.integType : null;
194194
const integId = (data && data.integId) ? data.integId : null;
195195

196-
showIntegrationsManager({
197-
room: MatrixClientPeg.get().getRoom(RoomViewStore.getRoomId()),
198-
screen: 'type_' + integType,
199-
integrationId: integId,
200-
});
196+
// TODO: Open the right integration manager for the widget
197+
IntegrationManagers.sharedInstance().getPrimaryManager().open(
198+
MatrixClientPeg.get().getRoom(RoomViewStore.getRoomId()),
199+
`type_${integType}`,
200+
integId,
201+
);
201202
} else if (action === 'set_always_on_screen') {
202203
// This is a new message: there is no reason to support the deprecated widgetData here
203204
const data = event.data.data;

src/ScalarAuthClient.js

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,43 @@ import * as Matrix from 'matrix-js-sdk';
2929
// The version of the integration manager API we're intending to work with
3030
const imApiVersion = "1.1";
3131

32-
class ScalarAuthClient {
33-
constructor() {
32+
export default class ScalarAuthClient {
33+
constructor(apiUrl, uiUrl) {
34+
this.apiUrl = apiUrl;
35+
this.uiUrl = uiUrl;
3436
this.scalarToken = null;
3537
// `undefined` to allow `startTermsFlow` to fallback to a default
3638
// callback if this is unset.
3739
this.termsInteractionCallback = undefined;
40+
41+
// We try and store the token on a per-manager basis, but need a fallback
42+
// for the default manager.
43+
const configApiUrl = SdkConfig.get()['integrations_rest_url'];
44+
const configUiUrl = SdkConfig.get()['integrations_ui_url'];
45+
this.isDefaultManager = apiUrl === configApiUrl && configUiUrl === uiUrl;
3846
}
3947

40-
/**
41-
* Determines if setting up a ScalarAuthClient is even possible
42-
* @returns {boolean} true if possible, false otherwise.
43-
*/
44-
static isPossible() {
45-
return SdkConfig.get()['integrations_rest_url'] && SdkConfig.get()['integrations_ui_url'];
48+
_writeTokenToStore() {
49+
window.localStorage.setItem("mx_scalar_token_at_" + this.apiUrl, this.scalarToken);
50+
if (this.isDefaultManager) {
51+
// We remove the old token from storage to migrate upwards. This is safe
52+
// to do because even if the user switches to /app when this is on /develop
53+
// they'll at worst register for a new token.
54+
window.localStorage.removeItem("mx_scalar_token"); // no-op when not present
55+
}
56+
}
57+
58+
_readTokenFromStore() {
59+
let token = window.localStorage.getItem("mx_scalar_token_at_" + this.apiUrl);
60+
if (!token && this.isDefaultManager) {
61+
token = window.localStorage.getItem("mx_scalar_token");
62+
}
63+
return token;
64+
}
65+
66+
_readToken() {
67+
if (this.scalarToken) return this.scalarToken;
68+
return this._readTokenFromStore();
4669
}
4770

4871
setTermsInteractionCallback(callback) {
@@ -61,8 +84,7 @@ class ScalarAuthClient {
6184

6285
// Returns a promise that resolves to a scalar_token string
6386
getScalarToken() {
64-
let token = this.scalarToken;
65-
if (!token) token = window.localStorage.getItem("mx_scalar_token");
87+
const token = this._readToken();
6688

6789
if (!token) {
6890
return this.registerForToken();
@@ -78,7 +100,7 @@ class ScalarAuthClient {
78100
}
79101

80102
_getAccountName(token) {
81-
const url = SdkConfig.get().integrations_rest_url + "/account";
103+
const url = this.apiUrl + "/account";
82104

83105
return new Promise(function(resolve, reject) {
84106
request({
@@ -111,7 +133,7 @@ class ScalarAuthClient {
111133
return token;
112134
}).catch((e) => {
113135
if (e instanceof TermsNotSignedError) {
114-
console.log("Integrations manager requires new terms to be agreed to");
136+
console.log("Integration manager requires new terms to be agreed to");
115137
// The terms endpoints are new and so live on standard _matrix prefixes,
116138
// but IM rest urls are currently configured with paths, so remove the
117139
// path from the base URL before passing it to the js-sdk
@@ -126,7 +148,7 @@ class ScalarAuthClient {
126148
// Once we've fully transitioned to _matrix URLs, we can give people
127149
// a grace period to update their configs, then use the rest url as
128150
// a regular base url.
129-
const parsedImRestUrl = url.parse(SdkConfig.get().integrations_rest_url);
151+
const parsedImRestUrl = url.parse(this.apiUrl);
130152
parsedImRestUrl.path = '';
131153
parsedImRestUrl.pathname = '';
132154
return startTermsFlow([new Service(
@@ -147,17 +169,18 @@ class ScalarAuthClient {
147169
return MatrixClientPeg.get().getOpenIdToken().then((tokenObject) => {
148170
// Now we can send that to scalar and exchange it for a scalar token
149171
return this.exchangeForScalarToken(tokenObject);
150-
}).then((tokenObject) => {
172+
}).then((token) => {
151173
// Validate it (this mostly checks to see if the IM needs us to agree to some terms)
152-
return this._checkToken(tokenObject);
153-
}).then((tokenObject) => {
154-
window.localStorage.setItem("mx_scalar_token", tokenObject);
155-
return tokenObject;
174+
return this._checkToken(token);
175+
}).then((token) => {
176+
this.scalarToken = token;
177+
this._writeTokenToStore();
178+
return token;
156179
});
157180
}
158181

159182
exchangeForScalarToken(openidTokenObject) {
160-
const scalarRestUrl = SdkConfig.get().integrations_rest_url;
183+
const scalarRestUrl = this.apiUrl;
161184

162185
return new Promise(function(resolve, reject) {
163186
request({
@@ -181,7 +204,7 @@ class ScalarAuthClient {
181204
}
182205

183206
getScalarPageTitle(url) {
184-
let scalarPageLookupUrl = SdkConfig.get().integrations_rest_url + '/widgets/title_lookup';
207+
let scalarPageLookupUrl = this.apiUrl + '/widgets/title_lookup';
185208
scalarPageLookupUrl = this.getStarterLink(scalarPageLookupUrl);
186209
scalarPageLookupUrl += '&curl=' + encodeURIComponent(url);
187210

@@ -217,7 +240,7 @@ class ScalarAuthClient {
217240
* @return {Promise} Resolves on completion
218241
*/
219242
disableWidgetAssets(widgetType, widgetId) {
220-
let url = SdkConfig.get().integrations_rest_url + '/widgets/set_assets_state';
243+
let url = this.apiUrl + '/widgets/set_assets_state';
221244
url = this.getStarterLink(url);
222245
return new Promise((resolve, reject) => {
223246
request({
@@ -246,7 +269,7 @@ class ScalarAuthClient {
246269
getScalarInterfaceUrlForRoom(room, screen, id) {
247270
const roomId = room.roomId;
248271
const roomName = room.name;
249-
let url = SdkConfig.get().integrations_ui_url;
272+
let url = this.uiUrl;
250273
url += "?scalar_token=" + encodeURIComponent(this.scalarToken);
251274
url += "&room_id=" + encodeURIComponent(roomId);
252275
url += "&room_name=" + encodeURIComponent(roomName);
@@ -264,5 +287,3 @@ class ScalarAuthClient {
264287
return starterLinkUrl + "?scalar_token=" + encodeURIComponent(this.scalarToken);
265288
}
266289
}
267-
268-
module.exports = ScalarAuthClient;

src/ScalarMessaging.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,13 @@ Example:
232232
}
233233
*/
234234

235-
import SdkConfig from './SdkConfig';
236235
import MatrixClientPeg from './MatrixClientPeg';
237236
import { MatrixEvent } from 'matrix-js-sdk';
238237
import dis from './dispatcher';
239238
import WidgetUtils from './utils/WidgetUtils';
240239
import RoomViewStore from './stores/RoomViewStore';
241240
import { _t } from './languageHandler';
241+
import {IntegrationManagers} from "./integrations/IntegrationManagers";
242242

243243
function sendResponse(event, res) {
244244
const data = JSON.parse(JSON.stringify(event.data));
@@ -548,7 +548,8 @@ const onMessage = function(event) {
548548
// (See https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)
549549
let configUrl;
550550
try {
551-
configUrl = new URL(SdkConfig.get().integrations_ui_url);
551+
// TODO: Support multiple integration managers
552+
configUrl = new URL(IntegrationManagers.sharedInstance().getPrimaryManager().uiUrl);
552553
} catch (e) {
553554
// No integrations UI URL, ignore silently.
554555
return;

src/components/views/elements/AppTile.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import qs from 'querystring';
2222
import React from 'react';
2323
import PropTypes from 'prop-types';
2424
import MatrixClientPeg from '../../../MatrixClientPeg';
25-
import ScalarAuthClient from '../../../ScalarAuthClient';
2625
import WidgetMessaging from '../../../WidgetMessaging';
2726
import AccessibleButton from './AccessibleButton';
2827
import Modal from '../../../Modal';
@@ -35,7 +34,7 @@ import WidgetUtils from '../../../utils/WidgetUtils';
3534
import dis from '../../../dispatcher';
3635
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
3736
import classNames from 'classnames';
38-
import { showIntegrationsManager } from '../../../integrations/integrations';
37+
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
3938

4039
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
4140
const ENABLE_REACT_PERF = false;
@@ -178,9 +177,22 @@ export default class AppTile extends React.Component {
178177
return;
179178
}
180179

180+
const managers = IntegrationManagers.sharedInstance();
181+
if (!managers.hasManager()) {
182+
console.warn("No integration manager - not setting scalar token", url);
183+
this.setState({
184+
error: null,
185+
widgetUrl: this._addWurlParams(this.props.url),
186+
initialising: false,
187+
});
188+
return;
189+
}
190+
191+
// TODO: Pick the right manager for the widget
192+
181193
// Fetch the token before loading the iframe as we need it to mangle the URL
182194
if (!this._scalarClient) {
183-
this._scalarClient = new ScalarAuthClient();
195+
this._scalarClient = managers.getPrimaryManager().getScalarClient();
184196
}
185197
this._scalarClient.getScalarToken().done((token) => {
186198
// Append scalar_token as a query param if not already present
@@ -189,7 +201,7 @@ export default class AppTile extends React.Component {
189201
const params = qs.parse(u.query);
190202
if (!params.scalar_token) {
191203
params.scalar_token = encodeURIComponent(token);
192-
// u.search must be set to undefined, so that u.format() uses query paramerters - https://nodejs.org/docs/latest/api/url.html#url_url_format_url_options
204+
// u.search must be set to undefined, so that u.format() uses query parameters - https://nodejs.org/docs/latest/api/url.html#url_url_format_url_options
193205
u.search = undefined;
194206
u.query = params;
195207
}
@@ -251,11 +263,12 @@ export default class AppTile extends React.Component {
251263
if (this.props.onEditClick) {
252264
this.props.onEditClick();
253265
} else {
254-
showIntegrationsManager({
255-
room: this.props.room,
256-
screen: 'type_' + this.props.type,
257-
integrationId: this.props.id,
258-
});
266+
// TODO: Open the right manager for the widget
267+
IntegrationManagers.sharedInstance().getPrimaryManager().open(
268+
this.props.room,
269+
this.props.type,
270+
this.props.id,
271+
);
259272
}
260273
}
261274

src/components/views/elements/ManageIntegsButton.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@ limitations under the License.
1818
import React from 'react';
1919
import PropTypes from 'prop-types';
2020
import sdk from '../../../index';
21-
import ScalarAuthClient from '../../../ScalarAuthClient';
2221
import { _t } from '../../../languageHandler';
23-
import { showIntegrationsManager } from '../../../integrations/integrations';
22+
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
2423

2524
export default class ManageIntegsButton extends React.Component {
2625
constructor(props) {
@@ -30,12 +29,17 @@ export default class ManageIntegsButton extends React.Component {
3029
onManageIntegrations = (ev) => {
3130
ev.preventDefault();
3231

33-
showIntegrationsManager({ room: this.props.room });
32+
const managers = IntegrationManagers.sharedInstance();
33+
if (!managers.hasManager()) {
34+
managers.openNoManagerDialog();
35+
} else {
36+
managers.getPrimaryManager().open(this.props.room);
37+
}
3438
};
3539

3640
render() {
3741
let integrationsButton = <div />;
38-
if (ScalarAuthClient.isPossible()) {
42+
if (IntegrationManagers.sharedInstance().hasManager()) {
3943
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
4044
integrationsButton = (
4145
<AccessibleButton

src/components/views/messages/TextualBody.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import highlight from 'highlight.js';
2525
import * as HtmlUtils from '../../../HtmlUtils';
2626
import {formatDate} from '../../../DateUtils';
2727
import sdk from '../../../index';
28-
import ScalarAuthClient from '../../../ScalarAuthClient';
2928
import Modal from '../../../Modal';
3029
import SdkConfig from '../../../SdkConfig';
3130
import dis from '../../../dispatcher';
@@ -35,6 +34,7 @@ import SettingsStore from "../../../settings/SettingsStore";
3534
import ReplyThread from "../elements/ReplyThread";
3635
import {host as matrixtoHost} from '../../../matrix-to';
3736
import {pillifyLinks} from '../../../utils/pillify';
37+
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
3838

3939
module.exports = React.createClass({
4040
displayName: 'TextualBody',
@@ -318,12 +318,19 @@ module.exports = React.createClass({
318318
// which requires the user to click through and THEN we can open the link in a new tab because
319319
// the window.open command occurs in the same stack frame as the onClick callback.
320320

321+
const managers = IntegrationManagers.sharedInstance();
322+
if (!managers.hasManager()) {
323+
managers.openNoManagerDialog();
324+
return;
325+
}
326+
321327
// Go fetch a scalar token
322-
const scalarClient = new ScalarAuthClient();
328+
const integrationManager = managers.getPrimaryManager();
329+
const scalarClient = integrationManager.getScalarClient();
323330
scalarClient.connect().then(() => {
324331
const completeUrl = scalarClient.getStarterLink(starterLink);
325332
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
326-
const integrationsUrl = SdkConfig.get().integrations_ui_url;
333+
const integrationsUrl = integrationManager.uiUrl;
327334
Modal.createTrackedDialog('Add an integration', '', QuestionDialog, {
328335
title: _t("Add an Integration"),
329336
description:

0 commit comments

Comments
 (0)