From 5a3649791bd8923db7599208362ea69f0e7d448e Mon Sep 17 00:00:00 2001 From: Tainan Felipe Date: Wed, 14 Nov 2018 15:11:10 -0200 Subject: [PATCH 1/6] Transform joinRouterHandler and aunthenticatedRouteHandler in components --- bigbluebutton-html5/client/main.jsx | 30 ++-- .../imports/startup/client/auth.js | 134 ------------------ .../authenticated-handler/component.jsx | 90 ++++++++++++ .../ui/components/join-handler/component.jsx | 121 ++++++++++++++++ .../ui/components/meeting-ended/component.jsx | 17 ++- 5 files changed, 235 insertions(+), 157 deletions(-) delete mode 100755 bigbluebutton-html5/imports/startup/client/auth.js create mode 100644 bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx create mode 100644 bigbluebutton-html5/imports/ui/components/join-handler/component.jsx diff --git a/bigbluebutton-html5/client/main.jsx b/bigbluebutton-html5/client/main.jsx index 683d148e23..7eea3c5c44 100755 --- a/bigbluebutton-html5/client/main.jsx +++ b/bigbluebutton-html5/client/main.jsx @@ -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(, document.getElementById('app')); - // Logs all uncaught exceptions to the client logger window.addEventListener('error', (e) => { const { stack } = e.error; @@ -26,19 +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('isChatOpen', false); - Session.set('idChatOpen', ''); - Session.set('isMeetingEnded', false); - Session.get('breakoutRoomIsOpen', false); - render(, document.getElementById('app')); - }); - }); + render( + + + + + , + document.getElementById('app'), + ); }); diff --git a/bigbluebutton-html5/imports/startup/client/auth.js b/bigbluebutton-html5/imports/startup/client/auth.js deleted file mode 100755 index 6f50e762c6..0000000000 --- a/bigbluebutton-html5/imports/startup/client/auth.js +++ /dev/null @@ -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(); - }); -} diff --git a/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx new file mode 100644 index 0000000000..96ebd5d943 --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx @@ -0,0 +1,90 @@ +import React, { Component } from 'react'; +import { Session } from 'meteor/session'; +import _ from 'lodash'; +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 + : (); + } +} + + +export default AuthenticatedHandler; diff --git a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx new file mode 100644 index 0000000000..87602df009 --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx @@ -0,0 +1,121 @@ +import React, { Component } from 'react'; +import { Session } from 'meteor/session'; +import _ from 'lodash'; +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.fetchTolken = this.fetchTolken.bind(this); + this.changeToJoin = this.changeToJoin.bind(this); + + this.state = { + joined: false, + }; + } + + componentDidMount() { + this.fetchTolken(); + } + + changeToJoin(bool) { + this.setState({ joined: bool }); + } + + fetchTolken() { + 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') return resolve(resp); + const e = new Error('Session not found'); + return reject(e); + }); + }); + + validAuth + .then(setCustomData) + .then(setAuth) + .then(setLogoURl) + .then(() => Session.set('isUserListOpen', deviceInfo.type().isPhone)) + .then(logUserInfo) + .finally(() => this.changeToJoin(true)); + } + + render() { + const { children } = this.props; + const { joined } = this.state; + return joined ? + children : + (); + } +} + +export default JoinHandler; diff --git a/bigbluebutton-html5/imports/ui/components/meeting-ended/component.jsx b/bigbluebutton-html5/imports/ui/components/meeting-ended/component.jsx index f5e93483f9..1b052589c9 100755 --- a/bigbluebutton-html5/imports/ui/components/meeting-ended/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/meeting-ended/component.jsx @@ -4,7 +4,6 @@ import { defineMessages, injectIntl } from 'react-intl'; 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'; @@ -73,6 +72,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 = { @@ -94,7 +105,7 @@ class MeetingEnded extends React.PureComponent { } = this.state; if (selected <= 0) { - logoutRouteHandler(); + MeetingEnded.logoutRouteHandler(); return; } @@ -116,7 +127,7 @@ class MeetingEnded extends React.PureComponent { fetch(url, options) .finally(() => { - logoutRouteHandler(); + MeetingEnded.logoutRouteHandler(); }); } From b86d89f0fc7e2695c38ae96a77a615bbcf361b8b Mon Sep 17 00:00:00 2001 From: Tainan Felipe Date: Fri, 16 Nov 2018 13:58:49 -0200 Subject: [PATCH 2/6] Re-add logger messages --- .../imports/ui/components/join-handler/component.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx index 87602df009..f79e18ac27 100644 --- a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx @@ -8,6 +8,7 @@ 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); @@ -94,8 +95,12 @@ class JoinHandler extends Component { .then(response => response.json()) .then(({ response }) => response) .then((resp) => { - if (resp.returncode !== 'FAILED') return resolve(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); }); }); @@ -104,9 +109,10 @@ class JoinHandler extends Component { .then(setCustomData) .then(setAuth) .then(setLogoURl) - .then(() => Session.set('isUserListOpen', deviceInfo.type().isPhone)) .then(logUserInfo) + .then(() => Session.set('isUserListOpen', deviceInfo.type().isPhone)) .finally(() => this.changeToJoin(true)); + } render() { From da54c41510cd1e183e2d3e55682d6d479128c606 Mon Sep 17 00:00:00 2001 From: Tainan Felipe Date: Mon, 19 Nov 2018 13:40:42 -0200 Subject: [PATCH 3/6] Rename misspell function names --- .../imports/ui/components/join-handler/component.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx index f79e18ac27..886f7cfc03 100644 --- a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx @@ -16,7 +16,7 @@ class JoinHandler extends Component { } constructor(props) { super(props); - this.fetchTolken = this.fetchTolken.bind(this); + this.fetchToken = this.fetchToken.bind(this); this.changeToJoin = this.changeToJoin.bind(this); this.state = { @@ -25,14 +25,14 @@ class JoinHandler extends Component { } componentDidMount() { - this.fetchTolken(); + this.fetchToken(); } changeToJoin(bool) { this.setState({ joined: bool }); } - fetchTolken() { + fetchToken() { const urlParams = new URLSearchParams(window.location.search); const sessionToken = urlParams.get('sessionToken'); if (!sessionToken) { @@ -72,7 +72,7 @@ class JoinHandler extends Component { return resp; }; - const setLogoURl = (resp) => { + const setLogoURL = (resp) => { setCustomLogoUrl(resp.customLogoURL); return resp; }; @@ -108,7 +108,7 @@ class JoinHandler extends Component { validAuth .then(setCustomData) .then(setAuth) - .then(setLogoURl) + .then(setLogoURL) .then(logUserInfo) .then(() => Session.set('isUserListOpen', deviceInfo.type().isPhone)) .finally(() => this.changeToJoin(true)); From ae812d2358296db99aed2435527abff7048c9143 Mon Sep 17 00:00:00 2001 From: Tainan Felipe Date: Mon, 19 Nov 2018 14:14:26 -0200 Subject: [PATCH 4/6] Remove unsedvars and fix linter error --- .../imports/ui/components/authenticated-handler/component.jsx | 1 - .../imports/ui/components/join-handler/component.jsx | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx index 96ebd5d943..9de30ed45e 100644 --- a/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; import { Session } from 'meteor/session'; -import _ from 'lodash'; import { log } from '/imports/ui/services/api'; import Auth from '/imports/ui/services/auth'; import LoadingScreen from '/imports/ui/components/loading-screen/component'; diff --git a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx index 886f7cfc03..bdd6f32278 100644 --- a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; -import { Session } from 'meteor/session'; -import _ from 'lodash'; +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'; @@ -112,7 +111,6 @@ class JoinHandler extends Component { .then(logUserInfo) .then(() => Session.set('isUserListOpen', deviceInfo.type().isPhone)) .finally(() => this.changeToJoin(true)); - } render() { From 6135b52b0891b379d186a0ba6a91a5ee91f7340b Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Mon, 19 Nov 2018 13:53:25 -0300 Subject: [PATCH 5/6] Remove trailing spaces --- .../imports/ui/components/join-handler/component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx index bdd6f32278..0e491ba787 100644 --- a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { Session } from 'meteor/session'; +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'; From 84e5d431e8e75a4b19ca083e5d82f90a6e7b4197 Mon Sep 17 00:00:00 2001 From: Maxim Khlobystov Date: Mon, 19 Nov 2018 18:32:15 -0500 Subject: [PATCH 6/6] Split the build into stages --- .travis.yml | 17 ++++++++++++++++- build_script.sh | 38 +++++++++++++++++++++----------------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 12a35f6bf6..625ed375d0 100644 --- a/.travis.yml +++ b/.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 diff --git a/build_script.sh b/build_script.sh index 445a2adbed..42265a3dba 100755 --- a/build_script.sh +++ b/build_script.sh @@ -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