mirror of
https://github.com/hanzoai/team.git
synced 2026-09-30 01:57:35 +00:00
The server module named github.com/hanzoai/team/server/v8 — a path that resolves to the retired workspace's repository, not this one — while server/public still published github.com/mattermost/mattermost/server/public. Both are github.com/hanzoteam/server/... now, which is where this code actually lives. That second half is what made the binary unbootable. Upstream's public path stayed claimed by upstream, mattermost-plugin-ai imported it, and the build linked public/model twice; public/plugin's gob.Register then ran twice under one name and panicked at init, before main. Reverting the rename traded the brand for a working binary. Rebranding the plugin alongside it needs no such trade: the agents fork is github.com/hanzoteam/agents/v2 against our public module, so no module named mattermost/mattermost is in the graph at all. Measured: `go list -deps ./cmd/mattermost` names exactly one public/model, and it is ours.
811 lines
27 KiB
Go
811 lines
27 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package api4
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hanzoteam/server/server/public/model"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func setupViewTest(t *testing.T) *TestHelper {
|
|
th := SetupConfig(t, func(cfg *model.Config) {
|
|
cfg.FeatureFlags.IntegratedBoards = true
|
|
}).InitBasic(t)
|
|
return th
|
|
}
|
|
|
|
func makeTestViewForAPI(t *testing.T) *model.View {
|
|
t.Helper()
|
|
kanban := &model.KanbanProps{
|
|
GroupBy: model.KanbanGroupBy{
|
|
FieldID: model.NewId(),
|
|
Columns: []model.KanbanColumn{
|
|
{ID: model.NewId(), Name: "Todo", OptionIDs: []string{model.NewId()}},
|
|
{ID: model.NewId(), Name: "Done", OptionIDs: []string{model.NewId()}},
|
|
},
|
|
},
|
|
}
|
|
props, err := kanban.ToProps()
|
|
require.NoError(t, err)
|
|
return &model.View{
|
|
Title: "Test Kanban",
|
|
Type: model.ViewTypeKanban,
|
|
Props: props,
|
|
}
|
|
}
|
|
|
|
func TestCreateView(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := setupViewTest(t)
|
|
|
|
t.Run("creates a view in a public channel", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, resp, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
require.NotNil(t, created)
|
|
require.Equal(t, view.Title, created.Title)
|
|
require.Equal(t, th.BasicChannel.Id, created.ChannelId)
|
|
require.Equal(t, th.BasicUser.Id, created.CreatorId)
|
|
require.NotEmpty(t, created.Id)
|
|
})
|
|
|
|
t.Run("creates a view in a private channel", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, resp, err := th.Client.CreateView(context.Background(), th.BasicPrivateChannel.Id, view)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
require.NotNil(t, created)
|
|
require.Equal(t, th.BasicPrivateChannel.Id, created.ChannelId)
|
|
})
|
|
|
|
t.Run("regular user in DM can create view", func(t *testing.T) {
|
|
dm, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
view := makeTestViewForAPI(t)
|
|
created, resp, err := th.Client.CreateView(context.Background(), dm.Id, view)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, resp)
|
|
require.NotNil(t, created)
|
|
require.Equal(t, dm.Id, created.ChannelId)
|
|
})
|
|
|
|
t.Run("invalid body returns 400", func(t *testing.T) {
|
|
_, resp, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, nil)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("empty title returns 400", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
view.Title = ""
|
|
_, resp, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("whitespace-only title returns 400", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
view.Title = " "
|
|
_, resp, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("oversized title returns 400", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
view.Title = strings.Repeat("a", model.ViewTitleMaxRunes+1)
|
|
_, resp, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("deleted channel returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
appErr := th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
view := makeTestViewForAPI(t)
|
|
_, resp, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("permission denied without create_post", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionCreatePost.Id, model.ChannelUserRoleId)
|
|
defer th.AddPermissionToRole(t, model.PermissionCreatePost.Id, model.ChannelUserRoleId)
|
|
|
|
view := makeTestViewForAPI(t)
|
|
_, resp, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("unauthenticated returns 401", func(t *testing.T) {
|
|
client := th.CreateClient()
|
|
view := makeTestViewForAPI(t)
|
|
_, resp, err := client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("exceeding max views per channel returns 400", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
|
|
for i := range model.MaxViewsPerChannel {
|
|
view := makeTestViewForAPI(t)
|
|
_, _, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err, "failed to create view %d", i)
|
|
}
|
|
|
|
// The next one should fail
|
|
view := makeTestViewForAPI(t)
|
|
_, resp, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestGetViewsForChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := setupViewTest(t)
|
|
|
|
t.Run("lists views for channel", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
|
|
v1 := makeTestViewForAPI(t)
|
|
_, _, err := th.Client.CreateView(context.Background(), channel.Id, v1)
|
|
require.NoError(t, err)
|
|
v2 := makeTestViewForAPI(t)
|
|
v2.Title = "Second View"
|
|
_, _, err = th.Client.CreateView(context.Background(), channel.Id, v2)
|
|
require.NoError(t, err)
|
|
|
|
views, resp, err := th.Client.GetViewsForChannel(context.Background(), channel.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, views, 2)
|
|
})
|
|
|
|
t.Run("empty channel returns empty list", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
views, resp, err := th.Client.GetViewsForChannel(context.Background(), channel.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Empty(t, views)
|
|
})
|
|
|
|
t.Run("permission denied for non-member", func(t *testing.T) {
|
|
channel := th.CreatePrivateChannel(t)
|
|
|
|
// BasicUser2 is not a member of this newly created private channel
|
|
user2Client := th.CreateClient()
|
|
th.LoginBasic2WithClient(t, user2Client)
|
|
|
|
_, resp, err := user2Client.GetViewsForChannel(context.Background(), channel.Id, model.ViewQueryOpts{})
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("pagination", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
|
|
// Create 3 views
|
|
for i := range 3 {
|
|
v := makeTestViewForAPI(t)
|
|
v.Title = "Paginated View"
|
|
v.SortOrder = i
|
|
_, _, err := th.Client.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Page 0: request per_page=2
|
|
page1, resp, err := th.Client.GetViewsForChannel(context.Background(), channel.Id, model.ViewQueryOpts{PerPage: 2})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, page1, 2)
|
|
|
|
// Page 1: next page
|
|
page2, resp, err := th.Client.GetViewsForChannel(context.Background(), channel.Id, model.ViewQueryOpts{PerPage: 2, Page: 1})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, page2, 1)
|
|
|
|
// Ensure no overlap between pages
|
|
page1IDs := map[string]bool{page1[0].Id: true, page1[1].Id: true}
|
|
require.False(t, page1IDs[page2[0].Id])
|
|
})
|
|
|
|
t.Run("excludes deleted views by default", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, makeTestViewForAPI(t))
|
|
require.NoError(t, err)
|
|
_, _, err = th.Client.CreateView(context.Background(), channel.Id, makeTestViewForAPI(t))
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.DeleteView(context.Background(), channel.Id, created.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
views, resp, err := th.Client.GetViewsForChannel(context.Background(), channel.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, views, 1)
|
|
})
|
|
|
|
t.Run("deleted channel returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
_, _, err := th.Client.CreateView(context.Background(), channel.Id, makeTestViewForAPI(t))
|
|
require.NoError(t, err)
|
|
|
|
appErr := th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.GetViewsForChannel(context.Background(), channel.Id)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("include_total_count returns views with count", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
|
|
for i := range 3 {
|
|
v := makeTestViewForAPI(t)
|
|
v.Title = "Count View"
|
|
v.SortOrder = i
|
|
_, _, err := th.Client.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
views, totalCount, resp, err := th.Client.GetViewsForChannelWithCount(context.Background(), channel.Id, model.ViewQueryOpts{PerPage: 2})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, views, 2)
|
|
require.Equal(t, int64(3), totalCount)
|
|
})
|
|
|
|
t.Run("out-of-bounds page returns empty list", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
_, _, err := th.Client.CreateView(context.Background(), channel.Id, makeTestViewForAPI(t))
|
|
require.NoError(t, err)
|
|
|
|
views, resp, err := th.Client.GetViewsForChannel(context.Background(), channel.Id, model.ViewQueryOpts{PerPage: 1, Page: 999})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Empty(t, views)
|
|
})
|
|
}
|
|
|
|
func TestGetView(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := setupViewTest(t)
|
|
|
|
t.Run("gets a view by ID", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
got, resp, err := th.Client.GetView(context.Background(), th.BasicChannel.Id, created.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, created.Id, got.Id)
|
|
require.Equal(t, created.Title, got.Title)
|
|
})
|
|
|
|
t.Run("not found returns 404", func(t *testing.T) {
|
|
_, resp, err := th.Client.GetView(context.Background(), th.BasicChannel.Id, model.NewId())
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("wrong channel returns 404", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
otherChannel := th.CreatePublicChannel(t)
|
|
_, resp, err := th.Client.GetView(context.Background(), otherChannel.Id, created.Id)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("deleted view returns 404", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.DeleteView(context.Background(), th.BasicChannel.Id, created.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
_, resp, err = th.Client.GetView(context.Background(), th.BasicChannel.Id, created.Id)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("deleted channel returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
appErr := th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.GetView(context.Background(), channel.Id, created.Id)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("permission denied for non-member", func(t *testing.T) {
|
|
channel := th.CreatePrivateChannel(t)
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.SystemAdminClient.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
user2Client := th.CreateClient()
|
|
th.LoginBasic2WithClient(t, user2Client)
|
|
|
|
_, resp, err := user2Client.GetView(context.Background(), channel.Id, created.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestUpdateView(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := setupViewTest(t)
|
|
|
|
t.Run("updates a view", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
newTitle := "Updated Title"
|
|
updated, resp, err := th.Client.UpdateView(context.Background(), th.BasicChannel.Id, created.Id, &model.ViewPatch{Title: &newTitle})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Equal(t, newTitle, updated.Title)
|
|
require.Equal(t, created.Id, updated.Id)
|
|
})
|
|
|
|
t.Run("not found returns 404", func(t *testing.T) {
|
|
newTitle := "Title"
|
|
_, resp, err := th.Client.UpdateView(context.Background(), th.BasicChannel.Id, model.NewId(), &model.ViewPatch{Title: &newTitle})
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("wrong channel returns 404", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
otherChannel := th.CreatePublicChannel(t)
|
|
newTitle := "Title"
|
|
_, resp, err := th.Client.UpdateView(context.Background(), otherChannel.Id, created.Id, &model.ViewPatch{Title: &newTitle})
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("invalid patch returns 400", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.UpdateView(context.Background(), th.BasicChannel.Id, created.Id, nil)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("deleted channel returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
appErr := th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
newTitle := "Title"
|
|
_, resp, err := th.Client.UpdateView(context.Background(), channel.Id, created.Id, &model.ViewPatch{Title: &newTitle})
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("permission denied without create_post", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionCreatePost.Id, model.ChannelUserRoleId)
|
|
defer th.AddPermissionToRole(t, model.PermissionCreatePost.Id, model.ChannelUserRoleId)
|
|
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.SystemAdminClient.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
newTitle := "Title"
|
|
_, resp, err := th.Client.UpdateView(context.Background(), th.BasicChannel.Id, created.Id, &model.ViewPatch{Title: &newTitle})
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestDeleteView(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := setupViewTest(t)
|
|
|
|
t.Run("deletes a view", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.DeleteView(context.Background(), th.BasicChannel.Id, created.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
// verify it's gone
|
|
_, resp, err = th.Client.GetView(context.Background(), th.BasicChannel.Id, created.Id)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("not found returns 404", func(t *testing.T) {
|
|
resp, err := th.Client.DeleteView(context.Background(), th.BasicChannel.Id, model.NewId())
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("wrong channel returns 404", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
otherChannel := th.CreatePublicChannel(t)
|
|
resp, err := th.Client.DeleteView(context.Background(), otherChannel.Id, created.Id)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("deleted channel returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
appErr := th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
resp, err := th.Client.DeleteView(context.Background(), channel.Id, created.Id)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("permission denied without create_post", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionCreatePost.Id, model.ChannelUserRoleId)
|
|
defer th.AddPermissionToRole(t, model.PermissionCreatePost.Id, model.ChannelUserRoleId)
|
|
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.SystemAdminClient.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
resp, err := th.Client.DeleteView(context.Background(), th.BasicChannel.Id, created.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestUpdateViewSortOrder(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := setupViewTest(t)
|
|
|
|
t.Run("reorders views in a channel", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
var created []*model.View
|
|
for i := range 3 {
|
|
v := makeTestViewForAPI(t)
|
|
v.Title = "Sort View"
|
|
v.SortOrder = i
|
|
c, _, err := th.Client.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
created = append(created, c)
|
|
}
|
|
|
|
views, resp, err := th.Client.UpdateViewSortOrder(context.Background(), channel.Id, created[2].Id, 0)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, views, 3)
|
|
require.Equal(t, created[2].Id, views[0].Id)
|
|
require.Equal(t, created[0].Id, views[1].Id)
|
|
require.Equal(t, created[1].Id, views[2].Id)
|
|
})
|
|
|
|
t.Run("negative sort order returns 400", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
v := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.UpdateViewSortOrder(context.Background(), channel.Id, created.Id, -1)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("out of bounds returns 400", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
v := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.UpdateViewSortOrder(context.Background(), channel.Id, created.Id, 99)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("non-existent view returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
v := makeTestViewForAPI(t)
|
|
_, _, err := th.Client.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.UpdateViewSortOrder(context.Background(), channel.Id, model.NewId(), 0)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("deleted channel returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
v := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
|
|
appErr := th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.UpdateViewSortOrder(context.Background(), channel.Id, created.Id, 0)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("permission denied without create_post", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(t, model.PermissionCreatePost.Id, model.ChannelUserRoleId)
|
|
defer th.AddPermissionToRole(t, model.PermissionCreatePost.Id, model.ChannelUserRoleId)
|
|
|
|
channel := th.CreatePublicChannel(t)
|
|
v := makeTestViewForAPI(t)
|
|
created, _, err := th.SystemAdminClient.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.UpdateViewSortOrder(context.Background(), channel.Id, created.Id, 0)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("wrong channel returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
v := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, v)
|
|
require.NoError(t, err)
|
|
|
|
otherChannel := th.CreatePublicChannel(t)
|
|
// Create a view in otherChannel so the store has views to search through
|
|
_, _, err = th.Client.CreateView(context.Background(), otherChannel.Id, makeTestViewForAPI(t))
|
|
require.NoError(t, err)
|
|
|
|
_, resp, err := th.Client.UpdateViewSortOrder(context.Background(), otherChannel.Id, created.Id, 0)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("unauthenticated returns 401", func(t *testing.T) {
|
|
client := th.CreateClient()
|
|
_, resp, err := client.UpdateViewSortOrder(context.Background(), th.BasicChannel.Id, model.NewId(), 0)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestGetPostsForView(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := setupViewTest(t)
|
|
|
|
t.Run("returns all post types", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
normalPost, _, err := th.Client.CreatePost(context.Background(), &model.Post{ChannelId: channel.Id, Message: "normal post"})
|
|
require.NoError(t, err)
|
|
|
|
cardPost, _, appErr := th.App.CreatePost(th.Context, &model.Post{
|
|
ChannelId: channel.Id,
|
|
UserId: th.BasicUser.Id,
|
|
Message: "card post",
|
|
Type: model.PostTypeCard,
|
|
}, channel, model.CreatePostFlags{})
|
|
require.Nil(t, appErr)
|
|
|
|
postList, resp, err := th.Client.GetPostsForView(context.Background(), channel.Id, created.Id, 0, 60)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Contains(t, postList.Order, normalPost.Id)
|
|
require.Contains(t, postList.Order, cardPost.Id)
|
|
})
|
|
|
|
t.Run("wrong channel for view returns 404", func(t *testing.T) {
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
otherChannel := th.CreatePublicChannel(t)
|
|
_, resp, err := th.Client.GetPostsForView(context.Background(), otherChannel.Id, created.Id, 0, 60)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("non-existent view returns 404", func(t *testing.T) {
|
|
_, resp, err := th.Client.GetPostsForView(context.Background(), th.BasicChannel.Id, model.NewId(), 0, 60)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("no channel read permission returns 403", func(t *testing.T) {
|
|
channel := th.CreatePrivateChannel(t)
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.SystemAdminClient.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
user2Client := th.CreateClient()
|
|
th.LoginBasic2WithClient(t, user2Client)
|
|
|
|
_, resp, err := user2Client.GetPostsForView(context.Background(), channel.Id, created.Id, 0, 60)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
})
|
|
|
|
t.Run("unauthenticated returns 401", func(t *testing.T) {
|
|
client := th.CreateClient()
|
|
_, resp, err := client.GetPostsForView(context.Background(), th.BasicChannel.Id, model.NewId(), 0, 60)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
|
|
t.Run("deleted channel returns 404", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
appErr := th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, resp, err := th.Client.GetPostsForView(context.Background(), channel.Id, created.Id, 0, 60)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("pagination works", func(t *testing.T) {
|
|
channel := th.CreatePublicChannel(t)
|
|
view := makeTestViewForAPI(t)
|
|
created, _, err := th.Client.CreateView(context.Background(), channel.Id, view)
|
|
require.NoError(t, err)
|
|
|
|
// Channel already has a system join post, so we create 5 more for 6 total
|
|
for i := range 5 {
|
|
_, _, err = th.Client.CreatePost(context.Background(), &model.Post{
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("post %d", i),
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
page1, resp, err := th.Client.GetPostsForView(context.Background(), channel.Id, created.Id, 0, 3)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, page1.Order, 3)
|
|
|
|
page2, resp, err := th.Client.GetPostsForView(context.Background(), channel.Id, created.Id, 1, 3)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, page2.Order, 3)
|
|
|
|
// No overlap between pages
|
|
for _, id := range page2.Order {
|
|
require.NotContains(t, page1.Order, id)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetPostsForViewFeatureFlagOff(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := SetupConfig(t, func(cfg *model.Config) {
|
|
cfg.FeatureFlags.IntegratedBoards = false
|
|
}).InitBasic(t)
|
|
|
|
_, resp, err := th.Client.GetPostsForView(context.Background(), th.BasicChannel.Id, model.NewId(), 0, 60)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
}
|
|
|
|
func TestViewFeatureFlagOff(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := SetupConfig(t, func(cfg *model.Config) {
|
|
cfg.FeatureFlags.IntegratedBoards = false
|
|
}).InitBasic(t)
|
|
|
|
view := makeTestViewForAPI(t)
|
|
|
|
t.Run("create returns 404 when flag is off", func(t *testing.T) {
|
|
_, resp, err := th.Client.CreateView(context.Background(), th.BasicChannel.Id, view)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("list returns 404 when flag is off", func(t *testing.T) {
|
|
_, resp, err := th.Client.GetViewsForChannel(context.Background(), th.BasicChannel.Id, model.ViewQueryOpts{})
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("get returns 404 when flag is off", func(t *testing.T) {
|
|
_, resp, err := th.Client.GetView(context.Background(), th.BasicChannel.Id, model.NewId())
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("update returns 404 when flag is off", func(t *testing.T) {
|
|
newTitle := "Title"
|
|
_, resp, err := th.Client.UpdateView(context.Background(), th.BasicChannel.Id, model.NewId(), &model.ViewPatch{Title: &newTitle})
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("delete returns 404 when flag is off", func(t *testing.T) {
|
|
resp, err := th.Client.DeleteView(context.Background(), th.BasicChannel.Id, model.NewId())
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
|
|
t.Run("sort order returns 404 when flag is off", func(t *testing.T) {
|
|
_, resp, err := th.Client.UpdateViewSortOrder(context.Background(), th.BasicChannel.Id, model.NewId(), 0)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestViewInvalidId(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := setupViewTest(t)
|
|
|
|
t.Run("get with invalid view_id returns 400", func(t *testing.T) {
|
|
_, resp, err := th.Client.GetView(context.Background(), th.BasicChannel.Id, "invalid")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("update with invalid view_id returns 400", func(t *testing.T) {
|
|
newTitle := "Title"
|
|
_, resp, err := th.Client.UpdateView(context.Background(), th.BasicChannel.Id, "invalid", &model.ViewPatch{Title: &newTitle})
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("delete with invalid view_id returns 400", func(t *testing.T) {
|
|
resp, err := th.Client.DeleteView(context.Background(), th.BasicChannel.Id, "invalid")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("sort order with invalid view_id returns 400", func(t *testing.T) {
|
|
_, resp, err := th.Client.UpdateViewSortOrder(context.Background(), th.BasicChannel.Id, "invalid", 0)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
}
|