Skip to content

Commit

Permalink
Merge b98a794 into 97cc0a0
Browse files Browse the repository at this point in the history
  • Loading branch information
zhouzi committed Feb 25, 2017
2 parents 97cc0a0 + b98a794 commit 92eec2c
Show file tree
Hide file tree
Showing 34 changed files with 814 additions and 52 deletions.
4 changes: 2 additions & 2 deletions api/admin_test.go
Expand Up @@ -225,7 +225,7 @@ func TestGetTeamAnalyticsStandard(t *testing.T) {
t.Fatal()
}

if rows[0].Value != 3 {
if rows[0].Value != 4 {
t.Log(rows.ToJson())
t.Fatal()
}
Expand All @@ -245,7 +245,7 @@ func TestGetTeamAnalyticsStandard(t *testing.T) {
t.Fatal()
}

if rows[2].Value != 5 {
if rows[2].Value != 6 {
t.Log(rows.ToJson())
t.Fatal()
}
Expand Down
19 changes: 19 additions & 0 deletions api/apitestlib.go
Expand Up @@ -21,6 +21,7 @@ type TestHelper struct {
BasicUser2 *model.User
BasicChannel *model.Channel
BasicPost *model.Post
PinnedPost *model.Post

SystemAdminClient *model.Client
SystemAdminTeam *model.Team
Expand Down Expand Up @@ -91,6 +92,9 @@ func (me *TestHelper) InitBasic() *TestHelper {
me.BasicChannel = me.CreateChannel(me.BasicClient, me.BasicTeam)
me.BasicPost = me.CreatePost(me.BasicClient, me.BasicChannel)

pinnedPostChannel := me.CreateChannel(me.BasicClient, me.BasicTeam)
me.PinnedPost = me.CreatePinnedPost(me.BasicClient, pinnedPostChannel)

return me
}

Expand Down Expand Up @@ -269,6 +273,21 @@ func (me *TestHelper) CreatePost(client *model.Client, channel *model.Channel) *
return r
}

func (me *TestHelper) CreatePinnedPost(client *model.Client, channel *model.Channel) *model.Post {
id := model.NewId()

post := &model.Post{
ChannelId: channel.Id,
Message: "message_" + id,
IsPinned: 1,
}

utils.DisableDebugLogForTest()
r := client.Must(client.CreatePost(post)).Data.(*model.Post)
utils.EnableDebugLogForTest()
return r
}

func (me *TestHelper) LoginBasic() {
utils.DisableDebugLogForTest()
me.BasicClient.Must(me.BasicClient.Login(me.BasicUser.Email, me.BasicUser.Password))
Expand Down
16 changes: 16 additions & 0 deletions api/channel.go
Expand Up @@ -38,6 +38,7 @@ func InitChannel() {
BaseRoutes.NeedChannel.Handle("/stats", ApiUserRequired(getChannelStats)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/members/{user_id:[A-Za-z0-9]+}", ApiUserRequired(getChannelMember)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/members/ids", ApiUserRequired(getChannelMembersByIds)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/pinned", ApiUserRequired(getPinnedPosts)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/join", ApiUserRequired(join)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/leave", ApiUserRequired(leave)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/delete", ApiUserRequired(deleteChannel)).Methods("POST")
Expand Down Expand Up @@ -565,6 +566,21 @@ func getMyChannelMembers(c *Context, w http.ResponseWriter, r *http.Request) {
}
}

func getPinnedPosts(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
channelId := params["channel_id"]
posts := &model.PostList{}

if result := <-app.Srv.Store.Channel().GetPinnedPosts(channelId); result.Err != nil {
c.Err = result.Err
return
} else {
posts = result.Data.(*model.PostList)
}

w.Write([]byte(posts.ToJson()))
}

func addMember(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["channel_id"]
Expand Down
33 changes: 27 additions & 6 deletions api/channel_test.go
Expand Up @@ -887,8 +887,8 @@ func TestGetMoreChannelsPage(t *testing.T) {
} else {
channels := r.Data.(*model.ChannelList)

// 1 for BasicChannel, 2 for open channels created above
if len(*channels) != 3 {
// 1 for BasicChannel, 1 for PinnedPostChannel, 2 for open channels created above
if len(*channels) != 4 {
t.Fatal("wrong length")
}

Expand Down Expand Up @@ -951,11 +951,11 @@ func TestGetChannelCounts(t *testing.T) {
} else {
counts := result.Data.(*model.ChannelCounts)

if len(counts.Counts) != 5 {
if len(counts.Counts) != 6 {
t.Fatal("wrong number of channel counts")
}

if len(counts.UpdateTimes) != 5 {
if len(counts.UpdateTimes) != 6 {
t.Fatal("wrong number of channel update times")
}

Expand Down Expand Up @@ -985,8 +985,8 @@ func TestGetMyChannelMembers(t *testing.T) {
} else {
members := result.Data.(*model.ChannelMembers)

// town-square, off-topic, basic test channel, channel1, channel2
if len(*members) != 5 {
// town-square, off-topic, basic test channel, pinned post channel, channel1, channel2
if len(*members) != 6 {
t.Fatal("wrong number of members", len(*members))
}
}
Expand Down Expand Up @@ -2074,3 +2074,24 @@ func TestUpdateChannelRoles(t *testing.T) {
t.Fatal("Channel member should not be able to promote itself to channel admin:", meta)
}
}

func TestGetPinnedPosts(t *testing.T) {
th := Setup().InitBasic()
Client := th.BasicClient

post1 := th.BasicPost
r1 := Client.Must(Client.GetPinnedPosts(post1.ChannelId)).Data.(*model.PostList)
if len(r1.Order) != 0 {
t.Fatal("should not have gotten a pinned post")
}

post2 := th.PinnedPost
r2 := Client.Must(Client.GetPinnedPosts(post2.ChannelId)).Data.(*model.PostList)
if len(r2.Order) == 0 {
t.Fatal("should have gotten a pinned post")
}

if _, ok := r2.Posts[post2.Id]; !ok {
t.Fatal("missing pinned post")
}
}
55 changes: 55 additions & 0 deletions api/post.go
Expand Up @@ -38,6 +38,8 @@ func InitPost() {
BaseRoutes.NeedPost.Handle("/before/{offset:[0-9]+}/{num_posts:[0-9]+}", ApiUserRequired(getPostsBefore)).Methods("GET")
BaseRoutes.NeedPost.Handle("/after/{offset:[0-9]+}/{num_posts:[0-9]+}", ApiUserRequired(getPostsAfter)).Methods("GET")
BaseRoutes.NeedPost.Handle("/get_file_infos", ApiUserRequired(getFileInfosForPost)).Methods("GET")
BaseRoutes.NeedPost.Handle("/pin", ApiUserRequired(pinPost)).Methods("POST")
BaseRoutes.NeedPost.Handle("/unpin", ApiUserRequired(unpinPost)).Methods("POST")
}

func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -91,6 +93,59 @@ func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(rpost.ToJson()))
}

func saveIsPinnedPost(c *Context, w http.ResponseWriter, r *http.Request, isPinned int8) {
params := mux.Vars(r)

channelId := params["channel_id"]
if len(channelId) != 26 {
c.SetInvalidParam("savedIsPinnedPost", "channelId")
return
}

postId := params["post_id"]
if len(postId) != 26 {
c.SetInvalidParam("savedIsPinnedPost", "postId")
return
}

pchan := app.Srv.Store.Post().Get(postId)

var oldPost *model.Post
if result := <-pchan; result.Err != nil {
c.Err = result.Err
return
} else {
oldPost = result.Data.(*model.PostList).Posts[postId]
newPost := &model.Post{}
*newPost = *oldPost
newPost.IsPinned = isPinned

if result := <-app.Srv.Store.Post().Update(newPost, oldPost); result.Err != nil {
c.Err = result.Err
return
} else {
rpost := result.Data.(*model.Post)

message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_POST_EDITED, "", rpost.ChannelId, "", nil)
message.Add("post", rpost.ToJson())

go app.Publish(message)

app.InvalidateCacheForChannelPosts(rpost.ChannelId)

w.Write([]byte(rpost.ToJson()))
}
}
}

func pinPost(c *Context, w http.ResponseWriter, r *http.Request) {
saveIsPinnedPost(c, w, r, 1)
}

func unpinPost(c *Context, w http.ResponseWriter, r *http.Request) {
saveIsPinnedPost(c, w, r, 0)
}

func getFlaggedPosts(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)

Expand Down
46 changes: 46 additions & 0 deletions api/post_test.go
Expand Up @@ -1319,3 +1319,49 @@ func TestGetOpenGraphMetadata(t *testing.T) {
}
}
}

func TestPinPost(t *testing.T) {
th := Setup().InitBasic()
Client := th.BasicClient

post := th.BasicPost
if rupost1, err := Client.PinPost(post.ChannelId, post.Id); err != nil {
t.Fatal(err)
} else {
if rupost1.Data.(*model.Post).IsPinned != 1 {
t.Fatal("failed to pin post")
}
}

pinnedPost := th.PinnedPost
if rupost2, err := Client.PinPost(pinnedPost.ChannelId, pinnedPost.Id); err != nil {
t.Fatal(err)
} else {
if rupost2.Data.(*model.Post).IsPinned != 1 {
t.Fatal("pinning a post should be idempotent")
}
}
}

func TestUnpinPost(t *testing.T) {
th := Setup().InitBasic()
Client := th.BasicClient

pinnedPost := th.PinnedPost
if rupost1, err := Client.UnpinPost(pinnedPost.ChannelId, pinnedPost.Id); err != nil {
t.Fatal(err)
} else {
if rupost1.Data.(*model.Post).IsPinned != 0 {
t.Fatal("failed to unpin post")
}
}

post := th.BasicPost
if rupost2, err := Client.UnpinPost(post.ChannelId, post.Id); err != nil {
t.Fatal(err)
} else {
if rupost2.Data.(*model.Post).IsPinned != 0 {
t.Fatal("unpinning a post should be idempotent")
}
}
}
4 changes: 4 additions & 0 deletions i18n/en.json
Expand Up @@ -4507,6 +4507,10 @@
"id": "store.sql_channel.extra_updated.app_error",
"translation": "Problem updating members last updated time"
},
{
"id": "store.sql_channel.pinned_posts.app_error",
"translation": "We couldn't find the pinned posts"
},
{
"id": "store.sql_channel.get.existing.app_error",
"translation": "We couldn't find the existing channel"
Expand Down
30 changes: 30 additions & 0 deletions model/client.go
Expand Up @@ -1523,6 +1523,16 @@ func (c *Client) GetFlaggedPosts(offset int, limit int) (*Result, *AppError) {
}
}

func (c *Client) GetPinnedPosts(channelId string) (*Result, *AppError) {
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", "", ""); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
}
}

func (c *Client) UploadProfileFile(data []byte, contentType string) (*Result, *AppError) {
return c.uploadFile(c.ApiUrl+"/users/newimage", data, contentType)
}
Expand Down Expand Up @@ -2359,3 +2369,23 @@ func (c *Client) UpdateChannelRoles(channelId string, userId string, roles strin
}
}
}

