GraphQL: Create dedicated top-level filter for sidebar categories (#20353)

We add the excludeTeam switch to allow user to get
all sidebar categories from other teams excluding a given team.

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2022-06-28 20:28:50 +05:30
коммит произвёл GitHub
родитель ade2271442
Коммит bd6acf04a9
23 изменённых файлов: 724 добавлений и 280 удалений

Просмотреть файл

@@ -23,7 +23,7 @@ func getCategoriesForTeamForUser(c *Context, w http.ResponseWriter, r *http.Requ
return
}
categories, err := c.App.GetSidebarCategories(c.Params.UserId, c.Params.TeamId)
categories, err := c.App.GetSidebarCategoriesForTeamForUser(c.Params.UserId, c.Params.TeamId)
if err != nil {
c.Err = err
return

Просмотреть файл

@@ -309,8 +309,9 @@ func (*resolver) ChannelMembers(ctx context.Context, args struct {
// match with api4.getCategoriesForTeamForUser
func (*resolver) SidebarCategories(ctx context.Context, args struct {
UserID string
TeamID string
UserID string
TeamID string
ExcludeTeam bool
}) ([]*model.SidebarCategoryWithChannels, error) {
c, err := getCtx(ctx)
if err != nil {
@@ -335,7 +336,44 @@ func (*resolver) SidebarCategories(ctx context.Context, args struct {
args.UserID = c.AppContext.Session().UserId
}
return getSidebarCategories(c, args.UserID, args.TeamID)
if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), args.UserID) {
c.SetPermissionError(model.PermissionEditOtherUsers)
return nil, c.Err
}
// If it's only for a single team.
var categories *model.OrderedSidebarCategories
var appErr *model.AppError
if !args.ExcludeTeam {
categories, appErr = c.App.GetSidebarCategoriesForTeamForUser(args.UserID, args.TeamID)
if appErr != nil {
return nil, appErr
}
} else {
opts := &store.SidebarCategorySearchOpts{
TeamID: args.TeamID,
ExcludeTeam: args.ExcludeTeam,
}
categories, appErr = c.App.GetSidebarCategories(args.UserID, opts)
if appErr != nil {
return nil, appErr
}
}
// TODO: look into optimizing this.
// create map
orderMap := make(map[string]*model.SidebarCategoryWithChannels, len(categories.Categories))
for _, category := range categories.Categories {
orderMap[category.Id] = category
}
// create a new slice based on the order
res := make([]*model.SidebarCategoryWithChannels, 0, len(categories.Categories))
for _, categoryId := range categories.Order {
res = append(res, orderMap[categoryId])
}
return res, nil
}
// getCtx extracts web.Context out of the usual request context.

Просмотреть файл

@@ -26,14 +26,15 @@ func TestGraphQLSidebarCategories(t *testing.T) {
DisplayName string `json:"displayName"`
Sorting model.SidebarCategorySorting `json:"sorting"`
ChannelIDs []string `json:"channelIds"`
TeamID string `json:"teamId"`
} `json:"sidebarCategories"`
}
input := graphQLInput{
OperationName: "sidebarCategories",
Query: `
query sidebarCategories($userId: String = "", $teamId: String = "") {
sidebarCategories(userId: $userId, teamId: $teamId) {
query sidebarCategories($userId: String = "", $teamId: String = "", $excludeTeam: Boolean = false) {
sidebarCategories(userId: $userId, teamId: $teamId, excludeTeam: $excludeTeam) {
id
displayName
sorting
@@ -69,4 +70,66 @@ func TestGraphQLSidebarCategories(t *testing.T) {
assert.Equal(t, categories.Categories[i].Sorting, q.SidebarCategories[i].Sorting)
assert.Equal(t, categories.Categories[i].ChannelIds(), q.SidebarCategories[i].ChannelIDs)
}
input = graphQLInput{
OperationName: "sidebarCategories",
Query: `
query sidebarCategories($userId: String = "", $teamId: String = "", $excludeTeam: Boolean = false) {
sidebarCategories(userId: $userId, teamId: $teamId, excludeTeam: $excludeTeam) {
id
displayName
sorting
channelIds
}
}
`,
Variables: map[string]interface{}{
"userId": "me",
"teamId": th.BasicTeam.Id,
"excludeTeam": true,
},
}
resp, err = th.MakeGraphQLRequest(&input)
require.NoError(t, err)
require.Len(t, resp.Errors, 0)
require.NoError(t, json.Unmarshal(resp.Data, &q))
assert.Len(t, q.SidebarCategories, 0)
// Adding a new team
myTeam := th.CreateTeam()
ch1 := th.CreateChannelWithClientAndTeam(th.Client, model.ChannelTypeOpen, myTeam.Id)
ch2 := th.CreateChannelWithClientAndTeam(th.Client, model.ChannelTypePrivate, myTeam.Id)
th.LinkUserToTeam(th.BasicUser, myTeam)
th.App.AddUserToChannel(th.BasicUser, ch1, false)
th.App.AddUserToChannel(th.BasicUser, ch2, false)
input = graphQLInput{
OperationName: "sidebarCategories",
Query: `
query sidebarCategories($userId: String = "", $teamId: String = "", $excludeTeam: Boolean = false) {
sidebarCategories(userId: $userId, teamId: $teamId, excludeTeam: $excludeTeam) {
id
displayName
sorting
channelIds
teamId
}
}
`,
Variables: map[string]interface{}{
"userId": "me",
"teamId": th.BasicTeam.Id,
"excludeTeam": true,
},
}
resp, err = th.MakeGraphQLRequest(&input)
require.NoError(t, err)
require.Len(t, resp.Errors, 0)
require.NoError(t, json.Unmarshal(resp.Data, &q))
assert.Len(t, q.SidebarCategories, 3)
for _, cat := range q.SidebarCategories {
assert.Equal(t, myTeam.Id, cat.TeamID)
}
}

Просмотреть файл

@@ -9,7 +9,6 @@ import (
"github.com/graph-gophers/dataloader/v6"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/web"
)
// teamMember is an internal graphQL wrapper struct to add resolver methods.
@@ -27,43 +26,6 @@ func (tm *teamMember) User(ctx context.Context) (*user, error) {
return getGraphQLUser(ctx, tm.UserId)
}
// match with api4.getCategoriesForTeamForUser
func (tm *teamMember) SidebarCategories(ctx context.Context) ([]*model.SidebarCategoryWithChannels, error) {
c, err := getCtx(ctx)
if err != nil {
return nil, err
}
return getSidebarCategories(c, tm.UserId, tm.TeamId)
}
func getSidebarCategories(c *web.Context, userID, teamID string) ([]*model.SidebarCategoryWithChannels, error) {
if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), userID) {
c.SetPermissionError(model.PermissionEditOtherUsers)
return nil, c.Err
}
categories, appErr := c.App.GetSidebarCategories(userID, teamID)
if appErr != nil {
return nil, appErr
}
// TODO: look into optimizing this.
// create map
orderMap := make(map[string]*model.SidebarCategoryWithChannels, len(categories.Categories))
for _, category := range categories.Categories {
orderMap[category.Id] = category
}
// create a new slice based on the order
res := make([]*model.SidebarCategoryWithChannels, 0, len(categories.Categories))
for _, categoryId := range categories.Order {
res = append(res, orderMap[categoryId])
}
return res, nil
}
// match with api4.getRolesByNames
func (tm *teamMember) Roles_(ctx context.Context) ([]*model.Role, error) {
loader, err := getRolesLoader(ctx)

Просмотреть файл

@@ -41,16 +41,10 @@ func TestGraphQLTeamMembers(t *testing.T) {
SchemeManaged bool `json:"schemeManaged"`
BuiltIn bool `json:"builtIn"`
} `json:"roles"`
DeleteAt float64 `json:"deleteAt"`
SchemeGuest bool `json:"schemeGuest"`
SchemeUser bool `json:"schemeUser"`
SchemeAdmin bool `json:"schemeAdmin"`
SidebarCategories []struct {
ID string `json:"id"`
DisplayName string `json:"displayName"`
Sorting model.SidebarCategorySorting `json:"sorting"`
ChannelIDs []string `json:"channelIds"`
} `json:"sidebarCategories"`
DeleteAt float64 `json:"deleteAt"`
SchemeGuest bool `json:"schemeGuest"`
SchemeUser bool `json:"schemeUser"`
SchemeAdmin bool `json:"schemeAdmin"`
} `json:"teamMembers"`
}
@@ -78,12 +72,6 @@ func TestGraphQLTeamMembers(t *testing.T) {
schemeGuest
schemeUser
schemeAdmin
sidebarCategories {
id
displayName
sorting
channelIds
}
}
}
`,
@@ -114,23 +102,6 @@ func TestGraphQLTeamMembers(t *testing.T) {
assert.False(t, tm.SchemeGuest)
assert.True(t, tm.SchemeUser)
assert.False(t, tm.SchemeAdmin)
categories, _, err := th.Client.GetSidebarCategoriesForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, "")
require.NoError(t, err)
sort.Slice(tm.SidebarCategories, func(i, j int) bool {
return tm.SidebarCategories[i].ID < tm.SidebarCategories[j].ID
})
sort.Slice(categories.Categories, func(i, j int) bool {
return categories.Categories[i].Id < categories.Categories[j].Id
})
for i := range categories.Categories {
assert.Equal(t, categories.Categories[i].Id, tm.SidebarCategories[i].ID)
assert.Equal(t, categories.Categories[i].DisplayName, tm.SidebarCategories[i].DisplayName)
assert.Equal(t, categories.Categories[i].Sorting, tm.SidebarCategories[i].Sorting)
assert.Equal(t, categories.Categories[i].ChannelIds(), tm.SidebarCategories[i].ChannelIDs)
}
})
t.Run("User+Team", func(t *testing.T) {

Просмотреть файл

@@ -26,7 +26,8 @@ type Query {
after: String = "",
lastUpdateAt: Float = 0): [ChannelMember]!
sidebarCategories(userId: String!,
teamId: String!): [SidebarCategory]!
teamId: String!,
excludeTeam: Boolean = false): [SidebarCategory]!
}
scalar ChannelType
@@ -158,7 +159,6 @@ type TeamMember {
schemeGuest: Boolean!
schemeUser: Boolean!
schemeAdmin: Boolean!
sidebarCategories: [SidebarCategory]!
}
type SidebarCategory {
@@ -168,6 +168,7 @@ type SidebarCategory {
displayName: String!
muted: Boolean!
collapsed: Boolean!
teamId: String!
channelIds: [String!]!
}