summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/react/components/admin_console/service_settings.jsx133
-rw-r--r--web/react/components/create_comment.jsx7
-rw-r--r--web/react/components/create_post.jsx7
-rw-r--r--web/react/components/file_upload.jsx46
-rw-r--r--web/react/utils/utils.jsx6
-rw-r--r--web/sass-files/sass/partials/_post.scss21
-rw-r--r--web/web.go2
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")