mirror of https://github.com/vector-im/riot-web
Remove support for team servers
parent
2061ce2dbf
commit
20b7debcaf
|
@ -27,7 +27,6 @@ import UserActivity from './UserActivity';
|
|||
import Presence from './Presence';
|
||||
import dis from './dispatcher';
|
||||
import DMRoomMap from './utils/DMRoomMap';
|
||||
import RtsClient from './RtsClient';
|
||||
import Modal from './Modal';
|
||||
import sdk from './index';
|
||||
import ActiveWidgetStore from './stores/ActiveWidgetStore';
|
||||
|
@ -224,7 +223,7 @@ function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) {
|
|||
//
|
||||
// The plan is to gradually move the localStorage access done here into
|
||||
// SessionStore to avoid bugs where the view becomes out-of-sync with
|
||||
// localStorage (e.g. teamToken, isGuest etc.)
|
||||
// localStorage (e.g. isGuest etc.)
|
||||
async function _restoreFromLocalStorage() {
|
||||
if (!localStorage) {
|
||||
return false;
|
||||
|
@ -286,15 +285,6 @@ function _handleLoadSessionFailure(e) {
|
|||
});
|
||||
}
|
||||
|
||||
let rtsClient = null;
|
||||
export function initRtsClient(url) {
|
||||
if (url) {
|
||||
rtsClient = new RtsClient(url);
|
||||
} else {
|
||||
rtsClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transitions to a logged-in state using the given credentials.
|
||||
*
|
||||
|
@ -333,7 +323,7 @@ async function _doSetLoggedIn(credentials, clearStorage) {
|
|||
);
|
||||
|
||||
// This is dispatched to indicate that the user is still in the process of logging in
|
||||
// because `teamPromise` may take some time to resolve, breaking the assumption that
|
||||
// because async code may take some time to resolve, breaking the assumption that
|
||||
// `setLoggedIn` takes an "instant" to complete, and dispatch `on_logged_in` a few ms
|
||||
// later than MatrixChat might assume.
|
||||
//
|
||||
|
@ -347,10 +337,6 @@ async function _doSetLoggedIn(credentials, clearStorage) {
|
|||
|
||||
Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl, credentials.identityServerUrl);
|
||||
|
||||
// Resolves by default
|
||||
let teamPromise = Promise.resolve(null);
|
||||
|
||||
|
||||
if (localStorage) {
|
||||
try {
|
||||
_persistCredentialsToLocalStorage(credentials);
|
||||
|
@ -367,27 +353,13 @@ async function _doSetLoggedIn(credentials, clearStorage) {
|
|||
} catch (e) {
|
||||
console.warn("Error using local storage: can't persist session!", e);
|
||||
}
|
||||
|
||||
if (rtsClient && !credentials.guest) {
|
||||
teamPromise = rtsClient.login(credentials.userId).then((body) => {
|
||||
if (body.team_token) {
|
||||
localStorage.setItem("mx_team_token", body.team_token);
|
||||
}
|
||||
return body.team_token;
|
||||
}, (err) => {
|
||||
console.warn(`Failed to get team token on login: ${err}` );
|
||||
return null;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.warn("No local storage available: can't persist session!");
|
||||
}
|
||||
|
||||
MatrixClientPeg.replaceUsingCreds(credentials);
|
||||
|
||||
teamPromise.then((teamToken) => {
|
||||
dis.dispatch({action: 'on_logged_in', teamToken: teamToken});
|
||||
});
|
||||
dis.dispatch({ action: 'on_logged_in' });
|
||||
|
||||
await startMatrixClient();
|
||||
return MatrixClientPeg.get();
|
||||
|
|
104
src/RtsClient.js
104
src/RtsClient.js
|
@ -1,104 +0,0 @@
|
|||
import 'whatwg-fetch';
|
||||
|
||||
let fetchFunction = fetch;
|
||||
|
||||
function checkStatus(response) {
|
||||
if (!response.ok) {
|
||||
return response.text().then((text) => {
|
||||
throw new Error(text);
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
function parseJson(response) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
function encodeQueryParams(params) {
|
||||
return '?' + Object.keys(params).map((k) => {
|
||||
return k + '=' + encodeURIComponent(params[k]);
|
||||
}).join('&');
|
||||
}
|
||||
|
||||
const request = (url, opts) => {
|
||||
if (opts && opts.qs) {
|
||||
url += encodeQueryParams(opts.qs);
|
||||
delete opts.qs;
|
||||
}
|
||||
if (opts && opts.body) {
|
||||
if (!opts.headers) {
|
||||
opts.headers = {};
|
||||
}
|
||||
opts.body = JSON.stringify(opts.body);
|
||||
opts.headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
return fetchFunction(url, opts)
|
||||
.then(checkStatus)
|
||||
.then(parseJson);
|
||||
};
|
||||
|
||||
|
||||
export default class RtsClient {
|
||||
constructor(url) {
|
||||
this._url = url;
|
||||
}
|
||||
|
||||
getTeamsConfig() {
|
||||
return request(this._url + '/teams');
|
||||
}
|
||||
|
||||
/**
|
||||
* Track a referral with the Riot Team Server. This should be called once a referred
|
||||
* user has been successfully registered.
|
||||
* @param {string} referrer the user ID of one who referred the user to Riot.
|
||||
* @param {string} sid the sign-up identity server session ID .
|
||||
* @param {string} clientSecret the sign-up client secret.
|
||||
* @returns {Promise} a promise that resolves to { team_token: 'sometoken' } upon
|
||||
* success.
|
||||
*/
|
||||
trackReferral(referrer, sid, clientSecret) {
|
||||
return request(this._url + '/register',
|
||||
{
|
||||
body: {
|
||||
referrer: referrer,
|
||||
session_id: sid,
|
||||
client_secret: clientSecret,
|
||||
},
|
||||
method: 'POST',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
getTeam(teamToken) {
|
||||
return request(this._url + '/teamConfiguration',
|
||||
{
|
||||
qs: {
|
||||
team_token: teamToken,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal to the RTS that a login has occurred and that a user requires their team's
|
||||
* token.
|
||||
* @param {string} userId the user ID of the user who is a member of a team.
|
||||
* @returns {Promise} a promise that resolves to { team_token: 'sometoken' } upon
|
||||
* success.
|
||||
*/
|
||||
login(userId) {
|
||||
return request(this._url + '/login',
|
||||
{
|
||||
qs: {
|
||||
user_id: userId,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// allow fetch to be replaced, for testing.
|
||||
static setFetch(fn) {
|
||||
fetchFunction = fn;
|
||||
}
|
||||
}
|
|
@ -30,11 +30,6 @@ class HomePage extends React.Component {
|
|||
static displayName = 'HomePage';
|
||||
|
||||
static propTypes = {
|
||||
// URL base of the team server. Optional.
|
||||
teamServerUrl: PropTypes.string,
|
||||
// Team token. Optional. If set, used to get the static homepage of the team
|
||||
// associated. If unset, homePageUrl will be used.
|
||||
teamToken: PropTypes.string,
|
||||
// URL to use as the iFrame src. Defaults to /home.html.
|
||||
homePageUrl: PropTypes.string,
|
||||
};
|
||||
|
@ -56,35 +51,29 @@ class HomePage extends React.Component {
|
|||
componentWillMount() {
|
||||
this._unmounted = false;
|
||||
|
||||
if (this.props.teamToken && this.props.teamServerUrl) {
|
||||
this.setState({
|
||||
iframeSrc: `${this.props.teamServerUrl}/static/${this.props.teamToken}/home.html`,
|
||||
});
|
||||
} else {
|
||||
// we use request() to inline the homepage into the react component
|
||||
// so that it can inherit CSS and theming easily rather than mess around
|
||||
// with iframes and trying to synchronise document.stylesheets.
|
||||
// we use request() to inline the homepage into the react component
|
||||
// so that it can inherit CSS and theming easily rather than mess around
|
||||
// with iframes and trying to synchronise document.stylesheets.
|
||||
|
||||
const src = this.props.homePageUrl || 'home.html';
|
||||
const src = this.props.homePageUrl || 'home.html';
|
||||
|
||||
request(
|
||||
{ method: "GET", url: src },
|
||||
(err, response, body) => {
|
||||
if (this._unmounted) {
|
||||
return;
|
||||
}
|
||||
request(
|
||||
{ method: "GET", url: src },
|
||||
(err, response, body) => {
|
||||
if (this._unmounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (err || response.status < 200 || response.status >= 300) {
|
||||
console.warn(`Error loading home page: ${err}`);
|
||||
this.setState({ page: _t("Couldn't load home page") });
|
||||
return;
|
||||
}
|
||||
if (err || response.status < 200 || response.status >= 300) {
|
||||
console.warn(`Error loading home page: ${err}`);
|
||||
this.setState({ page: _t("Couldn't load home page") });
|
||||
return;
|
||||
}
|
||||
|
||||
body = body.replace(/_t\(['"]([\s\S]*?)['"]\)/mg, (match, g1)=>this.translate(g1));
|
||||
this.setState({ page: body });
|
||||
},
|
||||
);
|
||||
}
|
||||
body = body.replace(/_t\(['"]([\s\S]*?)['"]\)/mg, (match, g1)=>this.translate(g1));
|
||||
this.setState({ page: body });
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
|
|
@ -63,7 +63,6 @@ const LoggedInView = React.createClass({
|
|||
// transitioned to PWLU)
|
||||
onRegistered: PropTypes.func,
|
||||
collapsedRhs: PropTypes.bool,
|
||||
teamToken: PropTypes.string,
|
||||
|
||||
// Used by the RoomView to handle joining rooms
|
||||
viaServers: PropTypes.arrayOf(PropTypes.string),
|
||||
|
@ -457,8 +456,6 @@ const LoggedInView = React.createClass({
|
|||
pageElement = <UserSettings
|
||||
onClose={this.props.onCloseAllSettings}
|
||||
brand={this.props.config.brand}
|
||||
referralBaseUrl={this.props.config.referralBaseUrl}
|
||||
teamToken={this.props.teamToken}
|
||||
/>;
|
||||
break;
|
||||
|
||||
|
@ -475,15 +472,7 @@ const LoggedInView = React.createClass({
|
|||
|
||||
case PageTypes.HomePage:
|
||||
{
|
||||
// If team server config is present, pass the teamServerURL. props.teamToken
|
||||
// must also be set for the team page to be displayed, otherwise the
|
||||
// welcomePageUrl is used (which might be undefined).
|
||||
const teamServerUrl = this.props.config.teamServerConfig ?
|
||||
this.props.config.teamServerConfig.teamServerURL : null;
|
||||
|
||||
pageElement = <HomePage
|
||||
teamServerUrl={teamServerUrl}
|
||||
teamToken={this.props.teamToken}
|
||||
homePageUrl={this.props.config.welcomePageUrl}
|
||||
/>;
|
||||
}
|
||||
|
|
|
@ -75,8 +75,8 @@ const VIEWS = {
|
|||
// we have valid matrix credentials (either via an explicit login, via the
|
||||
// initial re-animation/guest registration, or via a registration), and are
|
||||
// now setting up a matrixclient to talk to it. This isn't an instant
|
||||
// process because (a) we need to clear out indexeddb, and (b) we need to
|
||||
// talk to the team server; while it is going on we show a big spinner.
|
||||
// process because we need to clear out indexeddb. While it is going on we
|
||||
// show a big spinner.
|
||||
LOGGING_IN: 5,
|
||||
|
||||
// we are logged in with an active matrix client.
|
||||
|
@ -256,42 +256,6 @@ export default React.createClass({
|
|||
MatrixClientPeg.opts.initialSyncLimit = this.props.config.sync_timeline_limit;
|
||||
}
|
||||
|
||||
// To enable things like riot.im/geektime in a nicer way than rewriting the URL
|
||||
// and appending a team token query parameter, use the first path segment to
|
||||
// indicate a team, with "public" team tokens stored in the config teamTokenMap.
|
||||
let routedTeamToken = null;
|
||||
if (this.props.config.teamTokenMap) {
|
||||
const teamName = window.location.pathname.split('/')[1];
|
||||
if (teamName && this.props.config.teamTokenMap.hasOwnProperty(teamName)) {
|
||||
routedTeamToken = this.props.config.teamTokenMap[teamName];
|
||||
}
|
||||
}
|
||||
|
||||
// Persist the team token across refreshes using sessionStorage. A new window or
|
||||
// tab will not persist sessionStorage, but refreshes will.
|
||||
if (this.props.startingFragmentQueryParams.team_token) {
|
||||
window.sessionStorage.setItem(
|
||||
'mx_team_token',
|
||||
this.props.startingFragmentQueryParams.team_token,
|
||||
);
|
||||
}
|
||||
|
||||
// Use the locally-stored team token first, then as a fall-back, check to see if
|
||||
// a referral link was used, which will contain a query parameter `team_token`.
|
||||
this._teamToken = routedTeamToken ||
|
||||
window.localStorage.getItem('mx_team_token') ||
|
||||
window.sessionStorage.getItem('mx_team_token');
|
||||
|
||||
// Some users have ended up with "undefined" as their local storage team token,
|
||||
// treat that as undefined.
|
||||
if (this._teamToken === "undefined") {
|
||||
this._teamToken = undefined;
|
||||
}
|
||||
|
||||
if (this._teamToken) {
|
||||
console.info(`Team token set to ${this._teamToken}`);
|
||||
}
|
||||
|
||||
// Set up the default URLs (async)
|
||||
if (this.getDefaultServerName() && !this.getDefaultHsUrl(false)) {
|
||||
this.setState({loadingDefaultHomeserver: true});
|
||||
|
@ -360,9 +324,6 @@ export default React.createClass({
|
|||
linkifyMatrix.onGroupClick = this.onGroupClick;
|
||||
}
|
||||
|
||||
const teamServerConfig = this.props.config.teamServerConfig || {};
|
||||
Lifecycle.initRtsClient(teamServerConfig.teamServerURL);
|
||||
|
||||
// the first thing to do is to try the token params in the query-string
|
||||
Lifecycle.attemptTokenLogin(this.props.realQueryParams).then((loggedIn) => {
|
||||
if (loggedIn) {
|
||||
|
@ -726,7 +687,7 @@ export default React.createClass({
|
|||
});
|
||||
break;
|
||||
case 'on_logged_in':
|
||||
this._onLoggedIn(payload.teamToken);
|
||||
this._onLoggedIn();
|
||||
break;
|
||||
case 'on_logged_out':
|
||||
this._onLoggedOut();
|
||||
|
@ -1196,16 +1157,10 @@ export default React.createClass({
|
|||
|
||||
/**
|
||||
* Called when a new logged in session has started
|
||||
*
|
||||
* @param {string} teamToken
|
||||
*/
|
||||
_onLoggedIn: async function(teamToken) {
|
||||
_onLoggedIn: async function() {
|
||||
this.setStateForNewView({view: VIEWS.LOGGED_IN});
|
||||
if (teamToken) {
|
||||
// A team member has logged in, not a guest
|
||||
this._teamToken = teamToken;
|
||||
dis.dispatch({action: 'view_home_page'});
|
||||
} else if (this._is_registered) {
|
||||
if (this._is_registered) {
|
||||
this._is_registered = false;
|
||||
|
||||
if (this.props.config.welcomeUserId && getCurrentLanguage().startsWith("en")) {
|
||||
|
@ -1261,7 +1216,6 @@ export default React.createClass({
|
|||
currentRoomId: null,
|
||||
page_type: PageTypes.RoomDirectory,
|
||||
});
|
||||
this._teamToken = null;
|
||||
this._setPageSubtitle();
|
||||
},
|
||||
|
||||
|
@ -1707,15 +1661,13 @@ export default React.createClass({
|
|||
|
||||
onReturnToAppClick: function() {
|
||||
// treat it the same as if the user had completed the login
|
||||
this._onLoggedIn(null);
|
||||
this._onLoggedIn();
|
||||
},
|
||||
|
||||
// returns a promise which resolves to the new MatrixClient
|
||||
onRegistered: function(credentials, teamToken) {
|
||||
// XXX: These both should be in state or ideally store(s) because we risk not
|
||||
onRegistered: function(credentials) {
|
||||
// XXX: This should be in state or ideally store(s) because we risk not
|
||||
// rendering the most up-to-date view of state otherwise.
|
||||
// teamToken may not be truthy
|
||||
this._teamToken = teamToken;
|
||||
this._is_registered = true;
|
||||
return Lifecycle.setLoggedIn(credentials);
|
||||
},
|
||||
|
@ -1888,7 +1840,6 @@ export default React.createClass({
|
|||
onCloseAllSettings={this.onCloseAllSettings}
|
||||
onRegistered={this.onRegistered}
|
||||
currentRoomId={this.state.currentRoomId}
|
||||
teamToken={this._teamToken}
|
||||
showCookieBar={this.state.showCookieBar}
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
|
@ -1929,7 +1880,6 @@ export default React.createClass({
|
|||
defaultHsUrl={this.getDefaultHsUrl()}
|
||||
defaultIsUrl={this.getDefaultIsUrl()}
|
||||
brand={this.props.config.brand}
|
||||
teamServerConfig={this.props.config.teamServerConfig}
|
||||
customHsUrl={this.getCurrentHsUrl()}
|
||||
customIsUrl={this.getCurrentIsUrl()}
|
||||
makeRegistrationUrl={this._makeRegistrationUrl}
|
||||
|
|
|
@ -167,13 +167,6 @@ module.exports = React.createClass({
|
|||
onClose: PropTypes.func,
|
||||
// The brand string given when creating email pushers
|
||||
brand: PropTypes.string,
|
||||
|
||||
// The base URL to use in the referral link. Defaults to window.location.origin.
|
||||
referralBaseUrl: PropTypes.string,
|
||||
|
||||
// Team token for the referral link. If falsy, the referral section will
|
||||
// not appear
|
||||
teamToken: PropTypes.string,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
|
@ -590,27 +583,6 @@ module.exports = React.createClass({
|
|||
return <GroupUserSettings />;
|
||||
},
|
||||
|
||||
_renderReferral: function() {
|
||||
const teamToken = this.props.teamToken;
|
||||
if (!teamToken) {
|
||||
return null;
|
||||
}
|
||||
if (typeof teamToken !== 'string') {
|
||||
console.warn('Team token not a string');
|
||||
return null;
|
||||
}
|
||||
const href = (this.props.referralBaseUrl || window.location.origin) +
|
||||
`/#/register?referrer=${this._me}&team_token=${teamToken}`;
|
||||
return (
|
||||
<div>
|
||||
<h3>Referral</h3>
|
||||
<div className="mx_UserSettings_section">
|
||||
{ _t("Refer a friend to Riot:") } <a href={href} target="_blank" rel="noopener">{ href }</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
onLanguageChange: function(newLang) {
|
||||
if (this.state.language !== newLang) {
|
||||
SettingsStore.setValue("language", null, SettingLevel.DEVICE, newLang);
|
||||
|
@ -1355,8 +1327,6 @@ module.exports = React.createClass({
|
|||
|
||||
{ this._renderGroupSettings() }
|
||||
|
||||
{ this._renderReferral() }
|
||||
|
||||
{ notificationArea }
|
||||
|
||||
{ this._renderUserInterfaceSettings() }
|
||||
|
|
|
@ -23,9 +23,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
import sdk from '../../../index';
|
||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||
import RegistrationForm from '../../views/auth/RegistrationForm';
|
||||
import RtsClient from '../../../RtsClient';
|
||||
import { _t, _td } from '../../../languageHandler';
|
||||
import SdkConfig from '../../../SdkConfig';
|
||||
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
|
||||
|
@ -48,13 +46,6 @@ module.exports = React.createClass({
|
|||
brand: PropTypes.string,
|
||||
email: PropTypes.string,
|
||||
referrer: PropTypes.string,
|
||||
teamServerConfig: PropTypes.shape({
|
||||
// Email address to request new teams
|
||||
supportEmail: PropTypes.string.isRequired,
|
||||
// URL of the riot-team-server to get team configurations and track referrals
|
||||
teamServerURL: PropTypes.string.isRequired,
|
||||
}),
|
||||
teamSelected: PropTypes.object,
|
||||
|
||||
// The default server name to use when the user hasn't specified
|
||||
// one. This is used when displaying the defaultHsUrl in the UI.
|
||||
|
@ -70,18 +61,11 @@ module.exports = React.createClass({
|
|||
onLoginClick: PropTypes.func.isRequired,
|
||||
onCancelClick: PropTypes.func,
|
||||
onServerConfigChange: PropTypes.func.isRequired,
|
||||
|
||||
rtsClient: PropTypes.shape({
|
||||
getTeamsConfig: PropTypes.func.isRequired,
|
||||
trackReferral: PropTypes.func.isRequired,
|
||||
getTeam: PropTypes.func.isRequired,
|
||||
}),
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
busy: false,
|
||||
teamServerBusy: false,
|
||||
errorText: null,
|
||||
// We remember the values entered by the user because
|
||||
// the registration form will be unmounted during the
|
||||
|
@ -106,37 +90,7 @@ module.exports = React.createClass({
|
|||
|
||||
componentWillMount: function() {
|
||||
this._unmounted = false;
|
||||
|
||||
this._replaceClient();
|
||||
|
||||
if (
|
||||
this.props.teamServerConfig &&
|
||||
this.props.teamServerConfig.teamServerURL &&
|
||||
!this._rtsClient
|
||||
) {
|
||||
this._rtsClient = this.props.rtsClient || new RtsClient(this.props.teamServerConfig.teamServerURL);
|
||||
|
||||
this.setState({
|
||||
teamServerBusy: true,
|
||||
});
|
||||
// GET team configurations including domains, names and icons
|
||||
this._rtsClient.getTeamsConfig().then((data) => {
|
||||
const teamsConfig = {
|
||||
teams: data,
|
||||
supportEmail: this.props.teamServerConfig.supportEmail,
|
||||
};
|
||||
console.log('Setting teams config to ', teamsConfig);
|
||||
this.setState({
|
||||
teamsConfig: teamsConfig,
|
||||
teamServerBusy: false,
|
||||
});
|
||||
}, (err) => {
|
||||
console.error('Error retrieving config for teams', err);
|
||||
this.setState({
|
||||
teamServerBusy: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onServerConfigChange: function(config) {
|
||||
|
@ -191,7 +145,7 @@ module.exports = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
_onUIAuthFinished: function(success, response, extra) {
|
||||
_onUIAuthFinished: async function(success, response, extra) {
|
||||
if (!success) {
|
||||
let msg = response.message || response.toString();
|
||||
// can we give a better error message?
|
||||
|
@ -240,58 +194,15 @@ module.exports = React.createClass({
|
|||
doingUIAuth: false,
|
||||
});
|
||||
|
||||
// Done regardless of `teamSelected`. People registering with non-team emails
|
||||
// will just nop. The point of this being we might not have the email address
|
||||
// that the user registered with at this stage (depending on whether this
|
||||
// is the client they initiated registration).
|
||||
let trackPromise = Promise.resolve(null);
|
||||
if (this._rtsClient && extra.emailSid) {
|
||||
// Track referral if this.props.referrer set, get team_token in order to
|
||||
// retrieve team config and see welcome page etc.
|
||||
trackPromise = this._rtsClient.trackReferral(
|
||||
this.props.referrer || '', // Default to empty string = not referred
|
||||
extra.emailSid,
|
||||
extra.clientSecret,
|
||||
).then((data) => {
|
||||
const teamToken = data.team_token;
|
||||
// Store for use /w welcome pages
|
||||
window.localStorage.setItem('mx_team_token', teamToken);
|
||||
|
||||
this._rtsClient.getTeam(teamToken).then((team) => {
|
||||
console.log(
|
||||
`User successfully registered with team ${team.name}`,
|
||||
);
|
||||
if (!team.rooms) {
|
||||
return;
|
||||
}
|
||||
// Auto-join rooms
|
||||
team.rooms.forEach((room) => {
|
||||
if (room.auto_join && room.room_id) {
|
||||
console.log(`Auto-joining ${room.room_id}`);
|
||||
MatrixClientPeg.get().joinRoom(room.room_id);
|
||||
}
|
||||
});
|
||||
}, (err) => {
|
||||
console.error('Error getting team config', err);
|
||||
});
|
||||
|
||||
return teamToken;
|
||||
}, (err) => {
|
||||
console.error('Error tracking referral', err);
|
||||
});
|
||||
}
|
||||
|
||||
trackPromise.then((teamToken) => {
|
||||
return this.props.onLoggedIn({
|
||||
userId: response.user_id,
|
||||
deviceId: response.device_id,
|
||||
homeserverUrl: this._matrixClient.getHomeserverUrl(),
|
||||
identityServerUrl: this._matrixClient.getIdentityServerUrl(),
|
||||
accessToken: response.access_token,
|
||||
}, teamToken);
|
||||
}).then((cli) => {
|
||||
return this._setupPushers(cli);
|
||||
const cli = await this.props.onLoggedIn({
|
||||
userId: response.user_id,
|
||||
deviceId: response.device_id,
|
||||
homeserverUrl: this._matrixClient.getHomeserverUrl(),
|
||||
identityServerUrl: this._matrixClient.getIdentityServerUrl(),
|
||||
accessToken: response.access_token,
|
||||
});
|
||||
|
||||
this._setupPushers(cli);
|
||||
},
|
||||
|
||||
_setupPushers: function(matrixClient) {
|
||||
|
@ -356,12 +267,6 @@ module.exports = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
onTeamSelected: function(teamSelected) {
|
||||
if (!this._unmounted) {
|
||||
this.setState({ teamSelected });
|
||||
}
|
||||
},
|
||||
|
||||
onLoginClick: function(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
@ -418,7 +323,7 @@ module.exports = React.createClass({
|
|||
poll={true}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.busy || this.state.teamServerBusy || !this.state.flows) {
|
||||
} else if (this.state.busy || !this.state.flows) {
|
||||
registerBody = <Spinner />;
|
||||
} else {
|
||||
let serverConfigSection;
|
||||
|
@ -443,11 +348,9 @@ module.exports = React.createClass({
|
|||
defaultPhoneCountry={this.state.formVals.phoneCountry}
|
||||
defaultPhoneNumber={this.state.formVals.phoneNumber}
|
||||
defaultPassword={this.state.formVals.password}
|
||||
teamsConfig={this.state.teamsConfig}
|
||||
minPasswordLength={MIN_PASSWORD_LENGTH}
|
||||
onError={this.onFormValidationFailed}
|
||||
onRegisterClick={this.onFormSubmit}
|
||||
onTeamSelected={this.onTeamSelected}
|
||||
flows={this.state.flows}
|
||||
/>
|
||||
{ serverConfigSection }
|
||||
|
@ -472,12 +375,7 @@ module.exports = React.createClass({
|
|||
|
||||
return (
|
||||
<AuthPage>
|
||||
<AuthHeader
|
||||
icon={this.state.teamSelected ?
|
||||
this.props.teamServerConfig.teamServerURL + "/static/common/" +
|
||||
this.state.teamSelected.domain + "/icon.png" :
|
||||
null}
|
||||
/>
|
||||
<AuthHeader />
|
||||
<AuthBody>
|
||||
<h2>{ _t('Create your account') }</h2>
|
||||
{ registerBody }
|
||||
|
|
|
@ -46,17 +46,6 @@ module.exports = React.createClass({
|
|||
defaultPhoneNumber: PropTypes.string,
|
||||
defaultUsername: PropTypes.string,
|
||||
defaultPassword: PropTypes.string,
|
||||
teamsConfig: PropTypes.shape({
|
||||
// Email address to request new teams
|
||||
supportEmail: PropTypes.string,
|
||||
teams: PropTypes.arrayOf(PropTypes.shape({
|
||||
// The displayed name of the team
|
||||
"name": PropTypes.string,
|
||||
// The domain of team email addresses
|
||||
"domain": PropTypes.string,
|
||||
})).required,
|
||||
}),
|
||||
|
||||
minPasswordLength: PropTypes.number,
|
||||
onError: PropTypes.func,
|
||||
onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise
|
||||
|
@ -75,7 +64,6 @@ module.exports = React.createClass({
|
|||
getInitialState: function() {
|
||||
return {
|
||||
fieldValid: {},
|
||||
selectedTeam: null,
|
||||
// The ISO2 country code selected in the phone number entry
|
||||
phoneCountry: this.props.defaultPhoneCountry,
|
||||
};
|
||||
|
@ -150,10 +138,6 @@ module.exports = React.createClass({
|
|||
return true;
|
||||
},
|
||||
|
||||
_isUniEmail: function(email) {
|
||||
return email.endsWith('.ac.uk') || email.endsWith('.edu') || email.endsWith('matrix.org');
|
||||
},
|
||||
|
||||
validateField: function(fieldID) {
|
||||
const pwd1 = this.refs.password.value.trim();
|
||||
const pwd2 = this.refs.passwordConfirm.value.trim();
|
||||
|
@ -161,24 +145,6 @@ module.exports = React.createClass({
|
|||
switch (fieldID) {
|
||||
case FIELD_EMAIL: {
|
||||
const email = this.refs.email.value;
|
||||
if (this.props.teamsConfig && this._isUniEmail(email)) {
|
||||
const matchingTeam = this.props.teamsConfig.teams.find(
|
||||
(team) => {
|
||||
return email.split('@').pop() === team.domain;
|
||||
},
|
||||
) || null;
|
||||
this.setState({
|
||||
selectedTeam: matchingTeam,
|
||||
showSupportEmail: !matchingTeam,
|
||||
});
|
||||
this.props.onTeamSelected(matchingTeam);
|
||||
} else {
|
||||
this.props.onTeamSelected(null);
|
||||
this.setState({
|
||||
selectedTeam: null,
|
||||
showSupportEmail: false,
|
||||
});
|
||||
}
|
||||
const emailValid = email === '' || Email.looksValid(email);
|
||||
if (this._authStepIsRequired('m.login.email.identity') && (!emailValid || email === '')) {
|
||||
this.markFieldValid(fieldID, false, "RegistrationForm.ERR_MISSING_EMAIL");
|
||||
|
@ -304,30 +270,6 @@ module.exports = React.createClass({
|
|||
value={self.state.email} />
|
||||
</div>
|
||||
);
|
||||
let belowEmailSection;
|
||||
if (this.props.teamsConfig) {
|
||||
if (this.props.teamsConfig.supportEmail && this.state.showSupportEmail) {
|
||||
belowEmailSection = (
|
||||
<p className="mx_Login_support">
|
||||
Sorry, but your university is not registered with us just yet.
|
||||
Email us on
|
||||
<a href={"mailto:" + this.props.teamsConfig.supportEmail}>
|
||||
{ this.props.teamsConfig.supportEmail }
|
||||
</a>
|
||||
to get your university signed up.
|
||||
Or continue to register with Riot to enjoy our open source platform.
|
||||
</p>
|
||||
);
|
||||
} else if (this.state.selectedTeam) {
|
||||
belowEmailSection = (
|
||||
<p className="mx_Login_support">
|
||||
{_t("You are registering with %(SelectedTeamName)s", {
|
||||
SelectedTeamName: this.state.selectedTeam.name,
|
||||
})}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown');
|
||||
let phoneSection;
|
||||
|
@ -369,7 +311,6 @@ module.exports = React.createClass({
|
|||
<div>
|
||||
<form onSubmit={this.onSubmit}>
|
||||
{ emailSection }
|
||||
{ belowEmailSection }
|
||||
{ phoneSection }
|
||||
<input type="text" ref="username"
|
||||
placeholder={placeholderUserName} defaultValue={this.props.defaultUsername}
|
||||
|
|
|
@ -193,9 +193,6 @@ export default React.createClass({
|
|||
return;
|
||||
}
|
||||
|
||||
// XXX Implement RTS /register here
|
||||
const teamToken = null;
|
||||
|
||||
this.props.onFinished(true, {
|
||||
userId: response.user_id,
|
||||
deviceId: response.device_id,
|
||||
|
@ -203,7 +200,6 @@ export default React.createClass({
|
|||
identityServerUrl: this._matrixClient.getIdentityServerUrl(),
|
||||
accessToken: response.access_token,
|
||||
password: this._generatedPassword,
|
||||
teamToken: teamToken,
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import Skinner from './Skinner';
|
||||
import RtsClient from './RtsClient';
|
||||
|
||||
module.exports.loadSkin = function(skinObject) {
|
||||
Skinner.load(skinObject);
|
||||
|
@ -28,7 +27,3 @@ module.exports.resetSkin = function() {
|
|||
module.exports.getComponent = function(componentName) {
|
||||
return Skinner.getComponent(componentName);
|
||||
};
|
||||
|
||||
module.exports.setFetch = function(fetchFunction) {
|
||||
RtsClient.setFetch(fetchFunction);
|
||||
};
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const jest = require('jest-mock');
|
||||
const React = require('react');
|
||||
const ReactTestUtils = require('react-addons-test-utils');
|
||||
const expect = require('expect');
|
||||
|
||||
const testUtils = require('test-utils');
|
||||
|
||||
const sdk = require('matrix-react-sdk');
|
||||
const Registration = sdk.getComponent('structures.auth.Registration');
|
||||
|
||||
let rtsClient;
|
||||
let client;
|
||||
|
||||
const TEAM_CONFIG = {
|
||||
supportEmail: 'support@some.domain',
|
||||
teamServerURL: 'http://someteamserver.bla',
|
||||
};
|
||||
|
||||
const CREDENTIALS = {userId: '@me:here'};
|
||||
const MOCK_REG_RESPONSE = {
|
||||
user_id: CREDENTIALS.userId,
|
||||
device_id: 'mydevice',
|
||||
access_token: '2234569864534231',
|
||||
};
|
||||
|
||||
describe('Registration', function() {
|
||||
beforeEach(function() {
|
||||
testUtils.beforeEach(this);
|
||||
client = testUtils.createTestClient();
|
||||
client.credentials = CREDENTIALS;
|
||||
|
||||
// Mock an RTS client that supports one team and naively returns team tokens when
|
||||
// tracking by mapping email SIDs to team tokens. This is fine because we only
|
||||
// want to assert the client behaviour such that a user recognised by the
|
||||
// rtsClient (which would normally talk to the RTS server) as a team member is
|
||||
// correctly logged in as one (and other such assertions).
|
||||
rtsClient = testUtils.createTestRtsClient(
|
||||
{
|
||||
'myawesometeam123': {
|
||||
name: 'Team Awesome',
|
||||
domain: 'team.awesome.net',
|
||||
},
|
||||
},
|
||||
{'someEmailSid1234': 'myawesometeam123'},
|
||||
);
|
||||
});
|
||||
|
||||
it('should track a referral following successful registration of a team member', function(done) {
|
||||
const expectedCreds = {
|
||||
userId: MOCK_REG_RESPONSE.user_id,
|
||||
deviceId: MOCK_REG_RESPONSE.device_id,
|
||||
homeserverUrl: client.getHomeserverUrl(),
|
||||
identityServerUrl: client.getIdentityServerUrl(),
|
||||
accessToken: MOCK_REG_RESPONSE.access_token,
|
||||
};
|
||||
const onLoggedIn = function(creds, teamToken) {
|
||||
expect(creds).toEqual(expectedCreds);
|
||||
expect(teamToken).toBe('myawesometeam123');
|
||||
done();
|
||||
};
|
||||
|
||||
const res = ReactTestUtils.renderIntoDocument(
|
||||
<Registration
|
||||
teamServerConfig={TEAM_CONFIG}
|
||||
onLoggedIn={onLoggedIn}
|
||||
rtsClient={rtsClient}
|
||||
/>,
|
||||
);
|
||||
|
||||
res._onUIAuthFinished(true, MOCK_REG_RESPONSE, {emailSid: 'someEmailSid1234'});
|
||||
});
|
||||
|
||||
it('should NOT track a referral following successful registration of a non-team member', function(done) {
|
||||
const onLoggedIn = jest.fn(function(creds, teamToken) {
|
||||
expect(teamToken).toBeFalsy();
|
||||
done();
|
||||
});
|
||||
|
||||
const res = ReactTestUtils.renderIntoDocument(
|
||||
<Registration
|
||||
teamServerConfig={TEAM_CONFIG}
|
||||
onLoggedIn={onLoggedIn}
|
||||
rtsClient={rtsClient}
|
||||
/>,
|
||||
);
|
||||
|
||||
res._onUIAuthFinished(true, MOCK_REG_RESPONSE, {emailSid: 'someOtherEmailSid11'});
|
||||
});
|
||||
});
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const jest = require('jest-mock');
|
||||
const React = require('react');
|
||||
const ReactTestUtils = require('react-addons-test-utils');
|
||||
const expect = require('expect');
|
||||
|
||||
const testUtils = require('test-utils');
|
||||
|
||||
const sdk = require('matrix-react-sdk');
|
||||
const RegistrationForm = sdk.getComponent('views.auth.RegistrationForm');
|
||||
|
||||
const TEAM_CONFIG = {
|
||||
supportEmail: "support@some.domain",
|
||||
teams: [
|
||||
{ name: "The Team Org.", domain: "team.ac.uk" },
|
||||
{ name: "The Super Team", domain: "superteam.ac.uk" },
|
||||
],
|
||||
};
|
||||
|
||||
function doInputEmail(inputEmail, onTeamSelected) {
|
||||
const res = ReactTestUtils.renderIntoDocument(
|
||||
<RegistrationForm
|
||||
teamsConfig={TEAM_CONFIG}
|
||||
onTeamSelected={onTeamSelected}
|
||||
flows={[
|
||||
{
|
||||
stages: ['m.login.dummy'],
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
const teamInput = res.refs.email;
|
||||
teamInput.value = inputEmail;
|
||||
|
||||
ReactTestUtils.Simulate.change(teamInput);
|
||||
ReactTestUtils.Simulate.blur(teamInput);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function expectTeamSelectedFromEmailInput(inputEmail, expectedTeam) {
|
||||
const onTeamSelected = jest.fn();
|
||||
doInputEmail(inputEmail, onTeamSelected);
|
||||
|
||||
expect(onTeamSelected).toHaveBeenCalledWith(expectedTeam);
|
||||
}
|
||||
|
||||
function expectSupportFromEmailInput(inputEmail, isSupportShown) {
|
||||
const onTeamSelected = jest.fn();
|
||||
const res = doInputEmail(inputEmail, onTeamSelected);
|
||||
|
||||
expect(res.state.showSupportEmail).toBe(isSupportShown);
|
||||
}
|
||||
|
||||
describe('RegistrationForm', function() {
|
||||
beforeEach(function() {
|
||||
testUtils.beforeEach(this);
|
||||
});
|
||||
|
||||
it('should select a team when a team email is entered', function() {
|
||||
expectTeamSelectedFromEmailInput("member@team.ac.uk", TEAM_CONFIG.teams[0]);
|
||||
});
|
||||
|
||||
it('should not select a team when an unrecognised team email is entered', function() {
|
||||
expectTeamSelectedFromEmailInput("member@someunknownteam.ac.uk", null);
|
||||
});
|
||||
|
||||
it('should show support when an unrecognised team email is entered', function() {
|
||||
expectSupportFromEmailInput("member@someunknownteam.ac.uk", true);
|
||||
});
|
||||
|
||||
it('should NOT show support when an unrecognised non-team email is entered', function() {
|
||||
expectSupportFromEmailInput("someone@yahoo.com", false);
|
||||
});
|
||||
});
|
|
@ -104,20 +104,6 @@ export function createTestClient() {
|
|||
};
|
||||
}
|
||||
|
||||
export function createTestRtsClient(teamMap, sidMap) {
|
||||
return {
|
||||
getTeamsConfig() {
|
||||
return Promise.resolve(Object.keys(teamMap).map((token) => teamMap[token]));
|
||||
},
|
||||
trackReferral(referrer, emailSid, clientSecret) {
|
||||
return Promise.resolve({team_token: sidMap[emailSid]});
|
||||
},
|
||||
getTeam(teamToken) {
|
||||
return Promise.resolve(teamMap[teamToken]);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Event.
|
||||
* @param {Object} opts Values for the event.
|
||||
|
|
Loading…
Reference in New Issue