summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Tadeu Panato Junior <ctadeu@gmail.com>2018-10-13 12:35:57 +0200
committerGitHub <noreply@github.com>2018-10-13 12:35:57 +0200
commit908ed5555f8a3d37cd057035b2792d66c8b7838a (patch)
tree7ad4248a72a7c3b6e6c3981840c5951c6108fe1d
parente87965f39d2ce6dbd0e7883c387956413c663f6a (diff)
downloadchat-908ed5555f8a3d37cd057035b2792d66c8b7838a.tar.gz
chat-908ed5555f8a3d37cd057035b2792d66c8b7838a.tar.bz2
chat-908ed5555f8a3d37cd057035b2792d66c8b7838a.zip
[APIv4] add getChannelMembersTimezone (#9286)
* add getChannelMembersTimezone * update per feedback review * add delimeter to error
-rw-r--r--api4/channel.go22
-rw-r--r--api4/channel_test.go49
-rw-r--r--app/channel.go18
-rw-r--r--app/channel_test.go38
-rw-r--r--i18n/en.json4
-rw-r--r--model/client4.go11
-rw-r--r--model/user.go6
-rw-r--r--model/utils.go23
-rw-r--r--store/sqlstore/channel_store.go23
-rw-r--r--store/store.go1
-rw-r--r--store/storetest/mocks/ChannelStore.go15
11 files changed, 203 insertions, 7 deletions
diff --git a/api4/channel.go b/api4/channel.go
index 02a7c34b5..e3a5bf703 100644
--- a/api4/channel.go
+++ b/api4/channel.go
@@ -33,7 +33,7 @@ func (api *API) InitChannel() {
api.BaseRoutes.Channel.Handle("", api.ApiSessionRequired(deleteChannel)).Methods("DELETE")
api.BaseRoutes.Channel.Handle("/stats", api.ApiSessionRequired(getChannelStats)).Methods("GET")
api.BaseRoutes.Channel.Handle("/pinned", api.ApiSessionRequired(getPinnedPosts)).Methods("GET")
-
+ api.BaseRoutes.Channel.Handle("/timezones", api.ApiSessionRequired(getChannelMembersTimezones)).Methods("GET")
api.BaseRoutes.ChannelForUser.Handle("/unread", api.ApiSessionRequired(getChannelUnread)).Methods("GET")
api.BaseRoutes.ChannelByName.Handle("", api.ApiSessionRequired(getChannelByName)).Methods("GET")
@@ -821,6 +821,26 @@ func getChannelMembers(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(members.ToJson()))
}
+func getChannelMembersTimezones(c *Context, w http.ResponseWriter, r *http.Request) {
+ c.RequireChannelId()
+ if c.Err != nil {
+ return
+ }
+
+ if !c.App.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
+ c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
+ return
+ }
+
+ membersTimezones, err := c.App.GetChannelMembersTimezones(c.Params.ChannelId)
+ if err != nil {
+ c.Err = err
+ return
+ }
+
+ w.Write([]byte(model.ArrayToJson(membersTimezones)))
+}
+
func getChannelMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireChannelId()
if c.Err != nil {
diff --git a/api4/channel_test.go b/api4/channel_test.go
index 918b37c0f..d588c0c25 100644
--- a/api4/channel_test.go
+++ b/api4/channel_test.go
@@ -2335,3 +2335,52 @@ func TestUpdateChannelScheme(t *testing.T) {
_, resp = th.SystemAdminClient.UpdateChannelScheme(channel.Id, channelScheme.Id)
CheckUnauthorizedStatus(t, resp)
}
+
+func TestGetChannelMembersTimezones(t *testing.T) {
+ th := Setup().InitBasic().InitSystemAdmin()
+ defer th.TearDown()
+ Client := th.Client
+
+ user := th.BasicUser
+ user.Timezone["useAutomaticTimezone"] = "false"
+ user.Timezone["manualTimezone"] = "XOXO/BLABLA"
+ _, resp := Client.UpdateUser(user)
+ CheckNoError(t, resp)
+
+ user2 := th.BasicUser2
+ user2.Timezone["automaticTimezone"] = "NoWhere/Island"
+ _, resp = th.SystemAdminClient.UpdateUser(user2)
+ CheckNoError(t, resp)
+
+ timezone, resp := Client.GetChannelMembersTimezones(th.BasicChannel.Id)
+ CheckNoError(t, resp)
+ if len(timezone) != 2 {
+ t.Fatal("should return 2 timezones")
+ }
+
+ //both users have same timezone
+ user2.Timezone["automaticTimezone"] = "XOXO/BLABLA"
+ _, resp = th.SystemAdminClient.UpdateUser(user2)
+ CheckNoError(t, resp)
+
+ timezone, resp = Client.GetChannelMembersTimezones(th.BasicChannel.Id)
+ CheckNoError(t, resp)
+ if len(timezone) != 1 {
+ t.Fatal("should return 1 timezone")
+ }
+
+ //no timezone set should return empty
+ user2.Timezone["automaticTimezone"] = ""
+ _, resp = th.SystemAdminClient.UpdateUser(user2)
+ CheckNoError(t, resp)
+
+ user.Timezone["manualTimezone"] = ""
+ _, resp = Client.UpdateUser(user)
+
+ timezone, resp = Client.GetChannelMembersTimezones(th.BasicChannel.Id)
+ CheckNoError(t, resp)
+ if len(timezone) > 0 {
+ t.Fatal("should return 0 timezone")
+ }
+
+}
diff --git a/app/channel.go b/app/channel.go
index 93037cf05..dee856b94 100644
--- a/app/channel.go
+++ b/app/channel.go
@@ -1153,6 +1153,24 @@ func (a *App) GetChannelMembersPage(channelId string, page, perPage int) (*model
return result.Data.(*model.ChannelMembers), nil
}
+func (a *App) GetChannelMembersTimezones(channelId string) ([]string, *model.AppError) {
+ result := <-a.Srv.Store.Channel().GetChannelMembersTimezones(channelId)
+ if result.Err != nil {
+ return nil, result.Err
+ }
+ membersTimezones := result.Data.([]map[string]string)
+
+ var timezones []string
+ for _, membersTimezone := range membersTimezones {
+ if membersTimezone["automaticTimezone"] == "" && membersTimezone["manualTimezone"] == "" {
+ continue
+ }
+ timezones = append(timezones, model.GetPreferredTimezone(membersTimezone))
+ }
+
+ return model.RemoveDuplicateStrings(timezones), nil
+}
+
func (a *App) GetChannelMembersByIds(channelId string, userIds []string) (*model.ChannelMembers, *model.AppError) {
result := <-a.Srv.Store.Channel().GetMembersByIds(channelId, userIds)
if result.Err != nil {
diff --git a/app/channel_test.go b/app/channel_test.go
index 4b09bbb78..b6f460741 100644
--- a/app/channel_test.go
+++ b/app/channel_test.go
@@ -4,6 +4,7 @@
package app
import (
+ "strings"
"testing"
"github.com/mattermost/mattermost-server/model"
@@ -709,3 +710,40 @@ func TestRenameChannel(t *testing.T) {
})
}
}
+
+func TestGetChannelMembersTimezones(t *testing.T) {
+ th := Setup().InitBasic().InitSystemAdmin()
+ defer th.TearDown()
+
+ userRequestorId := ""
+ postRootId := ""
+ if _, err := th.App.AddChannelMember(th.BasicUser2.Id, th.BasicChannel, userRequestorId, postRootId, false); err != nil {
+ t.Fatal("Failed to add user to channel. Error: " + err.Message)
+ }
+
+ user := th.BasicUser
+ user.Timezone["useAutomaticTimezone"] = "false"
+ user.Timezone["manualTimezone"] = "XOXO/BLABLA"
+ th.App.UpdateUser(user, false)
+
+ user2 := th.BasicUser2
+ user2.Timezone["automaticTimezone"] = "NoWhere/Island"
+ th.App.UpdateUser(user2, false)
+
+ user3 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
+ ruser, _ := th.App.CreateUser(&user3)
+ th.App.AddUserToChannel(ruser, th.BasicChannel)
+
+ ruser.Timezone["automaticTimezone"] = "NoWhere/Island"
+ th.App.UpdateUser(ruser, false)
+
+ user4 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
+ ruser, _ = th.App.CreateUser(&user4)
+ th.App.AddUserToChannel(ruser, th.BasicChannel)
+
+ timezones, err := th.App.GetChannelMembersTimezones(th.BasicChannel.Id)
+ if err != nil {
+ t.Fatal("Failed to get the timezones for a channel. Error: " + err.Error())
+ }
+ assert.Equal(t, 2, len(timezones))
+}
diff --git a/i18n/en.json b/i18n/en.json
index 6bcfc603f..db325eee0 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -4987,6 +4987,10 @@
"translation": "Unable to get the channel members"
},
{
+ "id": "store.sql_channel.get_timezone.app_error",
+ "translation": "We couldn't get the channel members timezones"
+ },
+ {
"id": "store.sql_channel.get_members_by_ids.app_error",
"translation": "Unable to get the channel members"
},
diff --git a/model/client4.go b/model/client4.go
index 903687ece..6a613b6b3 100644
--- a/model/client4.go
+++ b/model/client4.go
@@ -1746,6 +1746,17 @@ func (c *Client4) GetChannelStats(channelId string, etag string) (*ChannelStats,
}
}
+// GetChannelMembersTimezones gets a list of timezones for a channel.
+func (c *Client4) GetChannelMembersTimezones(channelId string) ([]string, *Response) {
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/timezones", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+
+ defer closeBody(r)
+ return ArrayFromJson(r.Body), BuildResponse(r)
+}
+
// GetPinnedPosts gets a list of pinned posts.
func (c *Client4) GetPinnedPosts(channelId string, etag string) (*PostList, *Response) {
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag); err != nil {
diff --git a/model/user.go b/model/user.go
index 781bcae66..06ad9294f 100644
--- a/model/user.go
+++ b/model/user.go
@@ -499,11 +499,7 @@ func (u *User) IsSAMLUser() bool {
}
func (u *User) GetPreferredTimezone() string {
- if u.Timezone["useAutomaticTimezone"] == "true" {
- return u.Timezone["automaticTimezone"]
- }
-
- return u.Timezone["manualTimezone"]
+ return GetPreferredTimezone(u.Timezone)
}
// UserFromJson will decode the input and return a User
diff --git a/model/utils.go b/model/utils.go
index 172b78242..849e529c1 100644
--- a/model/utils.go
+++ b/model/utils.go
@@ -564,3 +564,26 @@ func IsDomainName(s string) bool {
return ok
}
+
+func RemoveDuplicateStrings(in []string) []string {
+ out := []string{}
+ seen := make(map[string]bool, len(in))
+
+ for _, item := range in {
+ if !seen[item] {
+ out = append(out, item)
+
+ seen[item] = true
+ }
+ }
+
+ return out
+}
+
+func GetPreferredTimezone(timezone StringMap) string {
+ if timezone["useAutomaticTimezone"] == "true" {
+ return timezone["automaticTimezone"]
+ }
+
+ return timezone["manualTimezone"]
+}
diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go
index b1886c428..17ef6d4c9 100644
--- a/store/sqlstore/channel_store.go
+++ b/store/sqlstore/channel_store.go
@@ -1197,7 +1197,7 @@ func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) store.S
var dbMembers channelMemberWithSchemeRolesList
_, err := s.GetReplica().Select(&dbMembers, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelId = :ChannelId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Limit": limit, "Offset": offset})
if err != nil {
- result.Err = model.NewAppError("SqlChannelStore.GetMembers", "store.sql_channel.get_members.app_error", nil, "channel_id="+channelId+err.Error(), http.StatusInternalServerError)
+ result.Err = model.NewAppError("SqlChannelStore.GetMembers", "store.sql_channel.get_members.app_error", nil, "channel_id="+channelId+","+err.Error(), http.StatusInternalServerError)
return
}
@@ -1205,6 +1205,27 @@ func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) store.S
})
}
+func (s SqlChannelStore) GetChannelMembersTimezones(channelId string) store.StoreChannel {
+ return store.Do(func(result *store.StoreResult) {
+ var dbMembersTimezone []map[string]string
+ _, err := s.GetReplica().Select(&dbMembersTimezone, `
+ SELECT
+ Users.Timezone
+ FROM
+ ChannelMembers
+ LEFT JOIN
+ Users ON ChannelMembers.UserId = Id
+ WHERE ChannelId = :ChannelId
+ `, map[string]interface{}{
+ "ChannelId": channelId})
+ if err != nil {
+ result.Err = model.NewAppError("SqlChannelStore.GetChannelMembersTimezones", "store.sql_channel.get_members.app_error", nil, "channel_id="+channelId+","+err.Error(), http.StatusInternalServerError)
+ return
+ }
+ result.Data = dbMembersTimezone
+ })
+}
+
func (s SqlChannelStore) GetMember(channelId string, userId string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
var dbMember channelMemberWithSchemeRoles
diff --git a/store/store.go b/store/store.go
index e21917345..1e153b422 100644
--- a/store/store.go
+++ b/store/store.go
@@ -147,6 +147,7 @@ type ChannelStore interface {
UpdateMember(member *model.ChannelMember) StoreChannel
GetMembers(channelId string, offset, limit int) StoreChannel
GetMember(channelId string, userId string) StoreChannel
+ GetChannelMembersTimezones(channelId string) StoreChannel
GetAllChannelMembersForUser(userId string, allowFromCache bool, includeDeleted bool) StoreChannel
InvalidateAllChannelMembersForUser(userId string)
IsUserInChannelUseCache(userId string, channelId string) bool
diff --git a/store/storetest/mocks/ChannelStore.go b/store/storetest/mocks/ChannelStore.go
index 1c3a2a8f2..9d42d0b65 100644
--- a/store/storetest/mocks/ChannelStore.go
+++ b/store/storetest/mocks/ChannelStore.go
@@ -442,6 +442,21 @@ func (_m *ChannelStore) GetMember(channelId string, userId string) store.StoreCh
return r0
}
+func (_m *ChannelStore) GetChannelMembersTimezones(channelId string) store.StoreChannel {
+ ret := _m.Called(channelId)
+
+ var r0 store.StoreChannel
+ if rf, ok := ret.Get(0).(func(string) store.StoreChannel); ok {
+ r0 = rf(channelId)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(store.StoreChannel)
+ }
+ }
+
+ return r0
+}
+
// GetMemberCount provides a mock function with given fields: channelId, allowFromCache
func (_m *ChannelStore) GetMemberCount(channelId string, allowFromCache bool) store.StoreChannel {
ret := _m.Called(channelId, allowFromCache)