Merge branch 'master' of https://github.com/bigbluebutton/bigbluebutton into 2.2-panel-manager
This commit is contained in:
commit
79c168d2a4
17
.travis.yml
17
.travis.yml
@ -2,9 +2,24 @@ dist: trusty
|
||||
|
||||
language: node_js
|
||||
|
||||
env:
|
||||
- JOB_TYPE=linter
|
||||
- JOB_TYPE=acceptance_tests
|
||||
|
||||
node_js:
|
||||
- "8"
|
||||
|
||||
jobs:
|
||||
allow_failures:
|
||||
- env: JOB_TYPE=linter
|
||||
include:
|
||||
- stage: "Linter"
|
||||
name: "ESLint"
|
||||
env: JOB_TYPE=linter
|
||||
- stage: "Tests"
|
||||
name: "Acceptance Tests"
|
||||
env: JOB_TYPE=acceptance_tests
|
||||
|
||||
if: type = pull_request
|
||||
|
||||
env:
|
||||
@ -12,7 +27,7 @@ env:
|
||||
- BBB_SERVER_URL=http://localhost/bigbluebutton/api
|
||||
|
||||
script:
|
||||
- travis_wait bash ./build_script.sh
|
||||
- travis_wait bash ./build_script.sh $JOB_TYPE
|
||||
|
||||
after_script:
|
||||
- docker stop $docker
|
||||
|
@ -1,16 +1,13 @@
|
||||
/* eslint no-unused-vars: 0 */
|
||||
import React from 'react';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Session } from 'meteor/session';
|
||||
import { render } from 'react-dom';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import { joinRouteHandler, authenticatedRouteHandler } from '/imports/startup/client/auth';
|
||||
import Base from '/imports/startup/client/base';
|
||||
import LoadingScreen from '/imports/ui/components/loading-screen/component';
|
||||
import JoinHandler from '/imports/ui/components/join-handler/component';
|
||||
import AuthenticatedHandler from '/imports/ui/components/authenticated-handler/component';
|
||||
|
||||
Meteor.startup(() => {
|
||||
render(<LoadingScreen />, document.getElementById('app'));
|
||||
|
||||
// Logs all uncaught exceptions to the client logger
|
||||
window.addEventListener('error', (e) => {
|
||||
const { stack } = e.error;
|
||||
@ -26,18 +23,12 @@ Meteor.startup(() => {
|
||||
});
|
||||
|
||||
// TODO make this a Promise
|
||||
joinRouteHandler((value, error) => {
|
||||
if (error) {
|
||||
logger.error(`User faced [${value}] on main.joinRouteHandler. Error was:`, JSON.stringify(error));
|
||||
} else {
|
||||
logger.info(`User successfully went through main.joinRouteHandler with [${value}].`);
|
||||
}
|
||||
authenticatedRouteHandler(() => {
|
||||
// set defaults
|
||||
Session.set('openPanel', '');
|
||||
Session.set('idChatOpen', '');
|
||||
Session.set('isMeetingEnded', false);
|
||||
render(<Base />, document.getElementById('app'));
|
||||
});
|
||||
});
|
||||
render(
|
||||
<JoinHandler >
|
||||
<AuthenticatedHandler>
|
||||
<Base />
|
||||
</AuthenticatedHandler>
|
||||
</JoinHandler>,
|
||||
document.getElementById('app'),
|
||||
);
|
||||
});
|
||||
|
@ -1,134 +0,0 @@
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import { setCustomLogoUrl } from '/imports/ui/components/user-list/service';
|
||||
import { log, makeCall } from '/imports/ui/services/api';
|
||||
import deviceInfo from '/imports/utils/deviceInfo';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import { Session } from 'meteor/session';
|
||||
|
||||
// disconnected and trying to open a new connection
|
||||
const STATUS_CONNECTING = 'connecting';
|
||||
|
||||
const setError = (errorCode) => {
|
||||
Session.set('hasError', true);
|
||||
Session.set('codeError', errorCode);
|
||||
};
|
||||
|
||||
export function joinRouteHandler(callback) {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const sessionToken = urlParams.get('sessionToken');
|
||||
|
||||
if (!sessionToken) {
|
||||
setError('404');
|
||||
callback('failed - no sessionToken', urlParams);
|
||||
}
|
||||
|
||||
// Old credentials stored in memory were being used when joining a new meeting
|
||||
Auth.clearCredentials();
|
||||
|
||||
// use enter api to get params for the client
|
||||
const url = `/bigbluebutton/api/enter?sessionToken=${sessionToken}`;
|
||||
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(response => response.json())
|
||||
.then(({ response }) => {
|
||||
const {
|
||||
returncode, meetingID, internalUserID, authToken, logoutUrl, customLogoURL,
|
||||
externUserID, fullname, confname, customdata,
|
||||
} = response;
|
||||
|
||||
if (returncode === 'FAILED') {
|
||||
setError('404');
|
||||
callback('failed during enter API call', response);
|
||||
} else {
|
||||
setCustomLogoUrl(customLogoURL);
|
||||
|
||||
if (customdata.length) {
|
||||
makeCall('addUserSettings', meetingID, internalUserID, customdata);
|
||||
}
|
||||
|
||||
Auth.set(
|
||||
meetingID, internalUserID, authToken, logoutUrl,
|
||||
sessionToken, fullname, externUserID, confname,
|
||||
);
|
||||
|
||||
Session.set('isUserListOpen', deviceInfo.type().isPhone);
|
||||
const userInfo = window.navigator;
|
||||
|
||||
// Browser information is sent once on startup
|
||||
// Sent here instead of Meteor.startup, as the
|
||||
// user might not be validated by then, thus user's data
|
||||
// would not be sent with this information
|
||||
const clientInfo = {
|
||||
language: userInfo.language,
|
||||
userAgent: userInfo.userAgent,
|
||||
screenSize: { width: window.screen.width, height: window.screen.height },
|
||||
windowSize: { width: window.innerWidth, height: window.innerHeight },
|
||||
bbbVersion: Meteor.settings.public.app.bbbServerVersion,
|
||||
location: window.location.href,
|
||||
};
|
||||
|
||||
logger.info(clientInfo);
|
||||
|
||||
callback('all is good', null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function logoutRouteHandler() {
|
||||
Auth.logout()
|
||||
.then((logoutURL = window.location.origin) => {
|
||||
const protocolPattern = /^((http|https):\/\/)/;
|
||||
|
||||
window.location.href =
|
||||
protocolPattern.test(logoutURL) ?
|
||||
logoutURL :
|
||||
`http://${logoutURL}`;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if should revalidate the auth
|
||||
* @param {Object} status
|
||||
* @param {String} lastStatus
|
||||
*/
|
||||
export function shouldAuthenticate(status, lastStatus) {
|
||||
return lastStatus != null && lastStatus === STATUS_CONNECTING && status.connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the isn't the first connection try, preventing to authenticate on login.
|
||||
* @param {Object} status
|
||||
* @param {string} lastStatus
|
||||
*/
|
||||
export function updateStatus(status, lastStatus) {
|
||||
return status.retryCount > 0 && lastStatus !== STATUS_CONNECTING ? status.status : lastStatus;
|
||||
}
|
||||
|
||||
function _addReconnectObservable() {
|
||||
let lastStatus = null;
|
||||
|
||||
Tracker.autorun(() => {
|
||||
lastStatus = updateStatus(Meteor.status(), lastStatus);
|
||||
|
||||
if (shouldAuthenticate(Meteor.status(), lastStatus)) {
|
||||
Auth.authenticate(true);
|
||||
lastStatus = Meteor.status().status;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function authenticatedRouteHandler(callback) {
|
||||
if (Auth.loggedIn) {
|
||||
callback();
|
||||
}
|
||||
|
||||
_addReconnectObservable();
|
||||
|
||||
Auth.authenticate()
|
||||
.then(callback)
|
||||
.catch((reason) => {
|
||||
log('error', reason);
|
||||
setError(reason.error);
|
||||
callback();
|
||||
});
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Session } from 'meteor/session';
|
||||
import { log } from '/imports/ui/services/api';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import LoadingScreen from '/imports/ui/components/loading-screen/component';
|
||||
|
||||
const STATUS_CONNECTING = 'connecting';
|
||||
|
||||
class AuthenticatedHandler extends Component {
|
||||
static setError(codeError) {
|
||||
Session.set('hasError', true);
|
||||
if (codeError) Session.set('codeError', codeError);
|
||||
}
|
||||
static shouldAuthenticate(status, lastStatus) {
|
||||
return lastStatus != null && lastStatus === STATUS_CONNECTING && status.connected;
|
||||
}
|
||||
|
||||
static updateStatus(status, lastStatus) {
|
||||
return status.retryCount > 0 && lastStatus !== STATUS_CONNECTING ? status.status : lastStatus;
|
||||
}
|
||||
|
||||
static addReconnectObservable() {
|
||||
let lastStatus = null;
|
||||
|
||||
Tracker.autorun(() => {
|
||||
lastStatus = AuthenticatedHandler.updateStatus(Meteor.status(), lastStatus);
|
||||
|
||||
if (AuthenticatedHandler.shouldAuthenticate(Meteor.status(), lastStatus)) {
|
||||
Auth.authenticate(true);
|
||||
lastStatus = Meteor.status().status;
|
||||
}
|
||||
});
|
||||
}
|
||||
static authenticatedRouteHandler(callback) {
|
||||
if (Auth.loggedIn) {
|
||||
callback();
|
||||
}
|
||||
|
||||
AuthenticatedHandler.addReconnectObservable();
|
||||
|
||||
Auth.authenticate()
|
||||
.then(callback)
|
||||
.catch((reason) => {
|
||||
log('error', reason);
|
||||
AuthenticatedHandler.setError(reason.error);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.changeState = this.changeState.bind(this);
|
||||
this.state = {
|
||||
authenticated: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
AuthenticatedHandler.authenticatedRouteHandler((value, error) => {
|
||||
if (error) AuthenticatedHandler.setError(error);
|
||||
this.changeState(true);
|
||||
});
|
||||
}
|
||||
|
||||
changeState(state) {
|
||||
this.setState({ authenticated: state });
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
} = this.props;
|
||||
const {
|
||||
authenticated,
|
||||
} = this.state;
|
||||
|
||||
Session.set('isChatOpen', false);
|
||||
Session.set('idChatOpen', '');
|
||||
Session.set('isMeetingEnded', false);
|
||||
Session.set('isPollOpen', false);
|
||||
Session.set('breakoutRoomIsOpen', false);
|
||||
|
||||
return authenticated
|
||||
? children
|
||||
: (<LoadingScreen />);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default AuthenticatedHandler;
|
@ -0,0 +1,128 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Session } from 'meteor/session';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import { setCustomLogoUrl } from '/imports/ui/components/user-list/service';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import deviceInfo from '/imports/utils/deviceInfo';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import LoadingScreen from '/imports/ui/components/loading-screen/component';
|
||||
|
||||
|
||||
class JoinHandler extends Component {
|
||||
static setError(codeError) {
|
||||
Session.set('hasError', true);
|
||||
if (codeError) Session.set('codeError', codeError);
|
||||
}
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.fetchToken = this.fetchToken.bind(this);
|
||||
this.changeToJoin = this.changeToJoin.bind(this);
|
||||
|
||||
this.state = {
|
||||
joined: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchToken();
|
||||
}
|
||||
|
||||
changeToJoin(bool) {
|
||||
this.setState({ joined: bool });
|
||||
}
|
||||
|
||||
fetchToken() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const sessionToken = urlParams.get('sessionToken');
|
||||
if (!sessionToken) {
|
||||
JoinHandler.setError('404');
|
||||
}
|
||||
|
||||
// Old credentials stored in memory were being used when joining a new meeting
|
||||
Auth.clearCredentials();
|
||||
const logUserInfo = () => {
|
||||
const userInfo = window.navigator;
|
||||
|
||||
// Browser information is sent once on startup
|
||||
// Sent here instead of Meteor.startup, as the
|
||||
// user might not be validated by then, thus user's data
|
||||
// would not be sent with this information
|
||||
const clientInfo = {
|
||||
language: userInfo.language,
|
||||
userAgent: userInfo.userAgent,
|
||||
screenSize: { width: window.screen.width, height: window.screen.height },
|
||||
windowSize: { width: window.innerWidth, height: window.innerHeight },
|
||||
bbbVersion: Meteor.settings.public.app.bbbServerVersion,
|
||||
location: window.location.href,
|
||||
};
|
||||
|
||||
logger.info(clientInfo);
|
||||
};
|
||||
|
||||
const setAuth = (resp) => {
|
||||
const {
|
||||
meetingID, internalUserID, authToken, logoutUrl,
|
||||
fullname, externUserID, confname,
|
||||
} = resp;
|
||||
Auth.set(
|
||||
meetingID, internalUserID, authToken, logoutUrl,
|
||||
sessionToken, fullname, externUserID, confname,
|
||||
);
|
||||
return resp;
|
||||
};
|
||||
|
||||
const setLogoURL = (resp) => {
|
||||
setCustomLogoUrl(resp.customLogoURL);
|
||||
return resp;
|
||||
};
|
||||
|
||||
const setCustomData = (resp) => {
|
||||
const {
|
||||
meetingID, internalUserID, customdata,
|
||||
} = resp;
|
||||
|
||||
if (customdata.length) {
|
||||
makeCall('addUserSettings', meetingID, internalUserID, customdata);
|
||||
}
|
||||
return resp;
|
||||
};
|
||||
// use enter api to get params for the client
|
||||
const url = `/bigbluebutton/api/enter?sessionToken=${sessionToken}`;
|
||||
|
||||
const validAuth = new Promise((resolve, reject) => {
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(response => response.json())
|
||||
.then(({ response }) => response)
|
||||
.then((resp) => {
|
||||
if (resp.returncode !== 'FAILED') {
|
||||
logger.info(`User successfully went through main.joinRouteHandler with [${resp}].`);
|
||||
return resolve(resp);
|
||||
}
|
||||
const e = new Error('Session not found');
|
||||
logger.error(`User faced [${e}] on main.joinRouteHandler. Error was:`, JSON.stringify(resp));
|
||||
return reject(e);
|
||||
});
|
||||
});
|
||||
|
||||
validAuth
|
||||
.then(setCustomData)
|
||||
.then(setAuth)
|
||||
.then(setLogoURL)
|
||||
.then(logUserInfo)
|
||||
.then(() => {
|
||||
Session.set('openPanel', deviceInfo.type().isPhone ? 'userlist' : '');
|
||||
Session.set('idChatOpen', '');
|
||||
})
|
||||
.finally(() => this.changeToJoin(true));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const { joined } = this.state;
|
||||
return joined ?
|
||||
children :
|
||||
(<LoadingScreen />);
|
||||
}
|
||||
}
|
||||
|
||||
export default JoinHandler;
|
@ -5,7 +5,6 @@ import { Meteor } from 'meteor/meteor';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import { logoutRouteHandler } from '/imports/startup/client/auth';
|
||||
import Rating from './rating/component';
|
||||
import { styles } from './styles';
|
||||
|
||||
@ -79,6 +78,18 @@ class MeetingEnded extends React.PureComponent {
|
||||
return comment;
|
||||
}
|
||||
|
||||
static logoutRouteHandler() {
|
||||
Auth.logout()
|
||||
.then((logoutURL = window.location.origin) => {
|
||||
const protocolPattern = /^((http|https):\/\/)/;
|
||||
|
||||
window.location.href =
|
||||
protocolPattern.test(logoutURL) ?
|
||||
logoutURL :
|
||||
`http://${logoutURL}`;
|
||||
});
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@ -105,7 +116,7 @@ class MeetingEnded extends React.PureComponent {
|
||||
} = this.state;
|
||||
|
||||
if (selected <= 0) {
|
||||
logoutRouteHandler();
|
||||
MeetingEnded.logoutRouteHandler();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -127,7 +138,7 @@ class MeetingEnded extends React.PureComponent {
|
||||
|
||||
fetch(url, options)
|
||||
.finally(() => {
|
||||
logoutRouteHandler();
|
||||
MeetingEnded.logoutRouteHandler();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3,27 +3,31 @@ set -ev
|
||||
|
||||
files=`git diff --name-only HEAD..$TRAVIS_BRANCH`
|
||||
if [[ $files = *"bigbluebutton-html5"* ]]; then
|
||||
{
|
||||
cd bigbluebutton-html5
|
||||
git clone --single-branch -b update-html5 https://github.com/bigbluebutton/docker.git
|
||||
cp -r docker/{mod,restart.sh,setup.sh,supervisord.conf} .
|
||||
cp -r docker/Dockerfile Dockerfile.test
|
||||
docker build -t b2 -f Dockerfile.test .
|
||||
docker=$(docker run -d -p 80:80/tcp -p 443:443/tcp -p 1935:1935 -p 5066:5066 -p 3478:3478 -p 3478:3478/udp b2 -h localhost)
|
||||
echo $docker
|
||||
cd bigbluebutton-html5
|
||||
curl https://install.meteor.com/ | sh
|
||||
meteor npm install
|
||||
if [ $1 = linter ]
|
||||
then
|
||||
cd ..
|
||||
bigbluebutton-html5/node_modules/.bin/eslint --ext .jsx,.js $files
|
||||
elif [ $1 = acceptance_tests ]
|
||||
then
|
||||
{
|
||||
git clone --single-branch -b update-html5 https://github.com/bigbluebutton/docker.git
|
||||
cp -r docker/{mod,restart.sh,setup.sh,supervisord.conf} .
|
||||
cp -r docker/Dockerfile Dockerfile.test
|
||||
docker build -t b2 -f Dockerfile.test .
|
||||
docker=$(docker run -d -p 80:80/tcp -p 443:443/tcp -p 1935:1935 -p 5066:5066 -p 3478:3478 -p 3478:3478/udp b2 -h localhost)
|
||||
echo $docker
|
||||
} > /dev/null
|
||||
|
||||
cd tests/puppeteer
|
||||
npm install
|
||||
conf=$(docker exec $(docker ps -q) bbb-conf --secret | grep "Secret:")
|
||||
secret=$(echo $conf | cut -d' ' -f2)
|
||||
export BBB_SHARED_SECRET=$secret
|
||||
node html5-check.js
|
||||
|
||||
cd ../..
|
||||
curl https://install.meteor.com/ | sh
|
||||
meteor npm install
|
||||
cd tests/puppeteer
|
||||
npm install
|
||||
cd ../../..
|
||||
} > /dev/null
|
||||
bigbluebutton-html5/node_modules/.bin/eslint --ext .jsx,.js $files
|
||||
node html5-check.js
|
||||
npm test
|
||||
fi
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user