func (c *Client) PinPost(channelId string, postId string) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/posts/"+postId+"/pin", ""); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
}
}

func (c *Client) UnpinPost(channelId string, postId string) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/posts/"+postId+"/unpin", ""); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
}
}
1 change: 1 addition & 0 deletions model/post.go
Expand Up @@ -38,6 +38,7 @@ type Post struct {
UpdateAt int64 `json:"update_at"`
EditAt int64 `json:"edit_at"`
DeleteAt int64 `json:"delete_at"`
IsPinned int8 `json:"is_pinned"`
UserId string `json:"user_id"`
ChannelId string `json:"channel_id"`
RootId string `json:"root_id"`
Expand Down
26 changes: 26 additions & 0 deletions store/sql_channel_store.go
Expand Up @@ -326,6 +326,32 @@ func (s SqlChannelStore) Get(id string, allowFromCache bool) StoreChannel {
return s.get(id, false, allowFromCache)
}

func (s SqlChannelStore) GetPinnedPosts(channelId string) StoreChannel {
storeChannel := make(StoreChannel, 1)

go func() {
result := StoreResult{}
pl := &model.PostList{}

var posts []*model.Post
if _, err := s.GetReplica().Select(&posts, "SELECT * FROM Posts WHERE IsPinned = 1 AND ChannelId = :ChannelId AND DeleteAt = 0 ORDER BY CreateAt ASC", map[string]interface{}{"ChannelId": channelId}); err != nil {
result.Err = model.NewLocAppError("SqlPostStore.GetPinnedPosts", "store.sql_channel.pinned_posts.app_error", nil, err.Error())
} else {
for _, post := range posts {
pl.AddPost(post)
pl.AddOrder(post.Id)
}
}

result.Data = pl

storeChannel <- result
close(storeChannel)
}()

return storeChannel
}

func (s SqlChannelStore) GetFromMaster(id string) StoreChannel {
return s.get(id, true, false)
}
Expand Down
1 change: 1 addition & 0 deletions store/store.go
Expand Up @@ -117,6 +117,7 @@ type ChannelStore interface {
InvalidateMemberCount(channelId string)
GetMemberCountFromCache(channelId string) int64
GetMemberCount(channelId string, allowFromCache bool) StoreChannel
GetPinnedPosts(channelId string) StoreChannel
RemoveMember(channelId string, userId string) StoreChannel
PermanentDeleteMembersByUser(userId string) StoreChannel
PermanentDeleteMembersByChannel(channelId string) StoreChannel
Expand Down

0 comments on commit 92eec2c

Please sign in to comment.