diff options
Diffstat (limited to 'web')
-rw-r--r-- | web/react/components/admin_console/service_settings.jsx | 133 | ||||
-rw-r--r-- | web/react/components/create_comment.jsx | 7 | ||||
-rw-r--r-- | web/react/components/create_post.jsx | 7 | ||||
-rw-r--r-- | web/react/components/file_upload.jsx | 46 | ||||
-rw-r--r-- | web/react/utils/utils.jsx | 6 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_post.scss | 21 | ||||
-rw-r--r-- | web/web.go | 2 |
7 files changed, 181 insertions, 41 deletions
diff --git a/web/react/components/admin_console/service_settings.jsx b/web/react/components/admin_console/service_settings.jsx index e235819fe..f10721ffa 100644 --- a/web/react/components/admin_console/service_settings.jsx +++ b/web/react/components/admin_console/service_settings.jsx @@ -4,6 +4,10 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; +const DefaultSessionLength = 30; +const DefaultMaximumLoginAttempts = 10; +const DefaultSessionCacheInMinutes = 10; + export default class ServiceSettings extends React.Component { constructor(props) { super(props); @@ -45,13 +49,56 @@ export default class ServiceSettings extends React.Component { //config.ServiceSettings.EnableOAuthServiceProvider = ReactDOM.findDOMNode(this.refs.EnableOAuthServiceProvider).checked; - var MaximumLoginAttempts = 10; + var MaximumLoginAttempts = DefaultMaximumLoginAttempts; if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.MaximumLoginAttempts).value, 10))) { MaximumLoginAttempts = parseInt(ReactDOM.findDOMNode(this.refs.MaximumLoginAttempts).value, 10); } + if (MaximumLoginAttempts < 1) { + MaximumLoginAttempts = 1; + } config.ServiceSettings.MaximumLoginAttempts = MaximumLoginAttempts; ReactDOM.findDOMNode(this.refs.MaximumLoginAttempts).value = MaximumLoginAttempts; + var SessionLengthWebInDays = DefaultSessionLength; + if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.SessionLengthWebInDays).value, 10))) { + SessionLengthWebInDays = parseInt(ReactDOM.findDOMNode(this.refs.SessionLengthWebInDays).value, 10); + } + if (SessionLengthWebInDays < 1) { + SessionLengthWebInDays = 1; + } + config.ServiceSettings.SessionLengthWebInDays = SessionLengthWebInDays; + ReactDOM.findDOMNode(this.refs.SessionLengthWebInDays).value = SessionLengthWebInDays; + + var SessionLengthMobileInDays = DefaultSessionLength; + if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.SessionLengthMobileInDays).value, 10))) { + SessionLengthMobileInDays = parseInt(ReactDOM.findDOMNode(this.refs.SessionLengthMobileInDays).value, 10); + } + if (SessionLengthMobileInDays < 1) { + SessionLengthMobileInDays = 1; + } + config.ServiceSettings.SessionLengthMobileInDays = SessionLengthMobileInDays; + ReactDOM.findDOMNode(this.refs.SessionLengthMobileInDays).value = SessionLengthMobileInDays; + + var SessionLengthSSOInDays = DefaultSessionLength; + if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.SessionLengthSSOInDays).value, 10))) { + SessionLengthSSOInDays = parseInt(ReactDOM.findDOMNode(this.refs.SessionLengthSSOInDays).value, 10); + } + if (SessionLengthSSOInDays < 1) { + SessionLengthSSOInDays = 1; + } + config.ServiceSettings.SessionLengthSSOInDays = SessionLengthSSOInDays; + ReactDOM.findDOMNode(this.refs.SessionLengthSSOInDays).value = SessionLengthSSOInDays; + + var SessionCacheInMinutes = DefaultSessionCacheInMinutes; + if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.SessionCacheInMinutes).value, 10))) { + SessionCacheInMinutes = parseInt(ReactDOM.findDOMNode(this.refs.SessionCacheInMinutes).value, 10); + } + if (SessionCacheInMinutes < -1) { + SessionCacheInMinutes = -1; + } + config.ServiceSettings.SessionCacheInMinutes = SessionCacheInMinutes; + ReactDOM.findDOMNode(this.refs.SessionCacheInMinutes).value = SessionCacheInMinutes; + Client.saveConfig( config, () => { @@ -417,6 +464,90 @@ export default class ServiceSettings extends React.Component { </div> <div className='form-group'> + <label + className='control-label col-sm-4' + htmlFor='SessionLengthWebInDays' + > + {'Session Length for Web in Days:'} + </label> + <div className='col-sm-8'> + <input + type='text' + className='form-control' + id='SessionLengthWebInDays' + ref='SessionLengthWebInDays' + placeholder='Ex "30"' + defaultValue={this.props.config.ServiceSettings.SessionLengthWebInDays} + onChange={this.handleChange} + /> + <p className='help-text'>{'The web session will expire after the number of days specified and will require a user to login again.'}</p> + </div> + </div> + + <div className='form-group'> + <label + className='control-label col-sm-4' + htmlFor='SessionLengthMobileInDays' + > + {'Session Length for Mobile Device in Days:'} + </label> + <div className='col-sm-8'> + <input + type='text' + className='form-control' + id='SessionLengthMobileInDays' + ref='SessionLengthMobileInDays' + placeholder='Ex "30"' + defaultValue={this.props.config.ServiceSettings.SessionLengthMobileInDays} + onChange={this.handleChange} + /> + <p className='help-text'>{'The native mobile session will expire after the number of days specified and will require a user to login again.'}</p> + </div> + </div> + + <div className='form-group'> + <label + className='control-label col-sm-4' + htmlFor='SessionLengthSSOInDays' + > + {'Session Length for SSO in Days:'} + </label> + <div className='col-sm-8'> + <input + type='text' + className='form-control' + id='SessionLengthSSOInDays' + ref='SessionLengthSSOInDays' + placeholder='Ex "30"' + defaultValue={this.props.config.ServiceSettings.SessionLengthSSOInDays} + onChange={this.handleChange} + /> + <p className='help-text'>{'The SSO session will expire after the number of days specified and will require a user to login again.'}</p> + </div> + </div> + + <div className='form-group'> + <label + className='control-label col-sm-4' + htmlFor='SessionCacheInMinutes' + > + {'Session Cache in Minutes:'} + </label> + <div className='col-sm-8'> + <input + type='text' + className='form-control' + id='SessionCacheInMinutes' + ref='SessionCacheInMinutes' + placeholder='Ex "30"' + defaultValue={this.props.config.ServiceSettings.SessionCacheInMinutes} + onChange={this.handleChange} + /> + <p className='help-text'>{'The number of minutes to cache a session in memory.'}</p> + </div> + </div> + + <div className='form-group'> <div className='col-sm-12'> {serverError} <button diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index c190b4dd8..cae94429c 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -32,7 +32,6 @@ export default class CreateComment extends React.Component { this.handleUploadStart = this.handleUploadStart.bind(this); this.handleFileUploadComplete = this.handleFileUploadComplete.bind(this); this.handleUploadError = this.handleUploadError.bind(this); - this.handleTextDrop = this.handleTextDrop.bind(this); this.removePreview = this.removePreview.bind(this); this.getFileCount = this.getFileCount.bind(this); this.handleResize = this.handleResize.bind(this); @@ -239,11 +238,6 @@ export default class CreateComment extends React.Component { this.setState({uploadsInProgress: draft.uploadsInProgress, serverError: err}); } } - handleTextDrop(text) { - const newText = this.state.messageText + text; - this.handleUserInput(newText); - Utils.setCaretPosition(ReactDOM.findDOMNode(this.refs.textbox.refs.message), newText.length); - } removePreview(id) { let previews = this.state.previews; let uploadsInProgress = this.state.uploadsInProgress; @@ -344,7 +338,6 @@ export default class CreateComment extends React.Component { onUploadStart={this.handleUploadStart} onFileUpload={this.handleFileUploadComplete} onUploadError={this.handleUploadError} - onTextDrop={this.handleTextDrop} postType='comment' channelId={this.props.channelId} /> diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index e901b272a..a476863a3 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -40,7 +40,6 @@ export default class CreatePost extends React.Component { this.handleUploadStart = this.handleUploadStart.bind(this); this.handleFileUploadComplete = this.handleFileUploadComplete.bind(this); this.handleUploadError = this.handleUploadError.bind(this); - this.handleTextDrop = this.handleTextDrop.bind(this); this.removePreview = this.removePreview.bind(this); this.onChange = this.onChange.bind(this); this.onPreferenceChange = this.onPreferenceChange.bind(this); @@ -281,11 +280,6 @@ export default class CreatePost extends React.Component { this.setState({uploadsInProgress: draft.uploadsInProgress, serverError: message}); } } - handleTextDrop(text) { - const newText = this.state.messageText + text; - this.handleUserInput(newText); - Utils.setCaretPosition(ReactDOM.findDOMNode(this.refs.textbox.refs.message), newText.length); - } removePreview(id) { const previews = Object.assign([], this.state.previews); const uploadsInProgress = this.state.uploadsInProgress; @@ -462,7 +456,6 @@ export default class CreatePost extends React.Component { onUploadStart={this.handleUploadStart} onFileUpload={this.handleFileUploadComplete} onUploadError={this.handleUploadError} - onTextDrop={this.handleTextDrop} postType='post' channelId='' /> diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index 9316ca9a5..a0c930ffb 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -109,8 +109,6 @@ export default class FileUpload extends React.Component { if (typeof files !== 'string' && files.length) { this.uploadFiles(files); - } else { - this.props.onTextDrop(e.originalEvent.dataTransfer.getData('Text')); } } @@ -120,11 +118,19 @@ export default class FileUpload extends React.Component { if (this.props.postType === 'post') { $('.row.main').dragster({ - enter() { - $('.center-file-overlay').removeClass('hidden'); + enter(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (utils.isFileTransfer(files)) { + $('.center-file-overlay').removeClass('hidden'); + } }, - leave() { - $('.center-file-overlay').addClass('hidden'); + leave(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (utils.isFileTransfer(files)) { + $('.center-file-overlay').addClass('hidden'); + } }, drop(dragsterEvent, e) { $('.center-file-overlay').addClass('hidden'); @@ -133,11 +139,19 @@ export default class FileUpload extends React.Component { }); } else if (this.props.postType === 'comment') { $('.post-right__container').dragster({ - enter() { - $('.right-file-overlay').removeClass('hidden'); + enter(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (utils.isFileTransfer(files)) { + $('.right-file-overlay').removeClass('hidden'); + } }, - leave() { - $('.right-file-overlay').addClass('hidden'); + leave(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (utils.isFileTransfer(files)) { + $('.right-file-overlay').addClass('hidden'); + } }, drop(dragsterEvent, e) { $('.right-file-overlay').addClass('hidden'); @@ -229,6 +243,18 @@ export default class FileUpload extends React.Component { }); } + componentWillUnmount() { + let target; + if (this.props.postType === 'post') { + target = $('.row.main'); + } else { + target = $('.post-right__container'); + } + + // jquery-dragster doesn't provide a function to unregister itself so do it manually + target.off('dragenter dragleave dragover drop dragster:enter dragster:leave dragster:over dragster:drop'); + } + cancelUpload(clientId) { var requests = this.state.requests; var request = requests[clientId]; diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 33aae7d1e..95eca7c3a 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -1276,3 +1276,9 @@ export function fillArray(value, length) { return arr; } + +// Checks if a data transfer contains files not text, folders, etc.. +// Slightly modified from http://stackoverflow.com/questions/6848043/how-do-i-detect-a-file-is-being-dragged-rather-than-a-draggable-element-on-my-pa +export function isFileTransfer(files) { + return files.types != null && (files.types.indexOf ? files.types.indexOf('Files') !== -1 : files.types.contains('application/x-moz-file')); +} diff --git a/web/sass-files/sass/partials/_post.scss b/web/sass-files/sass/partials/_post.scss index 937b08084..31ad586ba 100644 --- a/web/sass-files/sass/partials/_post.scss +++ b/web/sass-files/sass/partials/_post.scss @@ -417,12 +417,6 @@ body.ios { background-color: beige; } - ul { - margin: 0; - padding: 0; - } - - p { margin: 0; line-height: 1.6em; @@ -671,20 +665,17 @@ body.ios { @include legacy-pie-clearfix; width: calc(100% - 75px); - img { - max-height: 400px; - } - - ul { - margin-bottom: 0.6em; - padding: 5px 0 0 20px; + p { + margin: 0 0 0.4em; } - ul + p { - margin-top: 1em; + img { + max-height: 400px; } ul, ol { + margin-bottom: 0.4em; + p { margin-bottom: 0; } diff --git a/web/web.go b/web/web.go index 30a70ba2e..bf1208adc 100644 --- a/web/web.go +++ b/web/web.go @@ -998,7 +998,7 @@ func getAccessToken(c *api.Context, w http.ResponseWriter, r *http.Request) { return } - accessRsp := &model.AccessResponse{AccessToken: session.Token, TokenType: model.ACCESS_TOKEN_TYPE, ExpiresIn: model.SESSION_TIME_OAUTH_IN_SECS} + accessRsp := &model.AccessResponse{AccessToken: session.Token, TokenType: model.ACCESS_TOKEN_TYPE, ExpiresIn: int32(*utils.Cfg.ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24)} w.Header().Set("Content-Type", "application/json") w.Header().Set("Cache-Control", "no-store") |