Unverified Commit 5872bf9c authored by Martin Kraft's avatar Martin Kraft Committed by GitHub

Pr 9039 (#9187)

* MM-11065: Allow to search and get archived channels from the API

* Fixing more tests

* Add some unit tests

* Add includeDeleted parameter to session permissions check function

* More test fixing

* Adding archive channels list in channels search

* Add restriction for archived channel edition

* Reverting permissions checks modification

* Changed the query parameter to include_deleted

* Enable search archive channels as true by default

* Adding tests for verify search on deleted channels

* Allowing to override archive channels during the imports

* Fixed test

* Search in archive channels from the API must be explicitly requested

* Removing includeDeleted parameter from GetChannelByName and GetChannelByNameForTeam

* Back to ViewArchivedChannels config

* Fixing tests

* Reverting GetChannelByName parameter

* Add include deleted parameter on GetChannel functions in plugins api

* Fixing tests
parent 65cd447a
......@@ -44,6 +44,7 @@ type TestHelper struct {
BasicTeam *model.Team
BasicChannel *model.Channel
BasicPrivateChannel *model.Channel
BasicDeletedChannel *model.Channel
BasicChannel2 *model.Channel
BasicPost *model.Post
......@@ -250,6 +251,7 @@ func (me *TestHelper) InitBasic() *TestHelper {
me.BasicTeam = me.CreateTeam()
me.BasicChannel = me.CreatePublicChannel()
me.BasicPrivateChannel = me.CreatePrivateChannel()
me.BasicDeletedChannel = me.CreatePublicChannel()
me.BasicChannel2 = me.CreatePublicChannel()
me.BasicPost = me.CreatePost()
me.BasicUser = me.CreateUser()
......@@ -262,7 +264,10 @@ func (me *TestHelper) InitBasic() *TestHelper {
me.App.AddUserToChannel(me.BasicUser2, me.BasicChannel2)
me.App.AddUserToChannel(me.BasicUser, me.BasicPrivateChannel)
me.App.AddUserToChannel(me.BasicUser2, me.BasicPrivateChannel)
me.App.AddUserToChannel(me.BasicUser, me.BasicDeletedChannel)
me.App.AddUserToChannel(me.BasicUser2, me.BasicDeletedChannel)
me.App.UpdateUserRoles(me.BasicUser.Id, model.SYSTEM_USER_ROLE_ID, false)
me.Client.DeleteChannel(me.BasicDeletedChannel.Id)
me.LoginBasic()
return me
......
......@@ -589,7 +589,7 @@ func getChannelsForTeamForUser(c *Context, w http.ResponseWriter, r *http.Reques
return
}
channels, err := c.App.GetChannelsForUser(c.Params.TeamId, c.Params.UserId)
channels, err := c.App.GetChannelsForUser(c.Params.TeamId, c.Params.UserId, false)
if err != nil {
c.Err = err
return
......@@ -709,7 +709,9 @@ func getChannelByName(c *Context, w http.ResponseWriter, r *http.Request) {
var channel *model.Channel
var err *model.AppError
if channel, err = c.App.GetChannelByName(c.Params.ChannelName, c.Params.TeamId); err != nil {
includeDeleted := r.URL.Query().Get("include_deleted") == "true"
if channel, err = c.App.GetChannelByName(c.Params.ChannelName, c.Params.TeamId, includeDeleted); err != nil {
c.Err = err
return
}
......@@ -744,7 +746,9 @@ func getChannelByNameForTeamName(c *Context, w http.ResponseWriter, r *http.Requ
var channel *model.Channel
var err *model.AppError
if channel, err = c.App.GetChannelByNameForTeamName(c.Params.ChannelName, c.Params.TeamName); err != nil {
includeDeleted := r.URL.Query().Get("include_deleted") == "true"
if channel, err = c.App.GetChannelByNameForTeamName(c.Params.ChannelName, c.Params.TeamName, includeDeleted); err != nil {
c.Err = err
return
}
......
......@@ -867,7 +867,7 @@ func TestDeleteChannel(t *testing.T) {
CheckNoError(t, resp)
// default channel cannot be deleted.
defaultChannel, _ := th.App.GetChannelByName(model.DEFAULT_CHANNEL, team.Id)
defaultChannel, _ := th.App.GetChannelByName(model.DEFAULT_CHANNEL, team.Id, false)
pass, resp = Client.DeleteChannel(defaultChannel.Id)
CheckBadRequestStatus(t, resp)
......@@ -998,7 +998,7 @@ func TestConvertChannelToPrivate(t *testing.T) {
defer th.TearDown()
Client := th.Client
defaultChannel, _ := th.App.GetChannelByName(model.DEFAULT_CHANNEL, th.BasicTeam.Id)
defaultChannel, _ := th.App.GetChannelByName(model.DEFAULT_CHANNEL, th.BasicTeam.Id, false)
_, resp := Client.ConvertChannelToPrivate(defaultChannel.Id)
CheckForbiddenStatus(t, resp)
......@@ -1115,6 +1115,16 @@ func TestGetChannelByName(t *testing.T) {
_, resp = Client.GetChannelByName(strings.ToUpper(th.BasicPrivateChannel.Name), th.BasicTeam.Id, "")
CheckNoError(t, resp)
_, resp = Client.GetChannelByName(th.BasicDeletedChannel.Name, th.BasicTeam.Id, "")
CheckNotFoundStatus(t, resp)
channel, resp = Client.GetChannelByNameIncludeDeleted(th.BasicDeletedChannel.Name, th.BasicTeam.Id, "")
CheckNoError(t, resp)
if channel.Name != th.BasicDeletedChannel.Name {
t.Fatal("names did not match")
}
Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser.Id)
_, resp = Client.GetChannelByName(th.BasicChannel.Name, th.BasicTeam.Id, "")
CheckNoError(t, resp)
......@@ -1157,6 +1167,16 @@ func TestGetChannelByNameForTeamName(t *testing.T) {
_, resp = Client.GetChannelByNameForTeamName(th.BasicChannel.Name, th.BasicTeam.Name, "")
CheckNoError(t, resp)
_, resp = Client.GetChannelByNameForTeamName(th.BasicDeletedChannel.Name, th.BasicTeam.Name, "")
CheckNotFoundStatus(t, resp)
channel, resp = Client.GetChannelByNameForTeamNameIncludeDeleted(th.BasicDeletedChannel.Name, th.BasicTeam.Name, "")
CheckNoError(t, resp)
if channel.Name != th.BasicDeletedChannel.Name {
t.Fatal("names did not match")
}
_, resp = Client.GetChannelByNameForTeamName(th.BasicChannel.Name, model.NewRandomString(15), "")
CheckNotFoundStatus(t, resp)
......@@ -1330,8 +1350,8 @@ func TestGetChannelMembersForUser(t *testing.T) {
members, resp := Client.GetChannelMembersForUser(th.BasicUser.Id, th.BasicTeam.Id, "")
CheckNoError(t, resp)
if len(*members) != 5 {
t.Fatal("should have 5 members on team")
if len(*members) != 6 {
t.Fatal("should have 6 members on team")
}
_, resp = Client.GetChannelMembersForUser("", th.BasicTeam.Id, "")
......
......@@ -330,6 +330,8 @@ func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
includeDeletedChannels := r.URL.Query().Get("include_deleted_channels") == "true"
props := model.StringInterfaceFromJson(r.Body)
terms, ok := props["terms"].(string)
if !ok || len(terms) == 0 {
......@@ -341,7 +343,7 @@ func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
results, err := c.App.SearchPostsInTeam(terms, c.Session.UserId, c.Params.TeamId, isOrSearch)
results, err := c.App.SearchPostsInTeam(terms, c.Session.UserId, c.Params.TeamId, isOrSearch, includeDeletedChannels)
elapsedTime := float64(time.Since(startTime)) / float64(time.Second)
metrics := c.App.Metrics
......
......@@ -1288,6 +1288,10 @@ func TestSearchPosts(t *testing.T) {
message = "hashtag for post4"
_ = th.CreateMessagePost(message)
archivedChannel := th.CreatePublicChannel()
_ = th.CreateMessagePostWithClient(th.Client, archivedChannel, "#hashtag for post3")
th.Client.DeleteChannel(archivedChannel.Id)
posts, resp := Client.SearchPosts(th.BasicTeam.Id, "search", false)
CheckNoError(t, resp)
if len(posts.Order) != 3 {
......@@ -1306,6 +1310,12 @@ func TestSearchPosts(t *testing.T) {
t.Fatal("wrong search")
}
posts, resp = Client.SearchPostsIncludeDeletedChannels(th.BasicTeam.Id, "#hashtag", false)
CheckNoError(t, resp)
if len(posts.Order) != 2 {
t.Fatal("wrong search")
}
if posts, resp = Client.SearchPosts(th.BasicTeam.Id, "*", false); len(posts.Order) != 0 {
t.Fatal("searching for just * shouldn't return any results")
}
......@@ -1328,7 +1338,6 @@ func TestSearchPosts(t *testing.T) {
Client.Logout()
_, resp = Client.SearchPosts(th.BasicTeam.Id, "#sgtitlereview", false)
CheckUnauthorizedStatus(t, resp)
}
func TestSearchHashtagPosts(t *testing.T) {
......
......@@ -176,7 +176,7 @@ func TestSaveReaction(t *testing.T) {
t.Run("unable-to-react-in-read-only-town-square", func(t *testing.T) {
th.LoginBasic()
channel, err := th.App.GetChannelByName("town-square", th.BasicTeam.Id)
channel, err := th.App.GetChannelByName("town-square", th.BasicTeam.Id, true)
assert.Nil(t, err)
post := th.CreatePostWithClient(th.Client, channel)
......@@ -482,7 +482,7 @@ func TestDeleteReaction(t *testing.T) {
t.Run("unable-to-delete-reactions-in-read-only-town-square", func(t *testing.T) {
th.LoginBasic()
channel, err := th.App.GetChannelByName("town-square", th.BasicTeam.Id)
channel, err := th.App.GetChannelByName("town-square", th.BasicTeam.Id, true)
assert.Nil(t, err)
post := th.CreatePostWithClient(th.Client, channel)
......
......@@ -37,7 +37,7 @@ func (a *App) SessionHasPermissionToChannel(session model.Session, channelId str
return false
}
cmc := a.Srv.Store.Channel().GetAllChannelMembersForUser(session.UserId, true)
cmc := a.Srv.Store.Channel().GetAllChannelMembersForUser(session.UserId, true, true)
var channelRoles []string
if cmcresult := <-cmc; cmcresult.Err == nil {
......
......@@ -393,7 +393,7 @@ func (a *App) GetGroupChannel(userIds []string) (*model.Channel, *model.AppError
return nil, model.NewAppError("GetGroupChannel", "api.channel.create_group.bad_user.app_error", nil, "user_ids="+model.ArrayToJson(userIds), http.StatusBadRequest)
}
channel, err := a.GetChannelByName(model.GetGroupNameFromUserIds(userIds), "")
channel, err := a.GetChannelByName(model.GetGroupNameFromUserIds(userIds), "", true)
if err != nil {
return nil, err
}
......@@ -1011,16 +1011,26 @@ func (a *App) GetChannel(channelId string) (*model.Channel, *model.AppError) {
}
}
func (a *App) GetChannelByName(channelName, teamId string) (*model.Channel, *model.AppError) {
if result := <-a.Srv.Store.Channel().GetByName(teamId, channelName, true); result.Err != nil && result.Err.Id == "store.sql_channel.get_by_name.missing.app_error" {
func (a *App) GetChannelByName(channelName, teamId string, includeDeleted bool) (*model.Channel, *model.AppError) {
var result store.StoreResult
if includeDeleted {
result = <-a.Srv.Store.Channel().GetByNameIncludeDeleted(teamId, channelName, false)
} else {
result = <-a.Srv.Store.Channel().GetByName(teamId, channelName, false)
}
if result.Err != nil && result.Err.Id == "store.sql_channel.get_by_name.missing.app_error" {
result.Err.StatusCode = http.StatusNotFound
return nil, result.Err
} else if result.Err != nil {
}
if result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return nil, result.Err
} else {
return result.Data.(*model.Channel), nil
}
return result.Data.(*model.Channel), nil
}
func (a *App) GetChannelsByNames(channelNames []string, teamId string) ([]*model.Channel, *model.AppError) {
......@@ -1035,7 +1045,7 @@ func (a *App) GetChannelsByNames(channelNames []string, teamId string) ([]*model
}
}
func (a *App) GetChannelByNameForTeamName(channelName, teamName string) (*model.Channel, *model.AppError) {
func (a *App) GetChannelByNameForTeamName(channelName, teamName string, includeDeleted bool) (*model.Channel, *model.AppError) {
var team *model.Team
if result := <-a.Srv.Store.Team().GetByName(teamName); result.Err != nil {
......@@ -1045,19 +1055,28 @@ func (a *App) GetChannelByNameForTeamName(channelName, teamName string) (*model.
team = result.Data.(*model.Team)
}
if result := <-a.Srv.Store.Channel().GetByName(team.Id, channelName, true); result.Err != nil && result.Err.Id == "store.sql_channel.get_by_name.missing.app_error" {
var result store.StoreResult
if includeDeleted {
result = <-a.Srv.Store.Channel().GetByNameIncludeDeleted(team.Id, channelName, false)
} else {
result = <-a.Srv.Store.Channel().GetByName(team.Id, channelName, false)
}
if result.Err != nil && result.Err.Id == "store.sql_channel.get_by_name.missing.app_error" {
result.Err.StatusCode = http.StatusNotFound
return nil, result.Err
} else if result.Err != nil {
}
if result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return nil, result.Err
} else {
return result.Data.(*model.Channel), nil
}
return result.Data.(*model.Channel), nil
}
func (a *App) GetChannelsForUser(teamId string, userId string) (*model.ChannelList, *model.AppError) {
if result := <-a.Srv.Store.Channel().GetChannels(teamId, userId); result.Err != nil {
func (a *App) GetChannelsForUser(teamId string, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
if result := <-a.Srv.Store.Channel().GetChannels(teamId, userId, includeDeleted); result.Err != nil {
return nil, result.Err
} else {
return result.Data.(*model.ChannelList), nil
......@@ -1494,7 +1513,9 @@ func (a *App) UpdateChannelLastViewedAt(channelIds []string, userId string) *mod
}
func (a *App) AutocompleteChannels(teamId string, term string) (*model.ChannelList, *model.AppError) {
if result := <-a.Srv.Store.Channel().AutocompleteInTeam(teamId, term); result.Err != nil {
includeDeleted := *a.Config().TeamSettings.ViewArchivedChannels
if result := <-a.Srv.Store.Channel().AutocompleteInTeam(teamId, term, includeDeleted); result.Err != nil {
return nil, result.Err
} else {
return result.Data.(*model.ChannelList), nil
......@@ -1502,7 +1523,9 @@ func (a *App) AutocompleteChannels(teamId string, term string) (*model.ChannelLi
}
func (a *App) SearchChannels(teamId string, term string) (*model.ChannelList, *model.AppError) {
if result := <-a.Srv.Store.Channel().SearchInTeam(teamId, term); result.Err != nil {
includeDeleted := *a.Config().TeamSettings.ViewArchivedChannels
if result := <-a.Srv.Store.Channel().SearchInTeam(teamId, term, includeDeleted); result.Err != nil {
return nil, result.Err
} else {
return result.Data.(*model.ChannelList), nil
......
......@@ -175,7 +175,7 @@ func TestJoinDefaultChannelsExperimentalDefaultChannels(t *testing.T) {
th.App.JoinDefaultChannels(th.BasicTeam.Id, user, false, "")
for _, channelName := range defaultChannelList {
channel, err := th.App.GetChannelByName(channelName, th.BasicTeam.Id)
channel, err := th.App.GetChannelByName(channelName, th.BasicTeam.Id, false)
if err != nil {
t.Errorf("Expected nil, got %s", err)
......
......@@ -59,7 +59,7 @@ func (me *InviteProvider) DoCommand(a *App, args *model.CommandArgs, message str
if len(splitMessage) > 1 && splitMessage[1] != "" {
targetChannelName := strings.TrimPrefix(strings.TrimSpace(splitMessage[1]), "~")
if channelToJoin, err = a.GetChannelByName(targetChannelName, args.TeamId); err != nil {
if channelToJoin, err = a.GetChannelByName(targetChannelName, args.TeamId, false); err != nil {
return &model.CommandResponse{Text: args.T("api.command_invite.channel.error", map[string]interface{}{"Channel": targetChannelName}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}
} else {
......
......@@ -1116,7 +1116,7 @@ func (a *App) ImportUserTeams(user *model.User, data *[]UserTeamImportData) *mod
a.UpdateTeamMemberSchemeRoles(team.Id, user.Id, isSchemeUser, isSchemeAdmin)
}
if defaultChannel, err := a.GetChannelByName(model.DEFAULT_CHANNEL, team.Id); err != nil {
if defaultChannel, err := a.GetChannelByName(model.DEFAULT_CHANNEL, team.Id, true); err != nil {
return err
} else if _, err = a.addUserToChannel(user, defaultChannel, member); err != nil {
return err
......@@ -1139,7 +1139,7 @@ func (a *App) ImportUserChannels(user *model.User, team *model.Team, teamMember
// Loop through all channels.
for _, cdata := range *data {
channel, err := a.GetChannelByName(*cdata.Name, team.Id)
channel, err := a.GetChannelByName(*cdata.Name, team.Id, true)
if err != nil {
return err
}
......
......@@ -1898,7 +1898,7 @@ func TestImportImportChannel(t *testing.T) {
th.CheckChannelsCount(t, channelCount+1)
// Get the Channel and check all the fields are correct.
if channel, err := th.App.GetChannelByName(*data.Name, team.Id); err != nil {
if channel, err := th.App.GetChannelByName(*data.Name, team.Id, false); err != nil {
t.Fatalf("Failed to get channel from database.")
} else {
assert.Equal(t, *data.Name, channel.Name)
......@@ -1923,7 +1923,7 @@ func TestImportImportChannel(t *testing.T) {
th.CheckChannelsCount(t, channelCount)
// Get the Channel and check all the fields are correct.
if channel, err := th.App.GetChannelByName(*data.Name, team.Id); err != nil {
if channel, err := th.App.GetChannelByName(*data.Name, team.Id, false); err != nil {
t.Fatalf("Failed to get channel from database.")
} else {
assert.Equal(t, *data.Name, channel.Name)
......@@ -2157,7 +2157,7 @@ func TestImportImportUser(t *testing.T) {
DisplayName: ptrStr("Display Name"),
Type: ptrStr("O"),
}, false)
channel, err := th.App.GetChannelByName(channelName, team.Id)
channel, err := th.App.GetChannelByName(channelName, team.Id, false)
if err != nil {
t.Fatalf("Failed to get channel from database.")
}
......@@ -2671,7 +2671,7 @@ func TestImportImportUser(t *testing.T) {
if err := th.App.ImportChannel(channelData, false); err != nil {
t.Fatalf("Import should have succeeded.")
}
channel, err = th.App.GetChannelByName(*channelData.Name, team.Id)
channel, err = th.App.GetChannelByName(*channelData.Name, team.Id, false)
if err != nil {
t.Fatalf("Failed to get channel from database: %v", err.Error())
}
......@@ -2755,7 +2755,7 @@ func TestImportImportPost(t *testing.T) {
DisplayName: ptrStr("Display Name"),
Type: ptrStr("O"),
}, false)
channel, err := th.App.GetChannelByName(channelName, team.Id)
channel, err := th.App.GetChannelByName(channelName, team.Id, false)
if err != nil {
t.Fatalf("Failed to get channel from database.")
}
......@@ -3959,7 +3959,7 @@ func TestImportPostAndRepliesWithAttachments(t *testing.T) {
DisplayName: ptrStr("Display Name"),
Type: ptrStr("O"),
}, false)
_, err = th.App.GetChannelByName(channelName, team.Id)
_, err = th.App.GetChannelByName(channelName, team.Id, false)
if err != nil {
t.Fatalf("Failed to get channel from database.")
}
......
......@@ -195,12 +195,12 @@ func (api *PluginAPI) GetChannel(channelId string) (*model.Channel, *model.AppEr
return api.app.GetChannel(channelId)
}
func (api *PluginAPI) GetChannelByName(teamId, name string) (*model.Channel, *model.AppError) {
return api.app.GetChannelByName(name, teamId)
func (api *PluginAPI) GetChannelByName(teamId, name string, includeDeleted bool) (*model.Channel, *model.AppError) {
return api.app.GetChannelByName(name, teamId, includeDeleted)
}
func (api *PluginAPI) GetChannelByNameForTeamName(teamName, channelName string) (*model.Channel, *model.AppError) {
return api.app.GetChannelByNameForTeamName(channelName, teamName)
func (api *PluginAPI) GetChannelByNameForTeamName(teamName, channelName string, includeDeleted bool) (*model.Channel, *model.AppError) {
return api.app.GetChannelByNameForTeamName(channelName, teamName, includeDeleted)
}
func (api *PluginAPI) GetDirectChannel(userId1, userId2 string) (*model.Channel, *model.AppError) {
......
......@@ -638,8 +638,9 @@ func (a *App) DeletePostFiles(post *model.Post) {
}
}
func (a *App) SearchPostsInTeam(terms string, userId string, teamId string, isOrSearch bool) (*model.PostSearchResults, *model.AppError) {
func (a *App) SearchPostsInTeam(terms string, userId string, teamId string, isOrSearch bool, includeDeletedChannels bool) (*model.PostSearchResults, *model.AppError) {
paramsList := model.ParseSearchParams(terms)
includeDeleted := includeDeletedChannels && *a.Config().TeamSettings.ViewArchivedChannels
esInterface := a.Elasticsearch
if license := a.License(); esInterface != nil && *a.Config().ElasticsearchSettings.EnableSearching && license != nil && *license.Features.Elasticsearch {
......@@ -651,7 +652,7 @@ func (a *App) SearchPostsInTeam(terms string, userId string, teamId string, isOr
if params.Terms != "*" {
// Convert channel names to channel IDs
for idx, channelName := range params.InChannels {
if channel, err := a.GetChannelByName(channelName, teamId); err != nil {
if channel, err := a.GetChannelByName(channelName, teamId, includeDeleted); err != nil {
mlog.Error(fmt.Sprint(err))
} else {
params.InChannels[idx] = channel.Id
......@@ -677,7 +678,7 @@ func (a *App) SearchPostsInTeam(terms string, userId string, teamId string, isOr
}
// We only allow the user to search in channels they are a member of.
userChannels, err := a.GetChannelsForUser(teamId, userId)
userChannels, err := a.GetChannelsForUser(teamId, userId, includeDeleted)
if err != nil {
mlog.Error(fmt.Sprint(err))
return nil, err
......@@ -710,6 +711,7 @@ func (a *App) SearchPostsInTeam(terms string, userId string, teamId string, isOr
channels := []store.StoreChannel{}
for _, params := range paramsList {
params.IncludeDeletedChannels = includeDeleted
params.OrTerms = isOrSearch
// don't allow users to search for everything
if params.Terms != "*" {
......
......@@ -715,7 +715,7 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string)
var channelList *model.ChannelList
if result := <-a.Srv.Store.Channel().GetChannels(team.Id, user.Id); result.Err != nil {
if result := <-a.Srv.Store.Channel().GetChannels(team.Id, user.Id, true); result.Err != nil {
if result.Err.Id == "store.sql_channel.get_channels.not_found.app_error" {
channelList = &model.ChannelList{}
} else {
......
......@@ -901,7 +901,7 @@ func (a *App) UpdateActive(user *model.User, active bool) (*model.User, *model.A
}
for _, team := range teamsForUser {
channelsForUser, err := a.GetChannelsForUser(team.Id, user.Id)
channelsForUser, err := a.GetChannelsForUser(team.Id, user.Id, false)
if err != nil {
return nil, err
}
......
......@@ -334,7 +334,7 @@ func (webCon *WebConn) ShouldSendEvent(msg *model.WebSocketEvent) bool {
}
if webCon.AllChannelMembers == nil {
if result := <-webCon.App.Srv.Store.Channel().GetAllChannelMembersForUser(webCon.UserId, true); result.Err != nil {
if result := <-webCon.App.Srv.Store.Channel().GetAllChannelMembersForUser(webCon.UserId, true, false); result.Err != nil {
mlog.Error("webhub.shouldSendEvent: " + result.Err.Error())
return false
} else {
......
......@@ -101,6 +101,7 @@
"MaxNotificationsPerChannel": 1000,
"EnableConfirmNotificationsToChannel": true,
"TeammateNameDisplay": "username",
"ViewArchivedChannels": true,
"ExperimentalEnableAutomaticReplies": false,
"ExperimentalHideTownSquareinLHS": false,
"ExperimentalTownSquareIsReadOnly": false,
......
......@@ -154,7 +154,7 @@ func manualTest(c *web.Context, w http.ResponseWriter, r *http.Request) {
func getChannelID(a *app.App, channelname string, teamid string, userid string) (id string, err bool) {
// Grab all the channels
result := <-a.Srv.Store.Channel().GetChannels(teamid, userid)
result := <-a.Srv.Store.Channel().GetChannels(teamid, userid, false)
if result.Err != nil {
mlog.Debug("Unable to get channels")
return "", false
......
......@@ -1791,6 +1791,15 @@ func (c *Client4) GetChannelByName(channelName, teamId string, etag string) (*Ch
}
}
func (c *Client4) GetChannelByNameIncludeDeleted(channelName, teamId string, etag string) (*Channel, *Response) {
if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted=true", etag); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return ChannelFromJson(r.Body), BuildResponse(r)
}
}
// GetChannelByNameForTeamName returns a channel based on the provided channel name and team name strings.
func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag string) (*Channel, *Response) {
if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag); err != nil {
......@@ -1801,6 +1810,15 @@ func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag
}
}
func (c *Client4) GetChannelByNameForTeamNameIncludeDeleted(channelName, teamName string, etag string) (*Channel, *Response) {
if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted=true", etag); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return ChannelFromJson(r.Body), BuildResponse(r)
}
}
// GetChannelMembers gets a page of channel members.
func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (*ChannelMembers, *Response) {
query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
......@@ -2127,6 +2145,17 @@ func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*Po
}
}
// SearchPosts returns any posts with matching terms string including deleted channels.
func (c *Client4) SearchPostsIncludeDeletedChannels(teamId string, terms string, isOrSearch bool) (*PostList, *Response) {
requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch}
if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search?include_deleted_channels=true", StringInterfaceToJson(requestBody)); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return PostListFromJson(r.Body), BuildResponse(r)
}
}
// SearchPosts returns any posts with matching terms string, including .
func (c *Client4) SearchPostsWithMatches(teamId string, terms string, isOrSearch bool) (*PostSearchResults, *Response) {
requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch}
......
......@@ -1125,6 +1125,7 @@ type TeamSettings struct {
MaxNotificationsPerChannel *int64
EnableConfirmNotificationsToChannel *bool
TeammateNameDisplay *string
ViewArchivedChannels *bool
ExperimentalEnableAutomaticReplies *bool
ExperimentalHideTownSquareinLHS *bool
ExperimentalTownSquareIsReadOnly *bool
......@@ -1254,6 +1255,9 @@ func (s *TeamSettings) SetDefaults() {
s.EnableUserCreation = NewBool(true)
}
if s.ViewArchivedChannels == nil {
s.ViewArchivedChannels = NewBool(true)
}
}
type ClientRequirements struct {
......
......@@ -12,11 +12,12 @@ var searchTermPuncStart = regexp.MustCompile(`^[^\pL\d\s#"]+`)
var searchTermPuncEnd = regexp.MustCompile(`[^\pL\d\s*"]+$`)
type SearchParams struct {
Terms string
IsHashtag bool
InChannels []string
FromUsers []string
OrTerms bool
Terms string
IsHashtag bool
InChannels []string
FromUsers []string
OrTerms bool
IncludeDeletedChannels bool
}
var searchFlags = [...]string{"from", "channel", "in"}
......
......@@ -108,10 +108,10 @@ type API interface {
GetChannel(channelId string) (*model.Channel, *model.AppError)
// GetChannelByName gets a channel by its name, given a team id.
GetChannelByName(teamId, name string) (*model.Channel, *model.AppError)
GetChannelByName(teamId, name string, includeDeleted bool) (*model.Channel, *model.AppError)
// GetChannelByNameForTeamName gets a channel by its name, given a team name.
GetChannelByNameForTeamName(teamName, channelName string) (*model.Channel, *model.AppError)
GetChannelByNameForTeamName(teamName, channelName string, includeDeleted bool) (*model.Channel, *model.AppError)
// GetDirectChannel gets a direct message channel.
GetDirectChannel(userId1, userId2 string) (*model.Channel, *model.AppError)
......
......@@ -1349,6 +1349,7 @@ func (s *apiRPCServer) GetChannel(args *Z_GetChannelArgs, returns *Z_GetChannelR
type Z_GetChannelByNameArgs struct {
A string
B string
C bool
}
type Z_GetChannelByNameReturns struct {
......@@ -1356,8 +1357,8 @@ type Z_GetChannelByNameReturns struct {
B *model.AppError
}
func (g *apiRPCClient) GetChannelByName(teamId, name string) (*model.Channel, *model.AppError) {
_args := &Z_GetChannelByNameArgs{teamId, name}
func (g *apiRPCClient) GetChannelByName(teamId, name string, includeDeleted bool) (*model.Channel, *model.AppError) {
_args := &Z_GetChannelByNameArgs{teamId, name, includeDeleted}
_returns := &Z_GetChannelByNameReturns{}
if err := g.client.Call("Plugin.GetChannelByName", _args, _returns); err != nil {
log.Printf("RPC call to GetChannelByName API failed: %s", err.Error())
......@@ -1367,9 +1368,9 @@ func (g *apiRPCClient) GetChannelByName(teamId, name string) (*model.Channel, *m
func (s *apiRPCServer) GetChannelByName(args *Z_GetChannelByNameArgs, returns *Z_GetChannelByNameReturns) error {
if hook, ok := s.impl.(interface {
GetChannelByName(teamId, name string) (*model.Channel, *model.AppError)
GetChannelByName(teamId, name string, includeDeleted bool) (*model.Channel, *model.AppError)
}); ok {
returns.A, returns.B = hook.GetChannelByName(args.A, args.B)
returns.A, returns.B = hook.GetChannelByName(args.A, args.B, args.C)
} else {
return fmt.Errorf("API GetChannelByName called but not implemented.")
}
......@@ -1379,6 +1380,7 @@ func (s *apiRPCServer) GetChannelByName(args *Z_GetChannelByNameArgs, returns *Z
type Z_GetChannelByNameForTeamNameArgs struct {
A string
B string
C bool
}
type Z_GetChannelByNameForTeamNameReturns struct {
......@@ -1386,8 +1388,8 @@ type Z_GetChannelByNameForTeamNameReturns struct {
B *model.AppError
}
func (g *apiRPCClient) GetChannelByNameForTeamName(teamName, channelName string) (*model.Channel, *model.AppError) {
_args := &Z_GetChannelByNameForTeamNameArgs{teamName, channelName}
func (g *apiRPCClient) GetChannelByNameForTeamName(teamName, channelName string, includeDeleted bool) (*model.Channel, *model.AppError) {
_args := &Z_GetChannelByNameForTeamNameArgs{teamName, channelName, includeDeleted}
_returns := &Z_GetChannelByNameForTeamNameReturns{}
if err := g.client.Call("Plugin.GetChannelByNameForTeamName", _args, _returns); err != nil {
log.Printf("RPC call to GetChannelByNameForTeamName API failed: %s", err.Error())
......@@ -1397,9 +1399,9 @@ func (g *apiRPCClient) GetChannelByNameForTeamName(teamName, channelName string)
func (s *apiRPCServer) GetChannelByNameForTeamName(args *Z_GetChannelByNameForTeamNameArgs, returns *Z_GetChannelByNameForTeamNameReturns) error {
if hook, ok := s.impl.(interface {
GetChannelByNameForTeamName(teamName, channelName string) (*model.Channel, *model.AppError)
GetChannelByNameForTeamName(teamName, channelName string, includeDeleted bool) (*model.Channel, *model.AppError)
}); ok {
returns.A, returns.B = hook.GetChannelByNameForTeamName(args.A, args.B)
returns.A, returns.B = hook.GetChannelByNameForTeamName(args.A, args.B, args.C)
} else {
return fmt.Errorf("API GetChannelByNameForTeamName called but not implemented.")
}
......
......@@ -30,7 +30,7 @@ func (p *HelpPlugin) OnConfigurationChange() error {
return nil
}
channel, err := p.API.GetChannelByName(p.ChannelName, team.Id)
channel, err := p.API.GetChannelByName(p.ChannelName, team.Id, false)
if err != nil {
p.API.LogError("failed to find channel", "channel_name", p.ChannelName)
return nil
......
......@@ -308,13 +308,13 @@ func (_m *API) GetChannel(channelId string) (*model.Channel, *model.AppError) {
return r0, r1
}
// GetChannelByName provides a mock function with given fields: teamId, name
func (_m *API) GetChannelByName(teamId string, name string) (*model.Channel, *model.AppError) {
ret := _m.Called(teamId, name)
// GetChannelByName provides a mock function with given fields: teamId, name, includeDeleted
func (_m *API) GetChannelByName(teamId string, name string, includeDeleted bool) (*model.Channel, *model.AppError) {
ret := _m.Called(teamId, name, includeDeleted)
var r0 *model.Channel
if rf, ok := ret.Get(0).(func(string, string) *model.Channel); ok {
r0 = rf(teamId, name)
if rf, ok := ret.Get(0).(func(string, string, bool) *model.Channel); ok {
r0 = rf(teamId, name, includeDeleted)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Channel)
......@@ -322,8 +322,8 @@ f