diff options
-rw-r--r-- | api/channel.go | 36 | ||||
-rw-r--r-- | api/channel_test.go | 21 | ||||
-rw-r--r-- | model/channel_data.go | 43 | ||||
-rw-r--r-- | model/client.go | 9 | ||||
-rw-r--r-- | web/react/components/edit_channel_modal.jsx | 2 | ||||
-rw-r--r-- | web/react/components/sidebar.jsx | 12 | ||||
-rw-r--r-- | web/react/stores/channel_store.jsx | 37 | ||||
-rw-r--r-- | web/react/utils/async_client.jsx | 24 | ||||
-rw-r--r-- | web/react/utils/client.jsx | 15 | ||||
-rw-r--r-- | web/react/utils/constants.jsx | 1 |
10 files changed, 190 insertions, 10 deletions
diff --git a/api/channel.go b/api/channel.go index 803274d32..a3de30377 100644 --- a/api/channel.go +++ b/api/channel.go @@ -23,6 +23,7 @@ func InitChannel(r *mux.Router) { sr.Handle("/update", ApiUserRequired(updateChannel)).Methods("POST") sr.Handle("/update_desc", ApiUserRequired(updateChannelDesc)).Methods("POST") sr.Handle("/update_notify_level", ApiUserRequired(updateNotifyLevel)).Methods("POST") + sr.Handle("/{id:[A-Za-z0-9]+}/", ApiUserRequired(getChannel)).Methods("GET") sr.Handle("/{id:[A-Za-z0-9]+}/extra_info", ApiUserRequired(getChannelExtraInfo)).Methods("GET") sr.Handle("/{id:[A-Za-z0-9]+}/join", ApiUserRequired(joinChannel)).Methods("POST") sr.Handle("/{id:[A-Za-z0-9]+}/leave", ApiUserRequired(leaveChannel)).Methods("POST") @@ -275,7 +276,7 @@ func updateChannelDesc(c *Context, w http.ResponseWriter, r *http.Request) { func getChannels(c *Context, w http.ResponseWriter, r *http.Request) { - // user is already in the newtork + // user is already in the team if result := <-Srv.Store.Channel().GetChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil { if result.Err.Message == "No channels were found" { @@ -300,7 +301,7 @@ func getChannels(c *Context, w http.ResponseWriter, r *http.Request) { func getMoreChannels(c *Context, w http.ResponseWriter, r *http.Request) { - // user is already in the newtork + // user is already in the team if result := <-Srv.Store.Channel().GetMoreChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil { c.Err = result.Err @@ -548,6 +549,37 @@ func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.MapToJson(result))) } +func getChannel(c *Context, w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + id := params["id"] + + //pchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, id, c.Session.UserId) + cchan := Srv.Store.Channel().Get(id) + cmchan := Srv.Store.Channel().GetMember(id, c.Session.UserId) + + if cresult := <-cchan; cresult.Err != nil { + c.Err = cresult.Err + return + } else if cmresult := <-cmchan; cmresult.Err != nil { + c.Err = cmresult.Err + return + } else { + data := &model.ChannelData{} + data.Channel = cresult.Data.(*model.Channel) + member := cmresult.Data.(model.ChannelMember) + data.Member = &member + + if HandleEtag(data.Etag(), w, r) { + return + } else { + w.Header().Set(model.HEADER_ETAG_SERVER, data.Etag()) + w.Header().Set("Expires", "-1") + w.Write([]byte(data.ToJson())) + } + } + +} + func getChannelExtraInfo(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) diff --git a/api/channel_test.go b/api/channel_test.go index d4fb11bd8..a0c2a6467 100644 --- a/api/channel_test.go +++ b/api/channel_test.go @@ -320,6 +320,27 @@ func TestGetChannel(t *testing.T) { if _, err := Client.UpdateLastViewedAt(channel2.Id); err != nil { t.Fatal(err) } + + if resp, err := Client.GetChannel(channel1.Id, ""); err != nil { + t.Fatal(err) + } else { + data := resp.Data.(*model.ChannelData) + if data.Channel.DisplayName != channel1.DisplayName { + t.Fatal("name didn't match") + } + + // test etag caching + if cache_result, err := Client.GetChannel(channel1.Id, resp.Etag); err != nil { + t.Fatal(err) + } else if cache_result.Data.(*model.ChannelData) != nil { + t.Log(cache_result.Data) + t.Fatal("cache should be empty") + } + } + + if _, err := Client.GetChannel("junk", ""); err == nil { + t.Fatal("should have failed - bad channel id") + } } func TestGetMoreChannel(t *testing.T) { diff --git a/model/channel_data.go b/model/channel_data.go new file mode 100644 index 000000000..234bdec6e --- /dev/null +++ b/model/channel_data.go @@ -0,0 +1,43 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +type ChannelData struct { + Channel *Channel `json:"channel"` + Member *ChannelMember `json:"member"` +} + +func (o *ChannelData) Etag() string { + var mt int64 = 0 + if o.Member != nil { + mt = o.Member.LastUpdateAt + } + + return Etag(o.Channel.Id, o.Channel.UpdateAt, o.Channel.LastPostAt, mt) +} + +func (o *ChannelData) ToJson() string { + b, err := json.Marshal(o) + if err != nil { + return "" + } else { + return string(b) + } +} + +func ChannelDataFromJson(data io.Reader) *ChannelData { + decoder := json.NewDecoder(data) + var o ChannelData + err := decoder.Decode(&o) + if err == nil { + return &o + } else { + return nil + } +} diff --git a/model/client.go b/model/client.go index a5016fa2c..9ae0a66e5 100644 --- a/model/client.go +++ b/model/client.go @@ -390,6 +390,15 @@ func (c *Client) GetChannels(etag string) (*Result, *AppError) { } } +func (c *Client) GetChannel(id, etag string) (*Result, *AppError) { + if r, err := c.DoGet("/channels/"+id+"/", "", etag); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), ChannelDataFromJson(r.Body)}, nil + } +} + func (c *Client) GetMoreChannels(etag string) (*Result, *AppError) { if r, err := c.DoGet("/channels/more", "", etag); err != nil { return nil, err diff --git a/web/react/components/edit_channel_modal.jsx b/web/react/components/edit_channel_modal.jsx index 06d7fc3e8..dcff5b89d 100644 --- a/web/react/components/edit_channel_modal.jsx +++ b/web/react/components/edit_channel_modal.jsx @@ -14,7 +14,7 @@ module.exports = React.createClass({ Client.updateChannelDesc(data, function(data) { this.setState({ server_error: "" }); - AsyncClient.getChannels(true); + AsyncClient.getChannel(this.state.channel_id); $(this.refs.modal.getDOMNode()).modal('hide'); }.bind(this), function(err) { diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index fe73cbcf7..fa6302b6d 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -157,9 +157,9 @@ module.exports = React.createClass({ onSocketChange: function(msg) { if (msg.action === 'posted') { if (ChannelStore.getCurrentId() === msg.channel_id) { - AsyncClient.getChannels(true, window.isActive); + if (window.isActive) AsyncClient.updateLastViewedAt(); } else { - AsyncClient.getChannels(true); + AsyncClient.getChannel(msg.channel_id); } if (UserStore.getCurrentId() !== msg.user_id) { @@ -213,13 +213,13 @@ module.exports = React.createClass({ utils.ding(); } } - } else if (msg.action === 'viewed') { - if (ChannelStore.getCurrentId() != msg.channel_id) { - AsyncClient.getChannels(true); + } else if (msg.action === "viewed") { + if (ChannelStore.getCurrentId() !== msg.channel_id && UserStore.getCurrentId() === msg.user_id) { + AsyncClient.getChannel(msg.channel_id); } } else if (msg.action === 'user_added') { if (UserStore.getCurrentId() === msg.user_id) { - AsyncClient.getChannels(true); + AsyncClient.getChannel(msg.channel_id); } } else if (msg.action === 'user_removed') { if (msg.user_id === UserStore.getCurrentId()) { diff --git a/web/react/stores/channel_store.jsx b/web/react/stores/channel_store.jsx index a97f13391..46e856a97 100644 --- a/web/react/stores/channel_store.jsx +++ b/web/react/stores/channel_store.jsx @@ -146,12 +146,39 @@ var ChannelStore = assign({}, EventEmitter.prototype, { return extra; }, + _storeChannel: function(channel) { + var channels = this._getChannels(); + var found; + + for (var i = 0; i < channels.length; i++) { + if (channels[i].id == channel.id) { + channels[i] = channel; + found = true; + break; + } + } + + if (!found) { + channels.push(channel); + channels.sort(function(a,b) { + if (a.display_name < b.display_name) return -1; + if (a.display_name > b.display_name) return 1; + return 0; + }); + } + this._storeChannels(channels); + }, _storeChannels: function(channels) { BrowserStore.setItem("channels", channels); }, _getChannels: function() { return BrowserStore.getItem("channels", []); }, + _storeChannelMember: function(channelMember) { + var members = this._getChannelMembers(); + members[channelMember.channel_id] = channelMember; + this._storeChannelMembers(members); + }, _storeChannelMembers: function(channelMembers) { BrowserStore.setItem("channel_members", channelMembers); }, @@ -202,6 +229,14 @@ ChannelStore.dispatchToken = AppDispatcher.register(function(payload) { ChannelStore.emitChange(); break; + case ActionTypes.RECIEVED_CHANNEL: + ChannelStore._storeChannel(action.channel); + ChannelStore._storeChannelMember(action.member); + var currentId = ChannelStore.getCurrentId(); + if (currentId) ChannelStore.resetCounts(currentId); + ChannelStore.emitChange(); + break; + case ActionTypes.RECIEVED_MORE_CHANNELS: ChannelStore._storeMoreChannels(action.channels); ChannelStore.emitMoreChange(); @@ -218,4 +253,4 @@ ChannelStore.dispatchToken = AppDispatcher.register(function(payload) { } }); -module.exports = ChannelStore;
\ No newline at end of file +module.exports = ChannelStore; diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx index f35b0f6cc..b938216ac 100644 --- a/web/react/utils/async_client.jsx +++ b/web/react/utils/async_client.jsx @@ -81,6 +81,30 @@ module.exports.getChannels = function(force, updateLastViewed, checkVersion) { } } +module.exports.getChannel = function(id) { + if (isCallInProgress("getChannel"+id)) return; + + callTracker["getChannel"+id] = utils.getTimestamp(); + client.getChannel(id, + function(data, textStatus, xhr) { + callTracker["getChannel"+id] = 0; + + if (xhr.status === 304 || !data) return; + + AppDispatcher.handleServerAction({ + type: ActionTypes.RECIEVED_CHANNEL, + channel: data.channel, + member: data.member + }); + + }, + function(err) { + callTracker["getChannel"+id] = 0; + dispatchError(err, "getChannel"); + } + ); +} + module.exports.updateLastViewedAt = function() { if (isCallInProgress("updateLastViewed")) return; diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index 6a1f7c820..7b014cdad 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -554,6 +554,21 @@ module.exports.getChannels = function(success, error) { }); }; +module.exports.getChannel = function(id, success, error) { + $.ajax({ + url: "/api/v1/channels/" + id + "/", + dataType: 'json', + type: 'GET', + success: success, + error: function(xhr, status, err) { + e = handleError("getChannel", xhr, status, err); + error(e); + } + }); + + module.exports.track('api', 'api_channel_get'); +}; + module.exports.getMoreChannels = function(success, error) { $.ajax({ url: "/api/v1/channels/more", diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index bed0ec556..19c92df33 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -10,6 +10,7 @@ module.exports = { CLICK_CHANNEL: null, CREATE_CHANNEL: null, RECIEVED_CHANNELS: null, + RECIEVED_CHANNEL: null, RECIEVED_MORE_CHANNELS: null, RECIEVED_CHANNEL_EXTRA_INFO: null, |