From a3cbe598fb6732be92bdd7e54cedc7737a513c34 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Mon, 27 Jul 2015 10:44:53 -0400 Subject: [PATCH 1/8] Replaced instance of String.prototype.startsWith which only works in browsers that support ES6 --- web/react/components/create_post.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 87895588ee..3275202101 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -32,7 +32,7 @@ module.exports = React.createClass({ post.message = this.state.messageText; // if this is a reply, trim off any carets from the beginning of a message - if (this.state.rootId && post.message.startsWith("^")) { + if (this.state.rootId && post.message[0] === "^") { post.message = post.message.replace(/^\^+\s*/g, ""); } From 4a28e6c5dc7e4256ce48d1d8a7869554afa33dc8 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Mon, 27 Jul 2015 11:30:10 -0800 Subject: [PATCH 2/8] Fixes mm-1502 changing session age to 30 days --- model/session.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/model/session.go b/model/session.go index 9fd3b9ec37..c812f83e23 100644 --- a/model/session.go +++ b/model/session.go @@ -10,9 +10,9 @@ import ( const ( SESSION_TOKEN = "MMSID" - SESSION_TIME_WEB_IN_DAYS = 365 + SESSION_TIME_WEB_IN_DAYS = 30 SESSION_TIME_WEB_IN_SECS = 60 * 60 * 24 * SESSION_TIME_WEB_IN_DAYS - SESSION_TIME_MOBILE_IN_DAYS = 365 + SESSION_TIME_MOBILE_IN_DAYS = 30 SESSION_TIME_MOBILE_IN_SECS = 60 * 60 * 24 * SESSION_TIME_MOBILE_IN_DAYS SESSION_CACHE_IN_SECS = 60 * 10 SESSION_CACHE_SIZE = 10000 From e122b31db1306bf42b1c0265a1f0a57e43153e54 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 27 Jul 2015 17:04:44 -0400 Subject: [PATCH 3/8] fixes some database queries that broke with postgres, fixes the unread/new mesasge issues --- store/sql_channel_store.go | 2 +- store/sql_post_store.go | 12 ++++++------ store/sql_user_store.go | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/store/sql_channel_store.go b/store/sql_channel_store.go index 8961d5d97a..f64558a922 100644 --- a/store/sql_channel_store.go +++ b/store/sql_channel_store.go @@ -120,7 +120,7 @@ func (s SqlChannelStore) Update(channel *model.Channel) StoreChannel { if count, err := s.GetMaster().Update(channel); err != nil { if IsUniqueConstraintError(err.Error(), "Name", "channels_name_teamid_key") { dupChannel := model.Channel{} - s.GetReplica().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId=? AND Name=? AND DeleteAt > 0", channel.TeamId, channel.Name) + s.GetReplica().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name= :Name AND DeleteAt > 0", map[string]interface{}{"TeamId": channel.TeamId, "Name": channel.Name}) if dupChannel.DeleteAt > 0 { result.Err = model.NewAppError("SqlChannelStore.Update", "A channel with that name was previously created", "id="+channel.Id+", "+err.Error()) } else { diff --git a/store/sql_post_store.go b/store/sql_post_store.go index 56c174e4c2..ede69d1255 100644 --- a/store/sql_post_store.go +++ b/store/sql_post_store.go @@ -38,7 +38,7 @@ func NewSqlPostStore(sqlStore *SqlStore) PostStore { func (s SqlPostStore) UpgradeSchemaIfNeeded() { // These execs are for upgrading currently created databases to full utf8mb4 compliance - // Will be removed as seen fit for upgrading + // Will be removed as seen fit for upgrading s.GetMaster().Exec("ALTER TABLE Posts charset=utf8mb4") s.GetMaster().Exec("ALTER TABLE Posts MODIFY COLUMN Message varchar(4000) CHARACTER SET utf8mb4") } @@ -80,14 +80,14 @@ func (s SqlPostStore) Save(post *model.Post) StoreChannel { time := model.GetMillis() if post.Type != model.POST_JOIN_LEAVE { - s.GetMaster().Exec("UPDATE Channels SET LastPostAt = ?, TotalMsgCount = TotalMsgCount + 1 WHERE Id = ?", time, post.ChannelId) + s.GetMaster().Exec("UPDATE Channels SET LastPostAt = :LastPostAt, TotalMsgCount = TotalMsgCount + 1 WHERE Id = :ChannelId", map[string]interface{}{"LastPostAt": time, "ChannelId": post.ChannelId}) } else { // don't update TotalMsgCount for unimportant messages so that the channel isn't marked as unread - s.GetMaster().Exec("UPDATE Channels SET LastPostAt = ? WHERE Id = ?", time, post.ChannelId) + s.GetMaster().Exec("UPDATE Channels SET LastPostAt = :LastPostAt WHERE Id = :ChannelId", map[string]interface{}{"LastPostAt": time, "ChannelId": post.ChannelId}) } if len(post.RootId) > 0 { - s.GetMaster().Exec("UPDATE Posts SET UpdateAt = ? WHERE Id = ?", time, post.RootId) + s.GetMaster().Exec("UPDATE Posts SET UpdateAt = :UpdateAt WHERE Id = :RootId", map[string]interface{}{"UpdateAt": time, "RootId": post.RootId}) } result.Data = post @@ -126,10 +126,10 @@ func (s SqlPostStore) Update(oldPost *model.Post, newMessage string, newHashtags result.Err = model.NewAppError("SqlPostStore.Update", "We couldn't update the Post", "id="+editPost.Id+", "+err.Error()) } else { time := model.GetMillis() - s.GetMaster().Exec("UPDATE Channels SET LastPostAt = ? WHERE Id = ?", time, editPost.ChannelId) + s.GetMaster().Exec("UPDATE Channels SET LastPostAt = :LastPostAt WHERE Id = :ChannelId", map[string]interface{}{"LastPostAt": time, "ChannelId": editPost.ChannelId}) if len(editPost.RootId) > 0 { - s.GetMaster().Exec("UPDATE Posts SET UpdateAt = ? WHERE Id = ?", time, editPost.RootId) + s.GetMaster().Exec("UPDATE Posts SET UpdateAt = :UpdateAt WHERE Id = :RootId", map[string]interface{}{"UpdateAt": time, "RootId": editPost.RootId}) } // mark the old post as deleted diff --git a/store/sql_user_store.go b/store/sql_user_store.go index 0228fa3085..cd63e95b83 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -184,7 +184,7 @@ func (us SqlUserStore) UpdateLastPictureUpdate(userId string) StoreChannel { curTime := model.GetMillis() - if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = ?, UpdateAt = ? WHERE Id = ?", curTime, curTime, userId); err != nil { + if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = :Time, UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil { result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "We couldn't update the update_at", "user_id="+userId) } else { result.Data = userId From c9459feb59a3dc05de229aea7652b0a726ac98bf Mon Sep 17 00:00:00 2001 From: nickago Date: Mon, 13 Jul 2015 13:18:50 -0700 Subject: [PATCH 4/8] When removed from a channel, user is sent back to town square and that channel is removed from their sidebar --- api/channel.go | 4 ++++ model/message.go | 1 + web/react/components/sidebar.jsx | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/api/channel.go b/api/channel.go index 4d8dbad099..a05aa0a3c7 100644 --- a/api/channel.go +++ b/api/channel.go @@ -710,6 +710,10 @@ func removeChannelMember(c *Context, w http.ResponseWriter, r *http.Request) { return } + message := model.NewMessage(c.Session.TeamId, "", userId, model.ACTION_USER_REMOVED) + message.Add("channel_id",id) + PublishAndForget(message) + c.LogAudit("name=" + channel.Name + " user_id=" + userId) result := make(map[string]string) diff --git a/model/message.go b/model/message.go index 52ee69e8f9..ec4817b2a2 100644 --- a/model/message.go +++ b/model/message.go @@ -16,6 +16,7 @@ const ( ACTION_VIEWED = "viewed" ACTION_NEW_USER = "new_user" ACTION_USER_ADDED = "user_added" + ACTION_USER_REMOVED = "user_removed" ) type Message struct { diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 3cf67e410e..ed75e51cfe 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -197,6 +197,14 @@ module.exports = React.createClass({ if (UserStore.getCurrentId() === msg.user_id) { AsyncClient.getChannels(true); } + } else if(msg.action === "user_removed") { + if(msg.user_id === UserStore.getCurrentId()) { + AsyncClient.getChannels(true); + + if(msg.props.channel_id === ChannelStore.getCurrentId()) { + window.location.reload(); + } + } } }, updateTitle: function() { From ed70db18611331de99b2a86b580947e56d0cb7e5 Mon Sep 17 00:00:00 2001 From: nickago Date: Wed, 22 Jul 2015 15:12:50 -0700 Subject: [PATCH 5/8] When user is removed, a modal appears, which on closing redirects the user to town square. --- api/channel.go | 1 + .../components/removed_from_channel_modal.jsx | 45 +++++++++++++++++++ web/react/components/sidebar.jsx | 9 +++- web/react/pages/channel.jsx | 6 +++ web/templates/channel.html | 1 + 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 web/react/components/removed_from_channel_modal.jsx diff --git a/api/channel.go b/api/channel.go index a05aa0a3c7..123fd8a355 100644 --- a/api/channel.go +++ b/api/channel.go @@ -712,6 +712,7 @@ func removeChannelMember(c *Context, w http.ResponseWriter, r *http.Request) { message := model.NewMessage(c.Session.TeamId, "", userId, model.ACTION_USER_REMOVED) message.Add("channel_id",id) + message.Add("remover", c.Session.UserId) PublishAndForget(message) c.LogAudit("name=" + channel.Name + " user_id=" + userId) diff --git a/web/react/components/removed_from_channel_modal.jsx b/web/react/components/removed_from_channel_modal.jsx new file mode 100644 index 0000000000..3a5a58d5e6 --- /dev/null +++ b/web/react/components/removed_from_channel_modal.jsx @@ -0,0 +1,45 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var ChannelStore = require('../stores/channel_store.jsx'); +var UserStore = require('../stores/user_store.jsx'); +var utils = require('../utils/utils.jsx'); + +module.exports = React.createClass({ + handleClose: function() { + var townSquare = ChannelStore.getByName("town-square"); + utils.switchChannel(townSquare); + }, + componentDidMount: function() { + $(this.getDOMNode()).on('hidden.bs.modal',this.handleClose); + }, + componentWillUnmount: function() { + $(this.getDOMNode()).off('hidden.bs.modal',this.handleClose); + }, + render: function() { + currentUser = UserStore.getCurrentUser(); + + if (currentUser != null) { + return ( + + ); + } else { + return
; + } + } +}); \ No newline at end of file diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index ed75e51cfe..a29c6a9030 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -201,8 +201,13 @@ module.exports = React.createClass({ if(msg.user_id === UserStore.getCurrentId()) { AsyncClient.getChannels(true); - if(msg.props.channel_id === ChannelStore.getCurrentId()) { - window.location.reload(); + if(msg.props.channel_id === ChannelStore.getCurrentId() && $('#removed_from_channel').length > 0) { + var channelName = ChannelStore.getCurrent().display_name; + var curUser = UserStore.getProfile(msg.props.remover).username; + $('#removed_from_channel').find('.modal-title').text("Removed from " + channelName); + $('#removed_from_channel').find('.modal-body').children().text(curUser + " removed you from " + channelName); + + $('#removed_from_channel').modal('show'); } } } diff --git a/web/react/pages/channel.jsx b/web/react/pages/channel.jsx index cc78df120a..90d90b29f6 100644 --- a/web/react/pages/channel.jsx +++ b/web/react/pages/channel.jsx @@ -34,6 +34,7 @@ var MentionList = require('../components/mention_list.jsx'); var ChannelInfoModal = require('../components/channel_info_modal.jsx'); var AccessHistoryModal = require('../components/access_history_modal.jsx'); var ActivityLogModal = require('../components/activity_log_modal.jsx'); +var RemovedFromChannelModal = require('../components/removed_from_channel_modal.jsx') var Constants = require('../utils/constants.jsx'); @@ -217,4 +218,9 @@ global.window.setup_channel_page = function(team_name, team_type, team_id, chann document.getElementById('activity_log_modal') ); + React.render( + , + document.getElementById('removed_from_channel_modal') + ); + }; diff --git a/web/templates/channel.html b/web/templates/channel.html index 8e856032d5..6325069eee 100644 --- a/web/templates/channel.html +++ b/web/templates/channel.html @@ -47,6 +47,7 @@
+
From 2d8b81170ba80a68865dc6305186a66099d418a2 Mon Sep 17 00:00:00 2001 From: nickago Date: Fri, 24 Jul 2015 09:03:43 -0700 Subject: [PATCH 6/8] Added precautions to avoid incorrect data display to the user by clearing modal after every close --- web/react/components/removed_from_channel_modal.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/react/components/removed_from_channel_modal.jsx b/web/react/components/removed_from_channel_modal.jsx index 3a5a58d5e6..b815e5d1d6 100644 --- a/web/react/components/removed_from_channel_modal.jsx +++ b/web/react/components/removed_from_channel_modal.jsx @@ -9,6 +9,9 @@ module.exports = React.createClass({ handleClose: function() { var townSquare = ChannelStore.getByName("town-square"); utils.switchChannel(townSquare); + + $(this.refs.title.getDOMNode()).text("") + $(this.refs.body.getDOMNode()).text(""); }, componentDidMount: function() { $(this.getDOMNode()).on('hidden.bs.modal',this.handleClose); @@ -26,10 +29,10 @@ module.exports = React.createClass({
-

+

-

+

From da6d3556e83b54472f1caa7777ce223988c0655c Mon Sep 17 00:00:00 2001 From: nickago Date: Mon, 27 Jul 2015 13:44:54 -0700 Subject: [PATCH 7/8] Changed from Jquery style modal modification to using browserStore --- .../components/removed_from_channel_modal.jsx | 26 +++++++++++++++---- web/react/components/sidebar.jsx | 9 ++++--- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/web/react/components/removed_from_channel_modal.jsx b/web/react/components/removed_from_channel_modal.jsx index b815e5d1d6..a8889a92a4 100644 --- a/web/react/components/removed_from_channel_modal.jsx +++ b/web/react/components/removed_from_channel_modal.jsx @@ -3,24 +3,40 @@ var ChannelStore = require('../stores/channel_store.jsx'); var UserStore = require('../stores/user_store.jsx'); +var BrowserStore = require('../stores/browser_store.jsx') var utils = require('../utils/utils.jsx'); module.exports = React.createClass({ + handleShow: function() { + var newState = {}; + if(BrowserStore.getItem("channel-removed-state")) { + newState = BrowserStore.getItem("channel-removed-state"); + BrowserStore.removeItem("channel-removed-state"); + } + + this.setState(newState); + }, handleClose: function() { var townSquare = ChannelStore.getByName("town-square"); utils.switchChannel(townSquare); - $(this.refs.title.getDOMNode()).text("") - $(this.refs.body.getDOMNode()).text(""); + this.setState({channelName: "", remover: ""}) }, componentDidMount: function() { + $(this.getDOMNode()).on('show.bs.modal',this.handleShow); $(this.getDOMNode()).on('hidden.bs.modal',this.handleClose); }, componentWillUnmount: function() { + $(this.getDOMNode()).off('show.bs.modal',this.handleShow); $(this.getDOMNode()).off('hidden.bs.modal',this.handleClose); }, + getInitialState: function() { + return {channelName: "", remover: ""} + }, render: function() { - currentUser = UserStore.getCurrentUser(); + var currentUser = UserStore.getCurrentUser(); + var channelName = this.state.channelName ? this.state.channelName : "the channel" + var remover = this.state.remover ? this.state.remover : "Someone" if (currentUser != null) { return ( @@ -29,10 +45,10 @@ module.exports = React.createClass({
-

+

Removed from {channelName}

-

+

{remover} removed you from {channelName}

diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index a29c6a9030..5b8d6c5429 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -7,6 +7,7 @@ var AsyncClient = require('../utils/async_client.jsx'); var SocketStore = require('../stores/socket_store.jsx'); var UserStore = require('../stores/user_store.jsx'); var TeamStore = require('../stores/team_store.jsx'); +var BrowserStore = require('../stores/browser_store.jsx') var utils = require('../utils/utils.jsx'); var SidebarHeader = require('./sidebar_header.jsx'); var SearchBox = require('./search_bar.jsx'); @@ -202,11 +203,11 @@ module.exports = React.createClass({ AsyncClient.getChannels(true); if(msg.props.channel_id === ChannelStore.getCurrentId() && $('#removed_from_channel').length > 0) { - var channelName = ChannelStore.getCurrent().display_name; - var curUser = UserStore.getProfile(msg.props.remover).username; - $('#removed_from_channel').find('.modal-title').text("Removed from " + channelName); - $('#removed_from_channel').find('.modal-body').children().text(curUser + " removed you from " + channelName); + var sentState = {}; + sentState.channelName = ChannelStore.getCurrent().display_name; + sentState.remover = UserStore.getProfile(msg.props.remover).username; + BrowserStore.setItem('channel-removed-state',sentState); $('#removed_from_channel').modal('show'); } } From 883d303be5f0bb261c120f71f10f4af34d2fa531 Mon Sep 17 00:00:00 2001 From: it33 Date: Mon, 27 Jul 2015 22:32:47 -0700 Subject: [PATCH 8/8] Removed version number from dev build README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 65a3e7c663..f0857e99de 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -**Mattermost Preview** +**Mattermost Alpha** **Team Communication Service** -**Version 0.5.0** +**Development Build** About Mattermost @@ -22,7 +22,7 @@ Learn More Installing the Mattermost ========================= -You're installing "Mattermost Preview", a pre-released 0.5.0 version intended for an early look at what we're building. While SpinPunch runs this version internally, it's not recommended for production deployments since we can't guarantee API stability or backwards compatibility until our 1.0.0 version release. +You're installing "Mattermost Alpha", a pre-released version intended for an early look at what we're building. While SpinPunch runs this version internally, it's not recommended for production deployments since we can't guarantee API stability or backwards compatibility until our production release. That said, any issues at all, please let us know on the Mattermost forum at: http://forum.mattermost.org