summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--docker/1.1/Dockerrun.aws.zipbin710 -> 0 bytes
-rw-r--r--docker/1.3/Dockerfile (renamed from docker/1.1/Dockerfile)2
-rw-r--r--docker/1.3/Dockerrun.aws.zipbin0 -> 867 bytes
-rw-r--r--docker/1.3/Dockerrun.aws/.ebextensions/01_files.config (renamed from docker/1.1/Dockerrun.aws/.ebextensions/01_files.config)0
-rwxr-xr-xdocker/1.3/Dockerrun.aws/Dockerrun.aws.json (renamed from docker/1.1/Dockerrun.aws/Dockerrun.aws.json)2
-rw-r--r--docker/1.3/README.md23
-rw-r--r--docker/1.3/config_docker.json (renamed from docker/1.1/config_docker.json)12
-rwxr-xr-xdocker/1.3/docker-entry.sh (renamed from docker/1.1/docker-entry.sh)0
-rw-r--r--model/version.go1
-rw-r--r--store/sql_post_store.go2
-rw-r--r--web/react/components/post.jsx2
-rw-r--r--web/react/stores/post_store.jsx121
-rw-r--r--web/react/stores/socket_store.jsx8
-rw-r--r--web/react/utils/async_client.jsx15
-rw-r--r--web/react/utils/utils.jsx5
16 files changed, 138 insertions, 57 deletions
diff --git a/.travis.yml b/.travis.yml
index 7e54d3335..c88267206 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,6 +17,8 @@ addons:
- 127.0.0.1 dockerhost
before_deploy:
- sudo rm -rf dist/mattermost
+ - sudo chown `whoami` dist/mattermost.tar.gz
+ - sudo chmod 777 dist/mattermost.tar.gz
- rvm 1.9.3 do gem install mime-types -v 2.6.2
deploy:
# Github releases, builds only on tags
diff --git a/docker/1.1/Dockerrun.aws.zip b/docker/1.1/Dockerrun.aws.zip
deleted file mode 100644
index 945168a71..000000000
--- a/docker/1.1/Dockerrun.aws.zip
+++ /dev/null
Binary files differ
diff --git a/docker/1.1/Dockerfile b/docker/1.3/Dockerfile
index 92bac6a04..55b69673a 100644
--- a/docker/1.1/Dockerfile
+++ b/docker/1.3/Dockerfile
@@ -34,7 +34,7 @@ VOLUME /var/lib/mysql
WORKDIR /mattermost
# Copy over files
-ADD https://github.com/mattermost/platform/releases/download/v1.1.0/mattermost.tar.gz /
+ADD https://github.com/mattermost/platform/releases/download/v1.3.0-rc1/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.3/Dockerrun.aws.zip b/docker/1.3/Dockerrun.aws.zip
new file mode 100644
index 000000000..dd201d990
--- /dev/null
+++ b/docker/1.3/Dockerrun.aws.zip
Binary files differ
diff --git a/docker/1.1/Dockerrun.aws/.ebextensions/01_files.config b/docker/1.3/Dockerrun.aws/.ebextensions/01_files.config
index 7f40a8b34..7f40a8b34 100644
--- a/docker/1.1/Dockerrun.aws/.ebextensions/01_files.config
+++ b/docker/1.3/Dockerrun.aws/.ebextensions/01_files.config
diff --git a/docker/1.1/Dockerrun.aws/Dockerrun.aws.json b/docker/1.3/Dockerrun.aws/Dockerrun.aws.json
index 042e79bd3..d4027e67c 100755
--- a/docker/1.1/Dockerrun.aws/Dockerrun.aws.json
+++ b/docker/1.3/Dockerrun.aws/Dockerrun.aws.json
@@ -1,7 +1,7 @@
{
"AWSEBDockerrunVersion": "1",
"Image": {
- "Name": "mattermost/platform:1.1",
+ "Name": "mattermost/platform:1.3",
"Update": "true"
},
"Ports": [
diff --git a/docker/1.3/README.md b/docker/1.3/README.md
new file mode 100644
index 000000000..f737a1554
--- /dev/null
+++ b/docker/1.3/README.md
@@ -0,0 +1,23 @@
+Mattermost
+==========
+
+http:/mattermost.org
+
+Mattermost is an open-source team communication service. It brings team messaging and file sharing into one place, accessible across PCs and phones, with archiving and search.
+
+Installing Mattermost
+=====================
+
+To run an instance of the latest version of mattermost on your local machine you can run:
+
+`docker run --name mattermost-dev -d --publish 8065:80 mattermost/platform`
+
+To update this image to the latest version you can run:
+
+`docker pull mattermost/platform`
+
+To run an instance of the latest code from the master branch on GitHub you can run:
+
+`docker run --name mattermost-dev -d --publish 8065:80 mattermost/platform:dev`
+
+Any questions, please visit http://forum.mattermost.org
diff --git a/docker/1.1/config_docker.json b/docker/1.3/config_docker.json
index 653b6ffd7..a35abb9da 100644
--- a/docker/1.1/config_docker.json
+++ b/docker/1.3/config_docker.json
@@ -5,7 +5,8 @@
"SegmentDeveloperKey": "",
"GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false,
- "EnableIncomingWebhooks": true,
+ "EnableIncomingWebhooks": false,
+ "EnableOutgoingWebhooks": false,
"EnablePostUsernameOverride": false,
"EnablePostIconOverride": false,
"EnableTesting": false,
@@ -16,7 +17,9 @@
"MaxUsersPerTeam": 50,
"EnableTeamCreation": true,
"EnableUserCreation": true,
- "RestrictCreationToDomains": ""
+ "RestrictCreationToDomains": "",
+ "RestrictTeamNames": true,
+ "EnableTeamListing": false
},
"SqlSettings": {
"DriverName": "mysql",
@@ -65,9 +68,8 @@
"ConnectionSecurity": "",
"InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9YoS",
"PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5eL",
- "ApplePushServer": "",
- "ApplePushCertPublic": "",
- "ApplePushCertPrivate": ""
+ "SendPushNotifications": false,
+ "PushNotificationServer": ""
},
"RateLimitSettings": {
"EnableRateLimiter": true,
diff --git a/docker/1.1/docker-entry.sh b/docker/1.3/docker-entry.sh
index 6bd2a1263..6bd2a1263 100755
--- a/docker/1.1/docker-entry.sh
+++ b/docker/1.3/docker-entry.sh
diff --git a/model/version.go b/model/version.go
index af99717cd..5e41a28d1 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.3.0",
"1.2.1",
"1.2.0",
"1.1.0",
diff --git a/store/sql_post_store.go b/store/sql_post_store.go
index be770c09e..40dca9930 100644
--- a/store/sql_post_store.go
+++ b/store/sql_post_store.go
@@ -38,8 +38,6 @@ func NewSqlPostStore(sqlStore *SqlStore) PostStore {
}
func (s SqlPostStore) UpgradeSchemaIfNeeded() {
- s.RemoveColumnIfExists("Posts", "ImgCount") // remove after 1.3 release
- s.GetMaster().Exec(`UPDATE Preferences SET Type = :NewType WHERE Type = :CurrentType`, map[string]string{"NewType": model.POST_JOIN_LEAVE, "CurrentType": "join_leave"}) // remove after 1.3 release
}
func (s SqlPostStore) CreateIndexesIfNotExists() {
diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx
index 695d7daef..b7711ca29 100644
--- a/web/react/components/post.jsx
+++ b/web/react/components/post.jsx
@@ -179,7 +179,7 @@ export default class Post extends React.Component {
}
let profilePic = null;
- if (!this.props.hideProfilePic) {
+ if (!this.props.hideProfilePic && post.user_id !== '0') {
let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp + '&' + utils.getSessionIndex();
if (post.props && post.props.from_webhook && global.window.mm_config.EnablePostIconOverride === 'true') {
if (post.props.override_icon_url) {
diff --git a/web/react/stores/post_store.jsx b/web/react/stores/post_store.jsx
index 2212edadb..8fedba9ce 100644
--- a/web/react/stores/post_store.jsx
+++ b/web/react/stores/post_store.jsx
@@ -7,6 +7,9 @@ import EventEmitter from 'events';
import ChannelStore from '../stores/channel_store.jsx';
import BrowserStore from '../stores/browser_store.jsx';
import UserStore from '../stores/user_store.jsx';
+import SocketStore from '../stores/socket_store.jsx';
+
+import * as Utils from '../utils/utils.jsx';
import Constants from '../utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
@@ -53,11 +56,14 @@ class PostStoreClass extends EventEmitter {
this.storePost = this.storePost.bind(this);
this.storeFocusedPost = this.storeFocusedPost.bind(this);
this.checkBounds = this.checkBounds.bind(this);
+ this.addEphemeralPost = this.addEphemeralPost.bind(this);
this.clearFocusedPost = this.clearFocusedPost.bind(this);
this.clearChannelVisibility = this.clearChannelVisibility.bind(this);
this.removePost = this.removePost.bind(this);
+ this.deletePost = this.deletePost.bind(this);
+ this.clearUnseenDeletedPosts = this.clearUnseenDeletedPosts.bind(this);
this.getPendingPosts = this.getPendingPosts.bind(this);
this.storePendingPost = this.storePendingPost.bind(this);
@@ -65,10 +71,6 @@ class PostStoreClass extends EventEmitter {
this.clearPendingPosts = this.clearPendingPosts.bind(this);
this.updatePendingPost = this.updatePendingPost.bind(this);
- this.storeUnseenDeletedPost = this.storeUnseenDeletedPost.bind(this);
- this.getUnseenDeletedPosts = this.getUnseenDeletedPosts.bind(this);
- this.clearUnseenDeletedPosts = this.clearUnseenDeletedPosts.bind(this);
-
// These functions are bad and work should be done to remove this system when the RHS dies
this.storeSelectedPost = this.storeSelectedPost.bind(this);
this.getSelectedPost = this.getSelectedPost.bind(this);
@@ -211,28 +213,6 @@ class PostStoreClass extends EventEmitter {
postList.order = this.postsInfo[id].pendingPosts.order.concat(postList.order);
}
- // Add deleted posts
- if (this.postsInfo[id].hasOwnProperty('deletedPosts')) {
- Object.assign(postList.posts, this.postsInfo[id].deletedPosts);
-
- for (const postID in this.postsInfo[id].deletedPosts) {
- if (this.postsInfo[id].deletedPosts.hasOwnProperty(postID)) {
- postList.order.push(postID);
- }
- }
-
- // Merge would be faster
- postList.order.sort((a, b) => {
- if (postList.posts[a].create_at > postList.posts[b].create_at) {
- return -1;
- }
- if (postList.posts[a].create_at < postList.posts[b].create_at) {
- return 1;
- }
- return 0;
- });
- }
-
return postList;
}
@@ -439,33 +419,88 @@ class PostStoreClass extends EventEmitter {
this.emitChange();
}
- storeUnseenDeletedPost(post) {
- let posts = this.getUnseenDeletedPosts(post.channel_id);
+ addEphemeralPost(post, disableNotification, autoDeleteTimer) {
+ if (!post.channel_id) {
+ return null;
+ }
- if (!posts) {
- posts = {};
+ const member = ChannelStore.getMember(post.channel_id);
+ if (!member) {
+ return null;
}
- post.message = '(message deleted)';
- post.state = Constants.POST_DELETED;
- post.filenames = [];
+ const timestamp = Utils.getTimestamp();
+ const newPost = $.extend(true, {
+ id: Utils.generateId(),
+ user_id: '0',
+ create_at: timestamp,
+ update_at: timestamp,
+ filenames: [],
+ props: {}
+ }, post);
+
+ if (disableNotification) {
+ newPost.props.disable_notification = true;
+ }
+
+ SocketStore.handleMessage({
+ user_id: newPost.user_id,
+ channel_id: newPost.channel_id,
+ action: Constants.SocketEvents.POSTED,
+ props: {
+ post: JSON.stringify(newPost),
+ ephemeral: true
+ }
+ });
+
+ if (autoDeleteTimer) {
+ setTimeout(() => {
+ ChannelStore.resetCounts(newPost.channel_id);
+ this.removePost(newPost);
+ this.emitChange();
+ ChannelStore.emitChange();
+ }, autoDeleteTimer);
+ }
- posts[post.id] = post;
- this.postsInfo[post.channel_id].deletedPosts = posts;
+ return newPost;
}
- getUnseenDeletedPosts(channelId) {
- if (this.postsInfo.hasOwnProperty(channelId)) {
- return this.postsInfo[channelId].deletedPosts;
+ deletePost(post) {
+ const newId = Utils.generateId();
+ const index = this.postsInfo[post.channel_id].postList.order.indexOf(post.id);
+ this.postsInfo[post.channel_id].postList.order.splice(index, 1, newId);
+ this.removePost(post);
+
+ post.id = newId;
+ post.message = '(message deleted)';
+ post.state = Constants.POST_DELETED;
+ post.filenames = [];
+ if (post.props && post.props.attachments) {
+ Reflect.deleteProperty(post.props, 'attachments');
}
- return null;
+ Utils.defer(() => {
+ this.addEphemeralPost(post, true);
+ });
}
clearUnseenDeletedPosts(channelId) {
- if (this.postsInfo.hasOwnProperty(channelId)) {
- Reflect.deleteProperty(this.postsInfo[channelId], 'deletedPosts');
+ const postList = this.postsInfo[channelId] && this.postsInfo[channelId].postList;
+ if (!postList) {
+ return;
+ }
+
+ const member = ChannelStore.getMember(channelId);
+ if (!member) {
+ return;
}
+
+ Object.keys(postList.posts).forEach((postId) => {
+ const post = postList.posts[postId];
+ if (post.state === Constants.POST_DELETED && post.create_at < member.last_viewed_at) {
+ this.removePost(post);
+ }
+ });
}
storeSelectedPost(postList) {
@@ -618,9 +653,7 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => {
PostStore.jumpPostsViewToBottom();
break;
case ActionTypes.POST_DELETED:
- PostStore.storeUnseenDeletedPost(action.post);
- PostStore.removePost(action.post);
- PostStore.emitChange();
+ PostStore.deletePost(action.post);
break;
case ActionTypes.RECIEVED_POST_SELECTED:
PostStore.storeSelectedPost(action.post_list);
diff --git a/web/react/stores/socket_store.jsx b/web/react/stores/socket_store.jsx
index d5aed40cf..87467b02f 100644
--- a/web/react/stores/socket_store.jsx
+++ b/web/react/stores/socket_store.jsx
@@ -160,11 +160,15 @@ function handleNewPostEvent(msg) {
AsyncClient.updateLastViewedAt();
}
} else if (UserStore.getCurrentId() !== msg.user_id || post.type !== Constants.POST_TYPE_JOIN_LEAVE) {
- AsyncClient.getChannel(msg.channel_id);
+ if (msg.props.ephemeral) {
+ AsyncClient.getChannelAndAddUnreadMessages(msg.channel_id, 1);
+ } else {
+ AsyncClient.getChannel(msg.channel_id);
+ }
}
// Send desktop notification
- if ((UserStore.getCurrentId() !== msg.user_id || post.props.from_webhook === 'true') && !Utils.isSystemMessage(post)) {
+ if ((UserStore.getCurrentId() !== msg.user_id || post.props.from_webhook === 'true') && !Utils.isSystemMessage(post) && !post.props.disable_notification) {
const msgProps = msg.props;
let mentions = [];
diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx
index 88b5aa739..9cdbd73a4 100644
--- a/web/react/utils/async_client.jsx
+++ b/web/react/utils/async_client.jsx
@@ -82,7 +82,7 @@ export function getChannels(checkVersion) {
);
}
-export function getChannel(id) {
+export function getChannelAndAddUnreadMessages(id, unreadCount) {
if (isCallInProgress('getChannel' + id)) {
return;
}
@@ -97,6 +97,7 @@ export function getChannel(id) {
return;
}
+ data.channel.total_msg_count += (unreadCount || 0);
AppDispatcher.handleServerAction({
type: ActionTypes.RECIEVED_CHANNEL,
channel: data.channel,
@@ -110,6 +111,10 @@ export function getChannel(id) {
);
}
+export function getChannel(id) {
+ getChannelAndAddUnreadMessages(id, 0);
+}
+
export function updateLastViewedAt(id) {
let channelId;
if (id) {
@@ -131,6 +136,14 @@ export function updateLastViewedAt(id) {
channelId,
() => {
callTracker.updateLastViewed = 0;
+
+ var channel = ChannelStore.get(channelId);
+ var member = ChannelStore.getMember(channelId);
+ if (channel && member) {
+ member.msg_count = channel.total_msg_count;
+ member.last_viewed_at = utils.getTimestamp();
+ ChannelStore.setChannelMember(member);
+ }
},
(err) => {
callTracker.updateLastViewed = 0;
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index c2e4276b0..13c7f961a 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -1254,3 +1254,8 @@ export function isFeatureEnabled(feature) {
export function isSystemMessage(post) {
return post.type && (post.type.lastIndexOf(Constants.SYSTEM_MESSAGE_PREFIX) === 0);
}
+
+// convenience method to dispatch an event in JS' next event cycle
+export function defer(fn) {
+ setTimeout(fn, 0);
+}