fix(dropbox): Address code review comments.
This commit is contained in:
parent
62544188bd
commit
2704b2f822
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
.recording-dialog {
|
.recording-dialog {
|
||||||
.authorization-panel {
|
.authorization-panel {
|
||||||
align-items: center;
|
|
||||||
border-bottom: 2px solid rgba(0, 0, 0, 0.3);
|
border-bottom: 2px solid rgba(0, 0, 0, 0.3);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -12,18 +11,23 @@
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
|
|
||||||
.dropbox-sign-in {
|
.dropbox-sign-in {
|
||||||
background-color: #4285f4;
|
align-items: center;
|
||||||
|
border: 1px solid #4285f4;
|
||||||
|
background-color: white;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
padding: 1px;
|
padding: 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
margin: 10px 0px;
|
margin: 10px 0px;
|
||||||
|
color: #4285f4;
|
||||||
|
|
||||||
.dropbox-logo {
|
.dropbox-logo {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 8px;
|
padding-right: 5px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,10 +456,11 @@
|
||||||
"on": "Recording",
|
"on": "Recording",
|
||||||
"pending": "Preparing to record the meeting...",
|
"pending": "Preparing to record the meeting...",
|
||||||
"rec": "REC",
|
"rec": "REC",
|
||||||
"authDropboxText": "To start the recording you need to first authorize our Dropbox recording app. After the recording is finished the file will be uploaded to your Dropbox account.",
|
"authDropboxText": "Upload your recording to Dropbox.",
|
||||||
"authDropboxCompletedText": "Our Dropbox app has been authorized successfully. You should see the recorded file in your Dropbox account shortly after the recording has finished.",
|
"authDropboxCompletedText": "Your recording file will appear in your Dropbox shortly after the recording has finished.",
|
||||||
"serviceName": "Recording service",
|
"serviceName": "Recording service",
|
||||||
"signOut": "Sign Out",
|
"signOut": "Sign Out",
|
||||||
|
"signIn": "sign in",
|
||||||
"loggedIn": "Logged in as __userName__",
|
"loggedIn": "Logged in as __userName__",
|
||||||
"availableSpace": "Available space: __spaceLeft__ MB (approximately __duration__ minutes of recording)",
|
"availableSpace": "Available space: __spaceLeft__ MB (approximately __duration__ minutes of recording)",
|
||||||
"startRecordingBody": "Are you sure you would like to start recording?",
|
"startRecordingBody": "Are you sure you would like to start recording?",
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { getJitsiMeetGlobalNS } from '../util';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the oauth flow.
|
|
||||||
*
|
|
||||||
* @param {string} authUrl - The URL to oauth service.
|
|
||||||
* @returns {Promise<string>} - The URL with the authorization details.
|
|
||||||
*/
|
|
||||||
export function authorize(authUrl: string): Promise<string> {
|
|
||||||
const windowName = `oauth${Date.now()}`;
|
|
||||||
const gloabalNS = getJitsiMeetGlobalNS();
|
|
||||||
|
|
||||||
gloabalNS.oauthCallbacks = gloabalNS.oauthCallbacks || {};
|
|
||||||
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const popup = window.open(authUrl, windowName);
|
|
||||||
|
|
||||||
gloabalNS.oauthCallbacks[windowName] = () => {
|
|
||||||
const returnURL = popup.location.href;
|
|
||||||
|
|
||||||
popup.close();
|
|
||||||
delete gloabalNS.oauthCallbacks.windowName;
|
|
||||||
resolve(returnURL);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { ReducerRegistry } from '../redux';
|
|
||||||
import { PersistenceRegistry } from '../storage';
|
|
||||||
|
|
||||||
import { UPDATE_DROPBOX_TOKEN } from './actionTypes';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default state.
|
|
||||||
*/
|
|
||||||
const DEFAULT_STATE = {
|
|
||||||
dropbox: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The redux subtree of this feature.
|
|
||||||
*/
|
|
||||||
const STORE_NAME = 'features/base/oauth';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the persistence of the feature {@code oauth}.
|
|
||||||
*/
|
|
||||||
PersistenceRegistry.register(STORE_NAME);
|
|
||||||
|
|
||||||
ReducerRegistry.register('features/base/oauth',
|
|
||||||
(state = DEFAULT_STATE, action) => {
|
|
||||||
switch (action.type) {
|
|
||||||
case UPDATE_DROPBOX_TOKEN:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
dropbox: {
|
|
||||||
token: action.token
|
|
||||||
}
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -2,12 +2,40 @@
|
||||||
|
|
||||||
import { Dropbox } from 'dropbox';
|
import { Dropbox } from 'dropbox';
|
||||||
|
|
||||||
import { getLocationContextRoot, parseStandardURIString } from '../util';
|
import {
|
||||||
import { parseURLParams } from '../config';
|
getJitsiMeetGlobalNS,
|
||||||
|
getLocationContextRoot,
|
||||||
|
parseStandardURIString
|
||||||
|
} from '../base/util';
|
||||||
|
import { parseURLParams } from '../base/config';
|
||||||
|
|
||||||
import { authorize } from './functions';
|
|
||||||
import { UPDATE_DROPBOX_TOKEN } from './actionTypes';
|
import { UPDATE_DROPBOX_TOKEN } from './actionTypes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the oauth flow.
|
||||||
|
*
|
||||||
|
* @param {string} authUrl - The URL to oauth service.
|
||||||
|
* @returns {Promise<string>} - The URL with the authorization details.
|
||||||
|
*/
|
||||||
|
function authorize(authUrl: string): Promise<string> {
|
||||||
|
const windowName = `oauth${Date.now()}`;
|
||||||
|
const gloabalNS = getJitsiMeetGlobalNS();
|
||||||
|
|
||||||
|
gloabalNS.oauthCallbacks = gloabalNS.oauthCallbacks || {};
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const popup = window.open(authUrl, windowName);
|
||||||
|
|
||||||
|
gloabalNS.oauthCallbacks[windowName] = () => {
|
||||||
|
const returnURL = popup.location.href;
|
||||||
|
|
||||||
|
popup.close();
|
||||||
|
delete gloabalNS.oauthCallbacks.windowName;
|
||||||
|
resolve(returnURL);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action to authorize the Jitsi Recording app in dropbox.
|
* Action to authorize the Jitsi Recording app in dropbox.
|
||||||
*
|
*
|
|
@ -0,0 +1,39 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { Dropbox } from 'dropbox';
|
||||||
|
|
||||||
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches information about the user's dropbox account.
|
||||||
|
*
|
||||||
|
* @param {string} token - The dropbox access token.
|
||||||
|
* @param {string} clientId - The Jitsi Recorder dropbox app ID.
|
||||||
|
* @returns {Promise<Object|undefined>}
|
||||||
|
*/
|
||||||
|
export function getDropboxData(
|
||||||
|
token: string,
|
||||||
|
clientId: string
|
||||||
|
): Promise<?Object> {
|
||||||
|
const dropboxAPI = new Dropbox({
|
||||||
|
accessToken: token,
|
||||||
|
clientId
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
[ dropboxAPI.usersGetCurrentAccount(), dropboxAPI.usersGetSpaceUsage() ]
|
||||||
|
).then(([ account, space ]) => {
|
||||||
|
const { allocation, used } = space;
|
||||||
|
const { allocated } = allocation;
|
||||||
|
|
||||||
|
return {
|
||||||
|
userName: account.name.display_name,
|
||||||
|
spaceLeft: Math.floor((allocated - used) / 1048576)// 1MiB=1048576B
|
||||||
|
};
|
||||||
|
|
||||||
|
}, error => {
|
||||||
|
logger.error(error);
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './actions';
|
export * from './actions';
|
||||||
|
export * from './functions';
|
||||||
|
|
||||||
import './reducer';
|
import './reducer';
|
|
@ -0,0 +1,28 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { ReducerRegistry } from '../base/redux';
|
||||||
|
import { PersistenceRegistry } from '../base/storage';
|
||||||
|
|
||||||
|
import { UPDATE_DROPBOX_TOKEN } from './actionTypes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The redux subtree of this feature.
|
||||||
|
*/
|
||||||
|
const STORE_NAME = 'features/dropbox';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the persistence of the feature {@code dropbox}.
|
||||||
|
*/
|
||||||
|
PersistenceRegistry.register(STORE_NAME);
|
||||||
|
|
||||||
|
ReducerRegistry.register(STORE_NAME, (state = {}, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case UPDATE_DROPBOX_TOKEN:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
token: action.token
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
});
|
|
@ -11,7 +11,7 @@ import { Dialog } from '../../../base/dialog';
|
||||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||||
|
|
||||||
import StartRecordingDialogContent from './StartRecordingDialogContent';
|
import StartRecordingDialogContent from './StartRecordingDialogContent';
|
||||||
import { getDropboxData } from '../../functions';
|
import { getDropboxData } from '../../../dropbox';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
@ -41,7 +41,6 @@ type Props = {
|
||||||
t: Function
|
t: Function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,15 +53,15 @@ type State = {
|
||||||
*/
|
*/
|
||||||
isValidating: boolean,
|
isValidating: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* The display name of the user's Dropbox account.
|
|
||||||
*/
|
|
||||||
userName: ?string,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of MiB of available space in user's Dropbox account.
|
* Number of MiB of available space in user's Dropbox account.
|
||||||
*/
|
*/
|
||||||
spaceLeft: ?number
|
spaceLeft: ?number,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The display name of the user's Dropbox account.
|
||||||
|
*/
|
||||||
|
userName: ?string
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -217,14 +216,16 @@ class StartRecordingDialog extends Component<Props, State> {
|
||||||
* @param {Object} state - The Redux state.
|
* @param {Object} state - The Redux state.
|
||||||
* @private
|
* @private
|
||||||
* @returns {{
|
* @returns {{
|
||||||
* _conference: JitsiConference
|
* _clientId: string,
|
||||||
|
* _conference: JitsiConference,
|
||||||
|
* _token: string
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
function mapStateToProps(state: Object) {
|
function mapStateToProps(state: Object) {
|
||||||
return {
|
return {
|
||||||
|
_clientId: state['features/base/config'].dropbox.clientId,
|
||||||
_conference: state['features/base/conference'].conference,
|
_conference: state['features/base/conference'].conference,
|
||||||
_token: state['features/base/oauth'].dropbox.token,
|
_token: state['features/dropbox'].token
|
||||||
_clientId: state['features/base/config'].dropbox.clientId
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
sendAnalytics
|
sendAnalytics
|
||||||
} from '../../../analytics';
|
} from '../../../analytics';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n';
|
||||||
import { authorizeDropbox, updateDropboxToken } from '../../../base/oauth';
|
import { authorizeDropbox, updateDropboxToken } from '../../../dropbox';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
@ -111,17 +111,21 @@ class StartRecordingDialogContent extends Component<Props> {
|
||||||
* @returns {React$Component}
|
* @returns {React$Component}
|
||||||
*/
|
*/
|
||||||
_renderSignIn() {
|
_renderSignIn() {
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>{ this.props.t('recording.authDropboxText') }</div>
|
<div>{ t('recording.authDropboxText') }</div>
|
||||||
<div
|
<div
|
||||||
className = 'dropbox-sign-in'
|
className = 'dropbox-sign-in'
|
||||||
onClick = { this._onSignInClick }>
|
onClick = { this._onSignInClick }>
|
||||||
<img
|
<img
|
||||||
className = 'dropbox-logo'
|
className = 'dropbox-logo'
|
||||||
src = 'images/dropboxLogo.svg' />
|
src = 'images/dropboxLogo.svg' />
|
||||||
|
<span>{ t('recording.signIn') }</span>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,7 +139,7 @@ class StartRecordingDialogContent extends Component<Props> {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>{ t('recording.authDropboxCompletedText') }</div>
|
<div>{ t('recording.authDropboxCompletedText') }</div>
|
||||||
<div className = 'logged-in-pannel'>
|
<div className = 'logged-in-panel'>
|
||||||
<div>
|
<div>
|
||||||
{ t('recording.loggedIn', { userName }) } (
|
{ t('recording.loggedIn', { userName }) } (
|
||||||
<a onClick = { this._onSignOutClick }>
|
<a onClick = { this._onSignOutClick }>
|
||||||
|
@ -154,7 +158,8 @@ class StartRecordingDialogContent extends Component<Props> {
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSignInClick: () => {};
|
_onSignInClick: () => {};
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { Dropbox } from 'dropbox';
|
|
||||||
|
|
||||||
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
||||||
|
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches in the passed in redux state for an active recording session of the
|
* Searches in the passed in redux state for an active recording session of the
|
||||||
* passed in mode.
|
* passed in mode.
|
||||||
|
@ -35,37 +31,3 @@ export function getSessionById(state: Object, id: string) {
|
||||||
return state['features/recording'].sessionDatas.find(
|
return state['features/recording'].sessionDatas.find(
|
||||||
sessionData => sessionData.id === id);
|
sessionData => sessionData.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches information about the user's dropbox account.
|
|
||||||
*
|
|
||||||
* @param {string} token - The dropbox access token.
|
|
||||||
* @param {string} clientId - The Jitsi Recorder dropbox app ID.
|
|
||||||
* @returns {Promise<Object|undefined>}
|
|
||||||
*/
|
|
||||||
export function getDropboxData(
|
|
||||||
token: string,
|
|
||||||
clientId: string
|
|
||||||
): Promise<?Object> {
|
|
||||||
const dropboxAPI = new Dropbox({
|
|
||||||
accessToken: token,
|
|
||||||
clientId
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(
|
|
||||||
[ dropboxAPI.usersGetCurrentAccount(), dropboxAPI.usersGetSpaceUsage() ]
|
|
||||||
).then(([ account, space ]) => {
|
|
||||||
const { allocation, used } = space;
|
|
||||||
const { allocated } = allocation;
|
|
||||||
|
|
||||||
return {
|
|
||||||
userName: account.name.display_name,
|
|
||||||
spaceLeft: Math.floor((allocated - used) / 1048576)// 1MiB=1048576B
|
|
||||||
};
|
|
||||||
|
|
||||||
}, error => {
|
|
||||||
logger.error(error);
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,30 +6,22 @@
|
||||||
<!--#include virtual="/base.html" -->
|
<!--#include virtual="/base.html" -->
|
||||||
<!--#include virtual="/title.html" -->
|
<!--#include virtual="/title.html" -->
|
||||||
<script>
|
<script>
|
||||||
function getParentWindowCallback() {
|
(function() {
|
||||||
var windowName = window.name;
|
var windowName = window.name;
|
||||||
var parentWindow = window.opener;
|
var parentWindow = window.opener;
|
||||||
if (parentWindow
|
if (parentWindow
|
||||||
&& parentWindow.JitsiMeetJS
|
&& parentWindow.JitsiMeetJS
|
||||||
&& parentWindow.JitsiMeetJS.app) {
|
&& parentWindow.JitsiMeetJS.app) {
|
||||||
var globalNS = parentWindow.JitsiMeetJS.app;
|
var globalNS = parentWindow.JitsiMeetJS.app;
|
||||||
if( globalNS.oauthCallbacks
|
if (globalNS.oauthCallbacks
|
||||||
&& typeof globalNS.oauthCallbacks[windowName]
|
&& typeof globalNS.oauthCallbacks[windowName]
|
||||||
=== 'function') {
|
=== 'function') {
|
||||||
return globalNS.oauthCallbacks[windowName];
|
globalNS.oauthCallbacks[windowName]();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
var callback = getParentWindowCallback();
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
callback();
|
|
||||||
} else {
|
|
||||||
alert('Something went wrong!');
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body />
|
<body>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue