Merge pull request #3696 from virtuacoplenny/lenny/stream-key-validation
Add some live stream key validation
This commit is contained in:
commit
699b13066e
|
@ -65,6 +65,8 @@
|
|||
}
|
||||
|
||||
.form-footer {
|
||||
display: flex;
|
||||
margin-top: 5px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
@ -95,9 +97,15 @@
|
|||
|
||||
.stream-key-form {
|
||||
.helper-link {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
margin-top: 5px;
|
||||
display: inline-block;
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.validation-error {
|
||||
color:#FFD740;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -515,6 +515,7 @@
|
|||
"expandedOn": "The meeting is currently being streamed to YouTube.",
|
||||
"expandedPending": "The live streaming is being started...",
|
||||
"failedToStart": "Live Streaming failed to start",
|
||||
"invalidStreamKey": "Live stream key may be incorrect.",
|
||||
"off": "Live Streaming stopped",
|
||||
"on": "Live Streaming",
|
||||
"pending": "Starting Live Stream...",
|
||||
|
|
|
@ -194,7 +194,8 @@ export default class AbstractStartLiveStreamDialog<P: Props>
|
|||
*/
|
||||
_onSubmit() {
|
||||
const { broadcasts, selectedBoundStreamID } = this.state;
|
||||
const key = this.state.streamKey || this.props._streamKey;
|
||||
const key
|
||||
= (this.state.streamKey || this.props._streamKey || '').trim();
|
||||
|
||||
if (!key) {
|
||||
return false;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import debounce from 'lodash/debounce';
|
||||
import { Component } from 'react';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
@ -33,14 +34,27 @@ export type Props = {
|
|||
value: string
|
||||
};
|
||||
|
||||
/**
|
||||
* The state of the component.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* Whether or not to show the warnings that the passed in value seems like
|
||||
* an improperly formatted stream key.
|
||||
*/
|
||||
showValidationError: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstract React Component for entering a key for starting a YouTube live
|
||||
* stream.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
export default class AbstractStreamKeyForm extends Component<Props> {
|
||||
export default class AbstractStreamKeyForm extends Component<Props, State> {
|
||||
helpURL: string;
|
||||
_debouncedUpdateValidationErrorVisibility: Function;
|
||||
|
||||
/**
|
||||
* Constructor for the component.
|
||||
|
@ -50,14 +64,45 @@ export default class AbstractStreamKeyForm extends Component<Props> {
|
|||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showValidationError: Boolean(this.props.value)
|
||||
&& !this._validateStreamKey(this.props.value)
|
||||
};
|
||||
|
||||
this.helpURL = (typeof interfaceConfig !== 'undefined'
|
||||
&& interfaceConfig.LIVE_STREAMING_HELP_LINK)
|
||||
|| LIVE_STREAMING_HELP_LINK;
|
||||
|
||||
this._debouncedUpdateValidationErrorVisibility = debounce(
|
||||
this._updateValidationErrorVisibility.bind(this),
|
||||
800,
|
||||
{ leading: false }
|
||||
);
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onInputChange = this._onInputChange.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React Component's componentDidUpdate.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (this.props.value !== prevProps.value) {
|
||||
this._debouncedUpdateValidationErrorVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React Component's componentWillUnmount.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this._debouncedUpdateValidationErrorVisibility.cancel();
|
||||
}
|
||||
|
||||
_onInputChange: Object => void
|
||||
|
||||
/**
|
||||
|
@ -75,4 +120,38 @@ export default class AbstractStreamKeyForm extends Component<Props> {
|
|||
|
||||
this.props.onChange(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the stream key value seems like a valid stream key and sets the
|
||||
* state for showing or hiding the notification about the stream key seeming
|
||||
* invalid.
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_updateValidationErrorVisibility() {
|
||||
const newShowValidationError = Boolean(this.props.value)
|
||||
&& !this._validateStreamKey(this.props.value);
|
||||
|
||||
if (newShowValidationError !== this.state.showValidationError) {
|
||||
this.setState({
|
||||
showValidationError: newShowValidationError
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a passed in stream key appears to be in a valid format.
|
||||
*
|
||||
* @param {string} streamKey - The stream key to check for valid formatting.
|
||||
* @returns {void}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_validateStreamKey(streamKey = '') {
|
||||
const trimmedKey = streamKey.trim();
|
||||
const fourGroupsDashSeparated = /^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}/;
|
||||
const match = fourGroupsDashSeparated.exec(trimmedKey);
|
||||
|
||||
return Boolean(match);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,15 +52,28 @@ class StreamKeyForm extends AbstractStreamKeyForm {
|
|||
placeholderTextColor = { PLACEHOLDER_COLOR }
|
||||
style = { styles.streamKeyInput }
|
||||
value = { this.props.value } />
|
||||
<TouchableOpacity
|
||||
onPress = { this._onOpenHelp }
|
||||
style = { styles.streamKeyHelp } >
|
||||
<Text style = { styles.text }>
|
||||
{
|
||||
t('liveStreaming.streamIdHelp')
|
||||
}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<View style = { styles.formFooter }>
|
||||
{
|
||||
this.state.showValidationError
|
||||
? <View style = { styles.formFooterItem }>
|
||||
<Text style = { styles.warningText }>
|
||||
{ t('liveStreaming.invalidStreamKey') }
|
||||
</Text>
|
||||
</View>
|
||||
: null
|
||||
}
|
||||
<View style = { styles.formFooterItem }>
|
||||
<TouchableOpacity
|
||||
onPress = { this._onOpenHelp }
|
||||
style = { styles.streamKeyHelp } >
|
||||
<Text style = { styles.text }>
|
||||
{
|
||||
t('liveStreaming.streamIdHelp')
|
||||
}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,20 @@ export default createStyleSheet({
|
|||
padding: BoxModel.padding
|
||||
},
|
||||
|
||||
/**
|
||||
* Wrapper for the last element in the form.
|
||||
*/
|
||||
formFooter: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
/**
|
||||
* Wrapper for individual children in the last element of the form.
|
||||
*/
|
||||
formFooterItem: {
|
||||
flex: 1
|
||||
},
|
||||
|
||||
/**
|
||||
* Explaining text on the top of the sign in form.
|
||||
*/
|
||||
|
@ -133,6 +147,12 @@ export default createStyleSheet({
|
|||
|
||||
text: {
|
||||
color: ColorPalette.white
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A different colored text to indicate information needing attention.
|
||||
*/
|
||||
warningText: {
|
||||
color: ColorPalette.Y200
|
||||
}
|
||||
});
|
||||
|
|
|
@ -36,7 +36,7 @@ class StreamKeyForm extends AbstractStreamKeyForm {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { value, t } = this.props;
|
||||
const { t, value } = this.props;
|
||||
|
||||
return (
|
||||
<div className = 'stream-key-form'>
|
||||
|
@ -52,16 +52,23 @@ class StreamKeyForm extends AbstractStreamKeyForm {
|
|||
shouldFitContainer = { true }
|
||||
type = 'text'
|
||||
value = { this.props.value } />
|
||||
{ this.helpURL
|
||||
? <div className = 'form-footer'>
|
||||
<a
|
||||
<div className = 'form-footer'>
|
||||
{
|
||||
this.state.showValidationError
|
||||
? <span className = 'validation-error'>
|
||||
{ t('liveStreaming.invalidStreamKey') }
|
||||
</span>
|
||||
: null
|
||||
}
|
||||
{ this.helpURL
|
||||
? <a
|
||||
className = 'helper-link'
|
||||
onClick = { this._onOpenHelp }>
|
||||
{ t('liveStreaming.streamIdHelp') }
|
||||
</a>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue