From a284cd8c1817bb5419cb9eae118c85cd7e99c039 Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Mon, 13 Mar 2017 09:46:28 -0400 Subject: Implement some team endpoints for APIv4 (#5745) * Implement PUT /teams/{team_id} endpoint for APIv4 * Implement GET /users/{user_id}/teams/{team_id}/unread endpoint for APIv4 * Implement POST /teams/{team_id}/members/ids endpoint for APIv4 * Remove debug statement --- api4/api.go | 2 + api4/team.go | 88 +++++++++++++++++++++- api4/team_test.go | 170 +++++++++++++++++++++++++++++++++++++++++++ app/team.go | 30 +++++++- model/channel_member.go | 10 +-- model/client4.go | 39 +++++++++- model/team_member.go | 20 +++++ model/team_member_test.go | 14 ++++ store/sql_team_store.go | 45 ++++++++++-- store/sql_team_store_test.go | 55 ++++++++++++-- store/store.go | 3 +- 11 files changed, 451 insertions(+), 25 deletions(-) diff --git a/api4/api.go b/api4/api.go index 223017151..289291951 100644 --- a/api4/api.go +++ b/api4/api.go @@ -28,6 +28,7 @@ type Routes struct { Teams *mux.Router // 'api/v4/teams' TeamsForUser *mux.Router // 'api/v4/users/{user_id:[A-Za-z0-9]+}/teams' Team *mux.Router // 'api/v4/teams/{team_id:[A-Za-z0-9]+}' + TeamForUser *mux.Router // 'api/v4/users/{user_id:[A-Za-z0-9]+}/teams/{team_id:[A-Za-z0-9]+}' TeamByName *mux.Router // 'api/v4/teams/name/{team_name:[A-Za-z0-9_-]+}' TeamMembers *mux.Router // 'api/v4/teams/{team_id:[A-Za-z0-9_-]+}/members' TeamMember *mux.Router // 'api/v4/teams/{team_id:[A-Za-z0-9_-]+}/members/{user_id:[A-Za-z0-9_-]+}' @@ -99,6 +100,7 @@ func InitApi(full bool) { BaseRoutes.Teams = BaseRoutes.ApiRoot.PathPrefix("/teams").Subrouter() BaseRoutes.TeamsForUser = BaseRoutes.User.PathPrefix("/teams").Subrouter() BaseRoutes.Team = BaseRoutes.Teams.PathPrefix("/{team_id:[A-Za-z0-9]+}").Subrouter() + BaseRoutes.TeamForUser = BaseRoutes.TeamsForUser.PathPrefix("/{team_id:[A-Za-z0-9]+}").Subrouter() BaseRoutes.TeamByName = BaseRoutes.Teams.PathPrefix("/name/{team_name:[A-Za-z0-9_-]+}").Subrouter() BaseRoutes.TeamMembers = BaseRoutes.Team.PathPrefix("/members").Subrouter() BaseRoutes.TeamMember = BaseRoutes.TeamMembers.PathPrefix("/{user_id:[A-Za-z0-9]+}").Subrouter() diff --git a/api4/team.go b/api4/team.go index 40f41aaab..ed4929326 100644 --- a/api4/team.go +++ b/api4/team.go @@ -21,8 +21,12 @@ func InitTeam() { BaseRoutes.TeamsForUser.Handle("/unread", ApiSessionRequired(getTeamsUnreadForUser)).Methods("GET") BaseRoutes.Team.Handle("", ApiSessionRequired(getTeam)).Methods("GET") + BaseRoutes.Team.Handle("", ApiSessionRequired(updateTeam)).Methods("PUT") BaseRoutes.Team.Handle("/stats", ApiSessionRequired(getTeamStats)).Methods("GET") - BaseRoutes.Team.Handle("/members", ApiSessionRequired(getTeamMembers)).Methods("GET") + BaseRoutes.TeamMembers.Handle("", ApiSessionRequired(getTeamMembers)).Methods("GET") + BaseRoutes.TeamMembers.Handle("/ids", ApiSessionRequired(getTeamMembersByIds)).Methods("POST") + + BaseRoutes.TeamForUser.Handle("/unread", ApiSessionRequired(getTeamUnread)).Methods("GET") BaseRoutes.TeamByName.Handle("", ApiSessionRequired(getTeamByName)).Methods("GET") BaseRoutes.TeamMember.Handle("", ApiSessionRequired(getTeamMember)).Methods("GET") @@ -92,6 +96,36 @@ func getTeamByName(c *Context, w http.ResponseWriter, r *http.Request) { } } +func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireTeamId() + if c.Err != nil { + return + } + + team := model.TeamFromJson(r.Body) + + if team == nil { + c.SetInvalidParam("team") + return + } + + team.Id = c.Params.TeamId + + if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_MANAGE_TEAM) { + c.SetPermissionError(model.PERMISSION_MANAGE_TEAM) + return + } + + updatedTeam, err := app.UpdateTeam(team) + + if err != nil { + c.Err = err + return + } + + w.Write([]byte(updatedTeam.ToJson())) +} + func getTeamsForUser(c *Context, w http.ResponseWriter, r *http.Request) { c.RequireUserId() if c.Err != nil { @@ -174,6 +208,58 @@ func getTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) { } } +func getTeamMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireTeamId() + if c.Err != nil { + return + } + + userIds := model.ArrayFromJson(r.Body) + + if len(userIds) == 0 { + c.SetInvalidParam("user_ids") + return + } + + if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) { + c.SetPermissionError(model.PERMISSION_VIEW_TEAM) + return + } + + members, err := app.GetTeamMembersByIds(c.Params.TeamId, userIds) + if err != nil { + c.Err = err + return + } + + w.Write([]byte(model.TeamMembersToJson(members))) +} + +func getTeamUnread(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireTeamId().RequireUserId() + if c.Err != nil { + return + } + + if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) { + c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS) + return + } + + if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) { + c.SetPermissionError(model.PERMISSION_VIEW_TEAM) + return + } + + unreadTeam, err := app.GetTeamUnread(c.Params.TeamId, c.Params.UserId) + if err != nil { + c.Err = err + return + } + + w.Write([]byte(unreadTeam.ToJson())) +} + func getTeamStats(c *Context, w http.ResponseWriter, r *http.Request) { c.RequireTeamId() if c.Err != nil { diff --git a/api4/team_test.go b/api4/team_test.go index 1ace69685..4b69f5b62 100644 --- a/api4/team_test.go +++ b/api4/team_test.go @@ -114,6 +114,138 @@ func TestGetTeam(t *testing.T) { CheckNoError(t, resp) } +func TestGetTeamUnread(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.Client + + teamUnread, resp := Client.GetTeamUnread(th.BasicTeam.Id, th.BasicUser.Id) + CheckNoError(t, resp) + if teamUnread.TeamId != th.BasicTeam.Id { + t.Fatal("wrong team id returned for regular user call") + } + + _, resp = Client.GetTeamUnread("junk", th.BasicUser.Id) + CheckBadRequestStatus(t, resp) + + _, resp = Client.GetTeamUnread(th.BasicTeam.Id, "junk") + CheckBadRequestStatus(t, resp) + + _, resp = Client.GetTeamUnread(model.NewId(), th.BasicUser.Id) + CheckForbiddenStatus(t, resp) + + _, resp = Client.GetTeamUnread(th.BasicTeam.Id, model.NewId()) + CheckForbiddenStatus(t, resp) + + Client.Logout() + _, resp = Client.GetTeamUnread(th.BasicTeam.Id, th.BasicUser.Id) + CheckUnauthorizedStatus(t, resp) + + teamUnread, resp = th.SystemAdminClient.GetTeamUnread(th.BasicTeam.Id, th.BasicUser.Id) + CheckNoError(t, resp) + if teamUnread.TeamId != th.BasicTeam.Id { + t.Fatal("wrong team id returned") + } +} + +func TestUpdateTeam(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.Client + + team := &model.Team{DisplayName: "Name", Description: "Some description", AllowOpenInvite: false, InviteId: "inviteid0", Name: "z-z-" + model.NewId() + "a", Email: "success+" + model.NewId() + "@simulator.amazonses.com", Type: model.TEAM_OPEN} + team, _ = Client.CreateTeam(team) + + team.Description = "updated description" + uteam, resp := Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.Description != "updated description" { + t.Fatal("Update failed") + } + + team.DisplayName = "Updated Name" + uteam, resp = Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.DisplayName != "Updated Name" { + t.Fatal("Update failed") + } + + team.AllowOpenInvite = true + uteam, resp = Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.AllowOpenInvite != true { + t.Fatal("Update failed") + } + + team.InviteId = "inviteid1" + uteam, resp = Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.InviteId != "inviteid1" { + t.Fatal("Update failed") + } + + team.Name = "Updated name" + uteam, resp = Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.Name == "Updated name" { + t.Fatal("Should not update name") + } + + team.Email = "test@domain.com" + uteam, resp = Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.Email == "test@domain.com" { + t.Fatal("Should not update email") + } + + team.Type = model.TEAM_INVITE + uteam, resp = Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.Type == model.TEAM_INVITE { + t.Fatal("Should not update type") + } + + team.AllowedDomains = "domain" + uteam, resp = Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.AllowedDomains == "domain" { + t.Fatal("Should not update allowed_domains") + } + + originalTeamId := team.Id + team.Id = model.NewId() + + if r, err := Client.DoApiPut(Client.GetTeamRoute(originalTeamId), team.ToJson()); err != nil { + t.Fatal(err) + } else { + uteam = model.TeamFromJson(r.Body) + } + + if uteam.Id != originalTeamId { + t.Fatal("wrong team id") + } + + team.Id = "fake" + _, resp = Client.UpdateTeam(team) + CheckBadRequestStatus(t, resp) + + Client.Logout() + _, resp = Client.UpdateTeam(team) + CheckUnauthorizedStatus(t, resp) + + team.Id = originalTeamId + _, resp = th.SystemAdminClient.UpdateTeam(team) + CheckNoError(t, resp) +} + func TestGetAllTeams(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer TearDown() @@ -332,6 +464,44 @@ func TestGetTeamMembers(t *testing.T) { CheckNoError(t, resp) } +func TestGetTeamMembersByIds(t *testing.T) { + th := Setup().InitBasic() + defer TearDown() + Client := th.Client + + tm, resp := Client.GetTeamMembersByIds(th.BasicTeam.Id, []string{th.BasicUser.Id}) + CheckNoError(t, resp) + + if tm[0].UserId != th.BasicUser.Id { + t.Fatal("returned wrong user") + } + + _, resp = Client.GetTeamMembersByIds(th.BasicTeam.Id, []string{}) + CheckBadRequestStatus(t, resp) + + tm1, resp := Client.GetTeamMembersByIds(th.BasicTeam.Id, []string{"junk"}) + CheckNoError(t, resp) + if len(tm1) > 0 { + t.Fatal("no users should be returned") + } + + tm1, resp = Client.GetTeamMembersByIds(th.BasicTeam.Id, []string{"junk", th.BasicUser.Id}) + CheckNoError(t, resp) + if len(tm1) != 1 { + t.Fatal("1 user should be returned") + } + + tm1, resp = Client.GetTeamMembersByIds("junk", []string{th.BasicUser.Id}) + CheckBadRequestStatus(t, resp) + + tm1, resp = Client.GetTeamMembersByIds(model.NewId(), []string{th.BasicUser.Id}) + CheckForbiddenStatus(t, resp) + + Client.Logout() + _, resp = Client.GetTeamMembersByIds(th.BasicTeam.Id, []string{th.BasicUser.Id}) + CheckUnauthorizedStatus(t, resp) +} + func TestGetTeamStats(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer TearDown() diff --git a/app/team.go b/app/team.go index 60a2f4220..6bc4d258e 100644 --- a/app/team.go +++ b/app/team.go @@ -391,6 +391,30 @@ func GetTeamMembersByIds(teamId string, userIds []string) ([]*model.TeamMember, } } +func GetTeamUnread(teamId, userId string) (*model.TeamUnread, *model.AppError) { + result := <-Srv.Store.Team().GetChannelUnreadsForTeam(teamId, userId) + if result.Err != nil { + return nil, result.Err + } + + channelUnreads := result.Data.([]*model.ChannelUnread) + var teamUnread = &model.TeamUnread{ + MsgCount: 0, + MentionCount: 0, + TeamId: teamId, + } + + for _, cu := range channelUnreads { + teamUnread.MentionCount += cu.MentionCount + + if cu.NotifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_MENTION { + teamUnread.MsgCount += cu.MsgCount + } + } + + return teamUnread, nil +} + func RemoveUserFromTeam(teamId string, userId string) *model.AppError { tchan := Srv.Store.Team().Get(teamId) uchan := Srv.Store.User().Get(userId) @@ -511,8 +535,8 @@ func FindTeamByName(name string) bool { } } -func GetTeamsUnreadForUser(teamId string, userId string) ([]*model.TeamUnread, *model.AppError) { - if result := <-Srv.Store.Team().GetTeamsUnreadForUser(teamId, userId); result.Err != nil { +func GetTeamsUnreadForUser(excludeTeamId string, userId string) ([]*model.TeamUnread, *model.AppError) { + if result := <-Srv.Store.Team().GetChannelUnreadsForAllTeams(excludeTeamId, userId); result.Err != nil { return nil, result.Err } else { data := result.Data.([]*model.ChannelUnread) @@ -523,7 +547,7 @@ func GetTeamsUnreadForUser(teamId string, userId string) ([]*model.TeamUnread, * tu.MentionCount += cu.MentionCount if cu.NotifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_MENTION { - tu.MsgCount += (cu.TotalMsgCount - cu.MsgCount) + tu.MsgCount += cu.MsgCount } return tu diff --git a/model/channel_member.go b/model/channel_member.go index 5de58bc4f..b9a08c769 100644 --- a/model/channel_member.go +++ b/model/channel_member.go @@ -19,11 +19,11 @@ const ( ) type ChannelUnread struct { - TeamId string - TotalMsgCount int64 - MsgCount int64 - MentionCount int64 - NotifyProps StringMap + TeamId string `json:"team_id"` + ChannelId string `json:"channel_id"` + MsgCount int64 `json:"msg_count"` + MentionCount int64 `json:"mention_count"` + NotifyProps StringMap `json:"-"` } type ChannelMember struct { diff --git a/model/client4.go b/model/client4.go index f2dc7625b..63f65ed48 100644 --- a/model/client4.go +++ b/model/client4.go @@ -549,8 +549,8 @@ func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) { } } -// getTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount of -// unread messages and mentions the current user has for the teams it belongs to. +// GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount +// of unread messages and mentions the current user has for the teams it belongs to. // An optional team ID can be set to exclude that team from the results. Must be authenticated. func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) { optional := "" @@ -696,7 +696,7 @@ func (c *Client4) GetTeamMember(teamId, userId, etag string) (*TeamMember, *Resp } } -// UpdateTeamMemberRoles will update the roles on a team for a user +// UpdateTeamMemberRoles will update the roles on a team for a user. func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, *Response) { requestBody := map[string]string{"roles": newRoles} if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)); err != nil { @@ -707,6 +707,16 @@ func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, } } +// UpdateTeam will update a team. +func (c *Client4) UpdateTeam(team *Team) (*Team, *Response) { + if r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson()); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) + } +} + // GetTeamMembers returns team members based on the provided team id string. func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag string) ([]*TeamMember, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) @@ -718,6 +728,17 @@ func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag stri } } +// GetTeamMembersByIds will return an array of team members based on the +// team id and a list of user ids provided. Must be authenticated. +func (c *Client4) GetTeamMembersByIds(teamId string, userIds []string) ([]*TeamMember, *Response) { + if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) + } +} + // GetTeamStats returns a team stats based on the team id string. // Must be authenticated. func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) { @@ -729,6 +750,18 @@ func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) { } } +// GetTeamUnread will return a TeamUnread object that contains the amount of +// unread messages and mentions the user has for the specified team. +// Must be authenticated. +func (c *Client4) GetTeamUnread(teamId, userId string) (*TeamUnread, *Response) { + if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", ""); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return TeamUnreadFromJson(r.Body), BuildResponse(r) + } +} + // Channel Section // CreateChannel creates a channel based on the provided channel struct. diff --git a/model/team_member.go b/model/team_member.go index 36a567a45..efd77e7ec 100644 --- a/model/team_member.go +++ b/model/team_member.go @@ -31,6 +31,15 @@ func (o *TeamMember) ToJson() string { } } +func (o *TeamUnread) ToJson() string { + b, err := json.Marshal(o) + if err != nil { + return "" + } else { + return string(b) + } +} + func TeamMemberFromJson(data io.Reader) *TeamMember { decoder := json.NewDecoder(data) var o TeamMember @@ -42,6 +51,17 @@ func TeamMemberFromJson(data io.Reader) *TeamMember { } } +func TeamUnreadFromJson(data io.Reader) *TeamUnread { + decoder := json.NewDecoder(data) + var o TeamUnread + err := decoder.Decode(&o) + if err == nil { + return &o + } else { + return nil + } +} + func TeamMembersToJson(o []*TeamMember) string { if b, err := json.Marshal(o); err != nil { return "[]" diff --git a/model/team_member_test.go b/model/team_member_test.go index eac07c646..e957ffd4f 100644 --- a/model/team_member_test.go +++ b/model/team_member_test.go @@ -41,3 +41,17 @@ func TestTeamMemberIsValid(t *testing.T) { t.Fatal(err) }*/ } + +func TestUnreadMemberJson(t *testing.T) { + o := TeamUnread{TeamId: NewId(), MsgCount: 5, MentionCount: 3} + json := o.ToJson() + + r := TeamUnreadFromJson(strings.NewReader(json)) + if o.TeamId != r.TeamId { + t.Fatal("Ids do not match") + } + + if o.MsgCount != r.MsgCount { + t.Fatal("MsgCount do not match") + } +} diff --git a/store/sql_team_store.go b/store/sql_team_store.go index bd99ed95c..7d843b030 100644 --- a/store/sql_team_store.go +++ b/store/sql_team_store.go @@ -663,7 +663,7 @@ func (s SqlTeamStore) GetTeamsForUser(userId string) StoreChannel { return storeChannel } -func (s SqlTeamStore) GetTeamsUnreadForUser(teamId, userId string) StoreChannel { +func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) StoreChannel { storeChannel := make(StoreChannel, 1) go func() { @@ -672,15 +672,50 @@ func (s SqlTeamStore) GetTeamsUnreadForUser(teamId, userId string) StoreChannel var data []*model.ChannelUnread _, err := s.GetReplica().Select(&data, `SELECT - Channels.TeamId, Channels.TotalMsgCount, ChannelMembers.MsgCount, ChannelMembers.MentionCount, ChannelMembers.NotifyProps + Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps FROM Channels, ChannelMembers WHERE - Id = ChannelId AND UserId = :UserId AND DeleteAt = 0 AND TeamId != :TeamId`, - map[string]interface{}{"UserId": userId, "TeamId": teamId}) + Id = ChannelId + AND UserId = :UserId + AND DeleteAt = 0 + AND TeamId != :TeamId`, + map[string]interface{}{"UserId": userId, "TeamId": excludeTeamId}) if err != nil { - result.Err = model.NewLocAppError("SqlTeamStore.GetTeamsUnreadForUser", "store.sql_team.get_unread.app_error", nil, "userId="+userId+" "+err.Error()) + result.Err = model.NewLocAppError("SqlTeamStore.GetChannelUnreadsForAllTeams", "store.sql_team.get_unread.app_error", nil, "userId="+userId+" "+err.Error()) + } else { + result.Data = data + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) StoreChannel { + storeChannel := make(StoreChannel, 1) + + go func() { + result := StoreResult{} + + var data []*model.ChannelUnread + _, err := s.GetReplica().Select(&data, + `SELECT + Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps + FROM + Channels, ChannelMembers + WHERE + Id = ChannelId + AND UserId = :UserId + AND TeamId = :TeamId + AND DeleteAt = 0`, + map[string]interface{}{"TeamId": teamId, "UserId": userId}) + + if err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.GetChannelUnreadsForTeam", "store.sql_team.get_unread.app_error", nil, "teamId="+teamId+" "+err.Error()) } else { result.Data = data } diff --git a/store/sql_team_store_test.go b/store/sql_team_store_test.go index 58ac74fc0..3aeb14c9c 100644 --- a/store/sql_team_store_test.go +++ b/store/sql_team_store_test.go @@ -554,7 +554,7 @@ func TestTeamStoreMemberCount(t *testing.T) { } } -func TestMyTeamMembersUnread(t *testing.T) { +func TestGetChannelUnreadsForAllTeams(t *testing.T) { Setup() teamId1 := model.NewId() @@ -566,17 +566,17 @@ func TestMyTeamMembersUnread(t *testing.T) { Must(store.Team().SaveMember(m1)) Must(store.Team().SaveMember(m2)) - c1 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN} + c1 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN, TotalMsgCount: 100} Must(store.Channel().Save(c1)) - c2 := &model.Channel{TeamId: m2.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN} + c2 := &model.Channel{TeamId: m2.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN, TotalMsgCount: 100} Must(store.Channel().Save(c2)) - cm1 := &model.ChannelMember{ChannelId: c1.Id, UserId: m1.UserId, NotifyProps: model.GetDefaultChannelNotifyProps()} + cm1 := &model.ChannelMember{ChannelId: c1.Id, UserId: m1.UserId, NotifyProps: model.GetDefaultChannelNotifyProps(), MsgCount: 90} Must(store.Channel().SaveMember(cm1)) - cm2 := &model.ChannelMember{ChannelId: c2.Id, UserId: m2.UserId, NotifyProps: model.GetDefaultChannelNotifyProps()} + cm2 := &model.ChannelMember{ChannelId: c2.Id, UserId: m2.UserId, NotifyProps: model.GetDefaultChannelNotifyProps(), MsgCount: 90} Must(store.Channel().SaveMember(cm2)) - if r1 := <-store.Team().GetTeamsUnreadForUser("", uid); r1.Err != nil { + if r1 := <-store.Team().GetChannelUnreadsForAllTeams("", uid); r1.Err != nil { t.Fatal(r1.Err) } else { ms := r1.Data.([]*model.ChannelUnread) @@ -590,9 +590,13 @@ func TestMyTeamMembersUnread(t *testing.T) { if len(membersMap) != 2 { t.Fatal("Should be the unreads for all the teams") } + + if ms[0].MsgCount != 10 { + t.Fatal("subtraction failed") + } } - if r2 := <-store.Team().GetTeamsUnreadForUser(teamId1, uid); r2.Err != nil { + if r2 := <-store.Team().GetChannelUnreadsForAllTeams(teamId1, uid); r2.Err != nil { t.Fatal(r2.Err) } else { ms := r2.Data.([]*model.ChannelUnread) @@ -607,9 +611,46 @@ func TestMyTeamMembersUnread(t *testing.T) { if len(membersMap) != 1 { t.Fatal("Should be the unreads for just one team") } + + if ms[0].MsgCount != 10 { + t.Fatal("subtraction failed") + } } if r1 := <-store.Team().RemoveAllMembersByUser(uid); r1.Err != nil { t.Fatal(r1.Err) } } + +func TestGetChannelUnreadsForTeam(t *testing.T) { + Setup() + + teamId1 := model.NewId() + + uid := model.NewId() + m1 := &model.TeamMember{TeamId: teamId1, UserId: uid} + Must(store.Team().SaveMember(m1)) + + c1 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN, TotalMsgCount: 100} + Must(store.Channel().Save(c1)) + c2 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN, TotalMsgCount: 100} + Must(store.Channel().Save(c2)) + + cm1 := &model.ChannelMember{ChannelId: c1.Id, UserId: m1.UserId, NotifyProps: model.GetDefaultChannelNotifyProps(), MsgCount: 90} + Must(store.Channel().SaveMember(cm1)) + cm2 := &model.ChannelMember{ChannelId: c2.Id, UserId: m1.UserId, NotifyProps: model.GetDefaultChannelNotifyProps(), MsgCount: 90} + Must(store.Channel().SaveMember(cm2)) + + if r1 := <-store.Team().GetChannelUnreadsForTeam(m1.TeamId, m1.UserId); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.ChannelUnread) + if len(ms) != 2 { + t.Fatal("wrong length") + } + + if ms[0].MsgCount != 10 { + t.Fatal("subtraction failed") + } + } +} diff --git a/store/store.go b/store/store.go index 8bc578114..b8b874f41 100644 --- a/store/store.go +++ b/store/store.go @@ -77,7 +77,8 @@ type TeamStore interface { GetTotalMemberCount(teamId string) StoreChannel GetActiveMemberCount(teamId string) StoreChannel GetTeamsForUser(userId string) StoreChannel - GetTeamsUnreadForUser(teamId, userId string) StoreChannel + GetChannelUnreadsForAllTeams(excludeTeamId, userId string) StoreChannel + GetChannelUnreadsForTeam(teamId, userId string) StoreChannel RemoveMember(teamId string, userId string) StoreChannel RemoveAllMembersByTeam(teamId string) StoreChannel RemoveAllMembersByUser(userId string) StoreChannel -- cgit v1.2.3-1-g7c22