summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--api/post.go8
-rw-r--r--config/config.json4
-rw-r--r--doc/integrations/webhooks/Outgoing-Webhooks.md4
-rw-r--r--docker/1.2/Dockerfile2
-rw-r--r--docker/1.2/config_docker.json4
-rw-r--r--docker/dev/config_docker.json4
-rw-r--r--docker/local/config_docker.json4
-rw-r--r--model/version.go1
-rw-r--r--store/sql_user_store.go2
-rw-r--r--utils/textgeneration.go15
-rw-r--r--web/react/components/post_body.jsx38
-rw-r--r--web/react/components/search_autocomplete.jsx12
-rw-r--r--web/react/components/team_general_tab.jsx3
-rw-r--r--web/react/components/tutorial/tutorial_tip.jsx27
-rw-r--r--web/react/components/user_settings/user_settings_general.jsx164
-rw-r--r--web/sass-files/sass/partials/_responsive.scss2
-rw-r--r--web/sass-files/sass/partials/_videos.scss2
-rw-r--r--web/web.go2
19 files changed, 161 insertions, 139 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 74c5b5208..3e423557d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -98,7 +98,7 @@ Multiple settings were added to [`config.json`](./config/config.json). These opt
- Added: `"RestrictTeamNames": true` to control whether team names can contain reserved words like www, admin, support, test, etc.
- Added: `"EnableTeamListing": false` to control whether teams can be listed on the root page of the site
- Under `ServiceSettings` in `config.json`
- - Added: `EnableOutgoingWebhooks": true` to turn on outgoing webhooks
+ - Added: `EnableOutgoingWebhooks": false` to control whether outgoing webhooks are enabled
#### Database Changes from v1.1 to v1.2
diff --git a/api/post.go b/api/post.go
index 3892d4ee8..ef70e1336 100644
--- a/api/post.go
+++ b/api/post.go
@@ -229,6 +229,14 @@ func handlePostEventsAndForget(c *Context, post *model.Post, triggerWebhooks boo
func handleWebhookEventsAndForget(c *Context, post *model.Post, team *model.Team, channel *model.Channel, user *model.User) {
go func() {
+ if !utils.Cfg.ServiceSettings.EnableOutgoingWebhooks {
+ return
+ }
+
+ if channel.Type != model.CHANNEL_OPEN {
+ return
+ }
+
hchan := Srv.Store.Webhook().GetOutgoingByTeam(c.Session.TeamId)
hooks := []*model.OutgoingWebhook{}
diff --git a/config/config.json b/config/config.json
index a927620b5..932bed8a2 100644
--- a/config/config.json
+++ b/config/config.json
@@ -5,8 +5,8 @@
"SegmentDeveloperKey": "",
"GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
- "EnableIncomingWebhooks": true,
- "EnableOutgoingWebhooks": true,
+ "EnableIncomingWebhooks": false,
+ "EnableOutgoingWebhooks": false,
"EnablePostUsernameOverride": false,
"EnablePostIconOverride": false,
"EnableTesting": false,
diff --git a/doc/integrations/webhooks/Outgoing-Webhooks.md b/doc/integrations/webhooks/Outgoing-Webhooks.md
index 008245715..5fbbb9d87 100644
--- a/doc/integrations/webhooks/Outgoing-Webhooks.md
+++ b/doc/integrations/webhooks/Outgoing-Webhooks.md
@@ -1,7 +1,5 @@
# Outgoing Webhooks
-#### [To be released in Mattermost v1.2, available now on master]
-
Outgoing webhooks allow external applications, written in the programming language of your choice--to receive HTTP POST requests whenever a user posts to a certain channel, with a trigger word at the beginning of the message, or a combination of both. If the external application responds appropriately to the HTTP request, as response post can be made in the channel where the original post occurred.
A couple key points:
@@ -36,7 +34,7 @@ Which would render in a Mattermost message as follows:
---
### Enabling Outgoing Webhooks
-Outgoing webhooks should be enabled on your Mattermost instance by default, but if they are not you'll need to get your system administrator to enable them. If you are the system administrator you can enable them by doing the following:
+Outgoing webhooks are off by default, and can be enabled by the system administrator. If you are the system administrator you can enable them by doing the following:
1. Login to your Mattermost team account that has the system administrator role.
1. Enable outgoing webhooks from **System Console -> Service Settings**.
diff --git a/docker/1.2/Dockerfile b/docker/1.2/Dockerfile
index cb2b58f53..e00c4e5ca 100644
--- a/docker/1.2/Dockerfile
+++ b/docker/1.2/Dockerfile
@@ -34,7 +34,7 @@ VOLUME /var/lib/mysql
WORKDIR /mattermost
# Copy over files
-ADD https://github.com/mattermost/platform/releases/download/v1.2.0/mattermost.tar.gz /
+ADD https://github.com/mattermost/platform/releases/download/v1.2.1/mattermost.tar.gz /
RUN tar -zxvf /mattermost.tar.gz --strip-components=1 && rm /mattermost.tar.gz
ADD config_docker.json /
ADD docker-entry.sh /
diff --git a/docker/1.2/config_docker.json b/docker/1.2/config_docker.json
index 80e6ab14e..c23a72cd1 100644
--- a/docker/1.2/config_docker.json
+++ b/docker/1.2/config_docker.json
@@ -5,8 +5,8 @@
"SegmentDeveloperKey": "",
"GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
- "EnableIncomingWebhooks": true,
- "EnableOutgoingWebhooks": true,
+ "EnableIncomingWebhooks": false,
+ "EnableOutgoingWebhooks": false,
"EnablePostUsernameOverride": false,
"EnablePostIconOverride": false,
"EnableTesting": false,
diff --git a/docker/dev/config_docker.json b/docker/dev/config_docker.json
index 80e6ab14e..c23a72cd1 100644
--- a/docker/dev/config_docker.json
+++ b/docker/dev/config_docker.json
@@ -5,8 +5,8 @@
"SegmentDeveloperKey": "",
"GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
- "EnableIncomingWebhooks": true,
- "EnableOutgoingWebhooks": true,
+ "EnableIncomingWebhooks": false,
+ "EnableOutgoingWebhooks": false,
"EnablePostUsernameOverride": false,
"EnablePostIconOverride": false,
"EnableTesting": false,
diff --git a/docker/local/config_docker.json b/docker/local/config_docker.json
index 80e6ab14e..c23a72cd1 100644
--- a/docker/local/config_docker.json
+++ b/docker/local/config_docker.json
@@ -5,8 +5,8 @@
"SegmentDeveloperKey": "",
"GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
- "EnableIncomingWebhooks": true,
- "EnableOutgoingWebhooks": true,
+ "EnableIncomingWebhooks": false,
+ "EnableOutgoingWebhooks": false,
"EnablePostUsernameOverride": false,
"EnablePostIconOverride": false,
"EnableTesting": false,
diff --git a/model/version.go b/model/version.go
index 6eae436bc..af99717cd 100644
--- a/model/version.go
+++ b/model/version.go
@@ -12,6 +12,7 @@ import (
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
+ "1.2.1",
"1.2.0",
"1.1.0",
"1.0.0",
diff --git a/store/sql_user_store.go b/store/sql_user_store.go
index d38b5c214..77ff5bfab 100644
--- a/store/sql_user_store.go
+++ b/store/sql_user_store.go
@@ -157,7 +157,7 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha
if count, err := us.GetMaster().Update(user); err != nil {
if IsUniqueConstraintError(err.Error(), "Email", "users_email_teamid_key") {
- result.Err = model.NewAppError("SqlUserStore.Update", "This email is already taken. Please choose another", "user_id="+user.Id+", "+err.Error())
+ result.Err = model.NewAppError("SqlUserStore.Update", "This email is already taken. Please choose another.", "user_id="+user.Id+", "+err.Error())
} else if IsUniqueConstraintError(err.Error(), "Username", "users_username_teamid_key") {
result.Err = model.NewAppError("SqlUserStore.Update", "This username is already taken. Please choose another.", "user_id="+user.Id+", "+err.Error())
} else {
diff --git a/utils/textgeneration.go b/utils/textgeneration.go
index affd65bc1..31b6517b8 100644
--- a/utils/textgeneration.go
+++ b/utils/textgeneration.go
@@ -126,6 +126,13 @@ http://en.wikipedia.org/wiki/Foo
https://vine.co/v/eDeVgbFrt9L
`,
+ `**[7] [Image Test]**
+
+## this *should* display an image
+
+http://37.media.tumblr.com/tumblr_mavsumGGAd1qboaw8o1_500.jpg
+`,
+
/* `**[2] [Username Linking Test]**
I saw @alice--and I said "Hi @alice!" then "What's up @alice?" and then @alice, was totally @alice; she just "@alice"'d me and walked on by. That's @alice...
@alice‽‽
@@ -134,7 +141,7 @@ https://vine.co/v/eDeVgbFrt9L
`**[3] [Mention Highlighting Test]**
`,*/
- `**[4] [Emoji Display Test 1]**
+ `**[8] [Emoji Display Test 1]**
:+1: :-1: :100: :1234: :8ball: :a: :ab: :abc: :abcd: :accept:
:aerial_tramway: :airplane: :alarm_clock: :ambulance: :anchor: :angel: :anger: :angry: :anguished: :ant:
:apple: :aquarius: :aries: :arrow_backward: :arrow_double_down: :arrow_double_up: :arrow_down: :arrow_down_small: :arrow_forward: :arrow_heading_down:
@@ -169,7 +176,7 @@ https://vine.co/v/eDeVgbFrt9L
:fork_and_knife: :fountain: :four: :four_leaf_clover: :fr: :free: :fried_shrimp: :fries: :frog: :frowning:
:fu: :fuelpump: :full_moon: :full_moon_with_face: :game_die: :gb: :gem: :gemini: :ghost: :gift:`,
- `**[5] [Emoji Display Test 2]**
+ `**[9] [Emoji Display Test 2]**
:gift_heart: :girl: :globe_with_meridians: :goat: :goberserk: :godmode: :golf: :grapes: :green_apple: :green_book:
:green_heart: :grey_exclamation: :grey_question: :grimacing: :grin: :grinning: :guardsman: :guitar: :gun: :haircut:
:hamburger: :hammer: :hamster: :hand: :handbag: :hankey: :hash: :hatched_chick: :hatching_chick: :headphones:
@@ -198,7 +205,7 @@ https://vine.co/v/eDeVgbFrt9L
:person_with_blond_hair: :person_with_pouting_face: :phone: :pig: :pig2: :pig_nose: :pill: :pineapple: :pisces: :pizza:
`,
- `**[6] [Emoji Display Test 3]**
+ `**[10] [Emoji Display Test 3]**
:plus1: :point_down: :point_left: :point_right: :point_up: :point_up_2: :police_car: :poodle: :poop: :post_office:
:postal_horn: :postbox: :potable_water: :pouch: :poultry_leg: :pound: :pouting_cat: :pray: :princess: :punch:
:purple_heart: :purse: :pushpin: :put_litter_in_its_place: :question: :rabbit: :rabbit2: :racehorse: :radio: :radio_button:
@@ -231,7 +238,7 @@ https://vine.co/v/eDeVgbFrt9L
Unnamed: :u5272: :u5408: :u55b6: :u6307: :u6708: :u6709: :u6e80: :u7121: :u7533: :u7981: :u7a7a:
`,
- `**[7] [Auto Linking]**
+ `**[11] [Auto Linking]**
#### should be turned into links:
http://example.com
https://example.com
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index 617b4b36c..975ac64dc 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -16,13 +16,13 @@ export default class PostBody extends React.Component {
super(props);
this.receivedYoutubeData = false;
- this.isGifLoading = false;
+ this.isImgLoading = false;
this.handleUserChange = this.handleUserChange.bind(this);
this.parseEmojis = this.parseEmojis.bind(this);
this.createEmbed = this.createEmbed.bind(this);
- this.createGifEmbed = this.createGifEmbed.bind(this);
- this.loadGif = this.loadGif.bind(this);
+ this.createImageEmbed = this.createImageEmbed.bind(this);
+ this.loadImg = this.loadImg.bind(this);
this.createYoutubeEmbed = this.createYoutubeEmbed.bind(this);
const linkData = Utils.extractLinks(this.props.post.message);
@@ -117,8 +117,12 @@ export default class PostBody extends React.Component {
return embed;
}
- if (link.substring(link.length - 4) === '.gif') {
- return this.createGifEmbed(link, this.state.gifLoaded);
+ for (let i = 0; i < Constants.IMAGE_TYPES.length; i++) {
+ const imageType = Constants.IMAGE_TYPES[i];
+ const suffix = link.substring(link.length - (imageType.length + 1));
+ if (suffix === '.' + imageType || suffix === '=' + imageType) {
+ return this.createImageEmbed(link, this.state.imgLoaded);
+ }
}
return null;
@@ -135,29 +139,29 @@ export default class PostBody extends React.Component {
return false;
}
- loadGif(src) {
- if (this.isGifLoading) {
+ loadImg(src) {
+ if (this.isImgLoading) {
return;
}
- this.isGifLoading = true;
+ this.isImgLoading = true;
- const gif = new Image();
- gif.onload = (
+ const img = new Image();
+ img.onload = (
() => {
- this.embed = this.createGifEmbed(src, true);
- this.setState({gifLoaded: true});
+ this.embed = this.createImageEmbed(src, true);
+ this.setState({imgLoaded: true});
}
);
- gif.src = src;
+ img.src = src;
}
- createGifEmbed(link, isLoaded) {
+ createImageEmbed(link, isLoaded) {
if (!isLoaded) {
- this.loadGif(link);
+ this.loadImg(link);
return (
<img
- className='gif-div placeholder'
+ className='img-div placeholder'
height='500px'
/>
);
@@ -165,7 +169,7 @@ export default class PostBody extends React.Component {
return (
<img
- className='gif-div'
+ className='img-div'
src={link}
/>
);
diff --git a/web/react/components/search_autocomplete.jsx b/web/react/components/search_autocomplete.jsx
index d245c6bac..04384203f 100644
--- a/web/react/components/search_autocomplete.jsx
+++ b/web/react/components/search_autocomplete.jsx
@@ -46,7 +46,7 @@ export default class SearchAutocomplete extends React.Component {
componentDidUpdate(prevProps, prevState) {
const content = $(ReactDOM.findDOMNode(this.refs.searchPopover)).find('.popover-content');
- if (this.state.show) {
+ if (this.state.show && this.state.suggestions.length > 0) {
if (!prevState.show) {
content.perfectScrollbar();
content.css('max-height', $(window).height() - 200);
@@ -143,10 +143,12 @@ export default class SearchAutocomplete extends React.Component {
}
getSelection() {
- if (this.state.mode === 'channels') {
- return this.state.suggestions[this.state.selection].name;
- } else if (this.state.mode === 'users') {
- return this.state.suggestions[this.state.selection].username;
+ if (this.state.suggestions.length > 0) {
+ if (this.state.mode === 'channels') {
+ return this.state.suggestions[this.state.selection].name;
+ } else if (this.state.mode === 'users') {
+ return this.state.suggestions[this.state.selection].username;
+ }
}
return '';
diff --git a/web/react/components/team_general_tab.jsx b/web/react/components/team_general_tab.jsx
index 587ef5ec2..a50859489 100644
--- a/web/react/components/team_general_tab.jsx
+++ b/web/react/components/team_general_tab.jsx
@@ -393,7 +393,7 @@ export default class GeneralTab extends React.Component {
</div>
</div>
</div>
- <div className='setting-list__hint'>{'When allowing open invites this code is used as part of the signup process. Changing this code will invalidate the previous open signup link.'}</div>
+ <div className='setting-list__hint'>{'Your Invite Code is used in the URL sent to people to join your team. Regenerating your Invite Code will invalidate the URLs in previous invitations, unless "Allow anyone to sign-up from login page" is enabled.'}</div>
</div>
);
@@ -452,6 +452,7 @@ export default class GeneralTab extends React.Component {
server_error={serverError}
client_error={clientError}
updateSection={this.onUpdateNameSection}
+ extraInfo='Set the name of the team as it appears on your sign-in screen and at the top of the left-hand sidebar.'
/>
);
} else {
diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx
index 75d73e920..dd231b816 100644
--- a/web/react/components/tutorial/tutorial_tip.jsx
+++ b/web/react/components/tutorial/tutorial_tip.jsx
@@ -51,21 +51,22 @@ export default class TutorialTip extends React.Component {
const dots = [];
if (this.props.screens.length > 1) {
for (let i = 0; i < this.props.screens.length; i++) {
+ let className = 'circle';
if (i === this.state.currentScreen) {
- dots.push(
- <div
- className='circle active'
- key={'dotactive' + i}
- />
- );
- } else {
- dots.push(
- <div
- className='circle'
- key={'dotinactive' + i}
- />
- );
+ className += ' active';
}
+
+ dots.push(
+ <a
+ href='#'
+ key={'dotactive' + i}
+ className={className}
+ onClick={(e) => { //eslint-disable-line no-loop-func
+ e.preventDefault();
+ this.setState({currentScreen: i});
+ }}
+ />
+ );
}
}
diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx
index 1bfae6930..b363f0673 100644
--- a/web/react/components/user_settings/user_settings_general.jsx
+++ b/web/react/components/user_settings/user_settings_general.jsx
@@ -1,15 +1,16 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-var UserStore = require('../../stores/user_store.jsx');
-var ErrorStore = require('../../stores/error_store.jsx');
-var SettingItemMin = require('../setting_item_min.jsx');
-var SettingItemMax = require('../setting_item_max.jsx');
-var SettingPicture = require('../setting_picture.jsx');
-var client = require('../../utils/client.jsx');
-var AsyncClient = require('../../utils/async_client.jsx');
-var utils = require('../../utils/utils.jsx');
-var assign = require('object-assign');
+const SettingItemMin = require('../setting_item_min.jsx');
+const SettingItemMax = require('../setting_item_max.jsx');
+const SettingPicture = require('../setting_picture.jsx');
+
+const UserStore = require('../../stores/user_store.jsx');
+const ErrorStore = require('../../stores/error_store.jsx');
+
+const Client = require('../../utils/client.jsx');
+const AsyncClient = require('../../utils/async_client.jsx');
+const Utils = require('../../utils/utils.jsx');
export default class UserSettingsGeneralTab extends React.Component {
constructor(props) {
@@ -32,17 +33,15 @@ export default class UserSettingsGeneralTab extends React.Component {
this.updatePicture = this.updatePicture.bind(this);
this.updateSection = this.updateSection.bind(this);
- this.setupInitialState = this.setupInitialState.bind(this);
-
this.state = this.setupInitialState(props);
}
submitUsername(e) {
e.preventDefault();
- var user = this.props.user;
- var username = this.state.username.trim().toLowerCase();
+ const user = Object.assign({}, this.props.user);
+ const username = this.state.username.trim().toLowerCase();
- var usernameError = utils.isValidUsername(username);
+ const usernameError = Utils.isValidUsername(username);
if (usernameError === 'Cannot use a reserved word as a username.') {
this.setState({clientError: 'This username is reserved, please choose a new one.'});
return;
@@ -52,7 +51,7 @@ export default class UserSettingsGeneralTab extends React.Component {
}
if (user.username === username) {
- this.setState({clientError: 'You must submit a new username'});
+ this.setState({clientError: 'You must submit a new username.', emailError: '', serverError: ''});
return;
}
@@ -63,11 +62,11 @@ export default class UserSettingsGeneralTab extends React.Component {
submitNickname(e) {
e.preventDefault();
- var user = UserStore.getCurrentUser();
- var nickname = this.state.nickname.trim();
+ const user = Object.assign({}, this.props.user);
+ const nickname = this.state.nickname.trim();
if (user.nickname === nickname) {
- this.setState({clientError: 'You must submit a new nickname'});
+ this.setState({clientError: 'You must submit a new nickname.', emailError: '', serverError: ''});
return;
}
@@ -78,12 +77,12 @@ export default class UserSettingsGeneralTab extends React.Component {
submitName(e) {
e.preventDefault();
- var user = UserStore.getCurrentUser();
- var firstName = this.state.firstName.trim();
- var lastName = this.state.lastName.trim();
+ const user = Object.assign({}, this.props.user);
+ const firstName = this.state.firstName.trim();
+ const lastName = this.state.lastName.trim();
if (user.first_name === firstName && user.last_name === lastName) {
- this.setState({clientError: 'You must submit a new first or last name'});
+ this.setState({clientError: 'You must submit a new first or last name.', emailError: '', serverError: ''});
return;
}
@@ -95,21 +94,21 @@ export default class UserSettingsGeneralTab extends React.Component {
submitEmail(e) {
e.preventDefault();
- var user = UserStore.getCurrentUser();
- var email = this.state.email.trim().toLowerCase();
- var confirmEmail = this.state.confirmEmail.trim().toLowerCase();
+ const user = Object.assign({}, this.props.user);
+ const email = this.state.email.trim().toLowerCase();
+ const confirmEmail = this.state.confirmEmail.trim().toLowerCase();
if (user.email === email) {
return;
}
- if (email === '' || !utils.isEmail(email)) {
- this.setState({emailError: 'Please enter a valid email address'});
+ if (email === '' || !Utils.isEmail(email)) {
+ this.setState({emailError: 'Please enter a valid email address.', clientError: '', serverError: ''});
return;
}
if (email !== confirmEmail) {
- this.setState({emailError: 'The new emails you entered do not match'});
+ this.setState({emailError: 'The new emails you entered do not match.', clientError: '', serverError: ''});
return;
}
@@ -117,7 +116,7 @@ export default class UserSettingsGeneralTab extends React.Component {
this.submitUser(user, true);
}
submitUser(user, emailUpdated) {
- client.updateUser(user,
+ Client.updateUser(user,
() => {
this.updateSection('');
AsyncClient.getMe();
@@ -130,13 +129,13 @@ export default class UserSettingsGeneralTab extends React.Component {
}
},
(err) => {
- var state = this.setupInitialState(this.props);
+ let serverError;
if (err.message) {
- state.serverError = err.message;
+ serverError = err.message;
} else {
- state.serverError = err;
+ serverError = err;
}
- this.setState(state);
+ this.setState({serverError, emailError: '', clientError: ''});
}
);
}
@@ -151,10 +150,10 @@ export default class UserSettingsGeneralTab extends React.Component {
return;
}
- var picture = this.state.picture;
+ const picture = this.state.picture;
if (picture.type !== 'image/jpeg' && picture.type !== 'image/png') {
- this.setState({clientError: 'Only JPG or PNG images may be used for profile pictures'});
+ this.setState({clientError: 'Only JPG or PNG images may be used for profile pictures.'});
return;
}
@@ -162,17 +161,17 @@ export default class UserSettingsGeneralTab extends React.Component {
formData.append('image', picture, picture.name);
this.setState({loadingPicture: true});
- client.uploadProfileImage(formData,
- function imageUploadSuccess() {
+ Client.uploadProfileImage(formData,
+ () => {
this.submitActive = false;
AsyncClient.getMe();
window.location.reload();
- }.bind(this),
- function imageUploadFailure(err) {
+ },
+ (err) => {
var state = this.setupInitialState(this.props);
state.serverError = err.message;
this.setState(state);
- }.bind(this)
+ }
);
}
updateUsername(e) {
@@ -205,34 +204,34 @@ export default class UserSettingsGeneralTab extends React.Component {
}
updateSection(section) {
const emailChangeInProgress = this.state.emailChangeInProgress;
- this.setState(assign({}, this.setupInitialState(this.props), {emailChangeInProgress: emailChangeInProgress, clientError: '', serverError: '', emailError: ''}));
+ this.setState(Object.assign({}, this.setupInitialState(this.props), {emailChangeInProgress, clientError: '', serverError: '', emailError: ''}));
this.submitActive = false;
this.props.updateSection(section);
}
setupInitialState(props) {
- var user = props.user;
+ const user = props.user;
return {username: user.username, firstName: user.first_name, lastName: user.last_name, nickname: user.nickname,
email: user.email, confirmEmail: '', picture: null, loadingPicture: false, emailChangeInProgress: false};
}
render() {
- var user = this.props.user;
+ const user = this.props.user;
- var clientError = null;
+ let clientError = null;
if (this.state.clientError) {
clientError = this.state.clientError;
}
- var serverError = null;
+ let serverError = null;
if (this.state.serverError) {
serverError = this.state.serverError;
}
- var emailError = null;
+ let emailError = null;
if (this.state.emailError) {
emailError = this.state.emailError;
}
- var nameSection;
- var inputs = [];
+ let nameSection;
+ const inputs = [];
if (this.props.activeSection === 'name') {
inputs.push(
@@ -298,15 +297,15 @@ export default class UserSettingsGeneralTab extends React.Component {
submit={this.submitName}
server_error={serverError}
client_error={clientError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
extraInfo={extraInfo}
/>
);
} else {
- var fullName = '';
+ let fullName = '';
if (user.first_name && user.last_name) {
fullName = user.first_name + ' ' + user.last_name;
@@ -320,17 +319,17 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingItemMin
title='Full Name'
describe={fullName}
- updateSection={function updateNameSection() {
+ updateSection={() => {
this.updateSection('name');
- }.bind(this)}
+ }}
/>
);
}
- var nicknameSection;
+ let nicknameSection;
if (this.props.activeSection === 'nickname') {
let nicknameLabel = 'Nickname';
- if (utils.isMobile()) {
+ if (Utils.isMobile()) {
nicknameLabel = '';
}
@@ -364,10 +363,10 @@ export default class UserSettingsGeneralTab extends React.Component {
submit={this.submitNickname}
server_error={serverError}
client_error={clientError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
extraInfo={extraInfo}
/>
);
@@ -376,17 +375,17 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingItemMin
title='Nickname'
describe={UserStore.getCurrentUser().nickname}
- updateSection={function updateNicknameSection() {
+ updateSection={() => {
this.updateSection('nickname');
- }.bind(this)}
+ }}
/>
);
}
- var usernameSection;
+ let usernameSection;
if (this.props.activeSection === 'username') {
let usernameLabel = 'Username';
- if (utils.isMobile()) {
+ if (Utils.isMobile()) {
usernameLabel = '';
}
@@ -416,10 +415,10 @@ export default class UserSettingsGeneralTab extends React.Component {
submit={this.submitUsername}
server_error={serverError}
client_error={clientError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
extraInfo={extraInfo}
/>
);
@@ -428,13 +427,14 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingItemMin
title='Username'
describe={UserStore.getCurrentUser().username}
- updateSection={function updateUsernameSection() {
+ updateSection={() => {
this.updateSection('username');
- }.bind(this)}
+ }}
/>
);
}
- var emailSection;
+
+ let emailSection;
if (this.props.activeSection === 'email') {
const emailEnabled = global.window.mm_config.SendEmailNotifications === 'true';
const emailVerificationEnabled = global.window.mm_config.RequireEmailVerification === 'true';
@@ -507,10 +507,10 @@ export default class UserSettingsGeneralTab extends React.Component {
submit={submit}
server_error={serverError}
client_error={emailError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
/>
);
} else {
@@ -534,26 +534,26 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingItemMin
title='Email'
describe={describe}
- updateSection={function updateEmailSection() {
+ updateSection={() => {
this.updateSection('email');
- }.bind(this)}
+ }}
/>
);
}
- var pictureSection;
+ let pictureSection;
if (this.props.activeSection === 'picture') {
pictureSection = (
<SettingPicture
title='Profile Picture'
submit={this.submitPicture}
- src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update + '&' + utils.getSessionIndex()}
+ src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update + '&' + Utils.getSessionIndex()}
server_error={serverError}
client_error={clientError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
picture={this.state.picture}
pictureChange={this.updatePicture}
submitActive={this.submitActive}
@@ -561,17 +561,17 @@ export default class UserSettingsGeneralTab extends React.Component {
/>
);
} else {
- var minMessage = 'Click \'Edit\' to upload an image.';
+ let minMessage = 'Click \'Edit\' to upload an image.';
if (user.last_picture_update) {
- minMessage = 'Image last updated ' + utils.displayDate(user.last_picture_update);
+ minMessage = 'Image last updated ' + Utils.displayDate(user.last_picture_update);
}
pictureSection = (
<SettingItemMin
title='Profile Picture'
describe={minMessage}
- updateSection={function updatePictureSection() {
+ updateSection={() => {
this.updateSection('picture');
- }.bind(this)}
+ }}
/>
);
}
@@ -619,10 +619,10 @@ export default class UserSettingsGeneralTab extends React.Component {
}
UserSettingsGeneralTab.propTypes = {
- user: React.PropTypes.object,
- updateSection: React.PropTypes.func,
- updateTab: React.PropTypes.func,
- activeSection: React.PropTypes.string,
+ user: React.PropTypes.object.isRequired,
+ updateSection: React.PropTypes.func.isRequired,
+ updateTab: React.PropTypes.func.isRequired,
+ activeSection: React.PropTypes.string.isRequired,
closeModal: React.PropTypes.func.isRequired,
collapseModal: React.PropTypes.func.isRequired
};
diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss
index cb140dce6..37626e303 100644
--- a/web/sass-files/sass/partials/_responsive.scss
+++ b/web/sass-files/sass/partials/_responsive.scss
@@ -280,7 +280,7 @@
min-height: 100px;
}
}
- .gif-div {
+ .img-div {
max-width: 100%;
}
.tip-div {
diff --git a/web/sass-files/sass/partials/_videos.scss b/web/sass-files/sass/partials/_videos.scss
index bb36b6223..3f15f8f1e 100644
--- a/web/sass-files/sass/partials/_videos.scss
+++ b/web/sass-files/sass/partials/_videos.scss
@@ -51,7 +51,7 @@
border-left:60px solid rgba(255,255,255,0.4);
}
-.gif-div {
+.img-div {
-moz-force-broken-image-icon: 1;
position:relative;
max-width: 450px;
diff --git a/web/web.go b/web/web.go
index ffc791cb7..02ceb69ba 100644
--- a/web/web.go
+++ b/web/web.go
@@ -989,7 +989,7 @@ func incomingWebhook(c *api.Context, w http.ResponseWriter, r *http.Request) {
}
text := parsedRequest.Text
- if len(text) == 0 {
+ if len(text) == 0 && parsedRequest.Attachments == nil {
c.Err = model.NewAppError("incomingWebhook", "No text specified", "")
return
}