Sidebar V2 Phase 2 (#14967)
* parent 48256721c4 (#14358)
author Eli Yukelzon <reflog@gmail.com> 1585814774 +0300
committer Eli Yukelzon <reflog@gmail.com> 1589111022 +0300
Sidebar caregories implemented
Apply suggestions from code review
Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>
Update store/sqlstore/channel_store.go
Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>
Update store/sqlstore/channel_store.go
Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>
code review suggestions
status messages
edge case
bugs...
timeout reverse
* MM-25126 Add a separate default sorting method for categories (#14575)
* MM-25158 Add user to initial sidebar categories when joining team (#14570)
* MM-25281 Place new categories in the correct position (#14609)
* MM-25277 Return channels that aren't in a category as part of the Channels/Direct Messages categories (#14601)
* MM-25276 Remove categories when leaving a team (#14600)
* Remove categories when leaving a team
* layers
* corrected cleanup function
* lint
* .
* corrected errors in postgres
* .
* MM-25280 Ensure that the "update category order" API call only contains real category IDs and isn't missing any IDs (#14626)
* Ensure that the "update category order" API call only contains real category IDs and isn't missing any IDs
* tests
* correct status code
* MM-25278 Change "update category" API to return 400 when changing unsupported fields (#14599)
* MM-25279 Change category migration to only populate channels in Favorites (#14627)
* MM-25157 Add API to delete custom categories (#14574)
* MM-25157 Add API to delete custom categories
* get categories fix
* maxorder fix
* Use correct websocket event when deleting category
* Fix tests and remove debug code
* Actually use the right websocket event this time
* test cleanup
* Update test for new category order
Co-authored-by: Eli Yukelzon <reflog@gmail.com>
* MM-24914 Various fixes for sidebar channel handling (#14756)
* Fix checking for channel membership when reordering channels
* Remove unique constraint on SidebarCategories
* Set column sizes for SidebarCategories and SidebarChannels tables
* Allow changing the sorting method for non-DM categories
* Fix nil pointers in error handling
* Fix orphaned channels from other team being returned in Channels category
* Fix non-orphaned channels being duplicated in the Channels category
* Remove unique constraint on SidebarChannels
* Fix category/name of favorites preferences
* Fix testSidebarChannelsMigration
* Rename err to nErr and appErr to err
* Fix channel order returned by GetSidebarCategories on MySQL
* Fix adding/removing favorites preferences
* Remove leftover TODO
* Change SidebarCategoryType enums to use full names (#14786)
* Change SidebarCategoryType enums to use full names
* Fix Channels constant
* Remove leftover debug code
* MM-24914 Fix updateCategory endpoint returning the wrong type (#14795)
* MM-24914 Make some changes to UpdateSidebarCategories (#14806)
* Fix orphaned DMs not always being returned
* MM-24914 Make some changes to UpdateSidebarCategories
* Run updateSidebarCategoryOrderT in a transaction
* Fix deleting SidebarChannels based on order of arguments to UpdateSidebarCategories
* bump for api testing
* bump for api testing
* Change CreateInitialSidebarCategories to return a plain error
* Change MigrateSidebarCategories to return a plain error
* Remove usage of UpdateColumns when updating sidebar categories (#14843)
* Remove usage of UpdateColumns when changing category order
* Add a random test case
* Remove usage of UpdateColumns when updating sidebar categories (#14843)
* Remove usage of UpdateColumns when changing category order
* Add a random test case
* Remove usage of UpdateColumns when updating sidebar categories (#14843)
* Remove usage of UpdateColumns when changing category order
* Add a random test case
* MM-26343 Make CreateInitialSidebarCategories idempotent (#14870)
* Fix bad merge
* Fix another bad merge
* Fix unintentionally removed i18n string
Co-authored-by: Eli Yukelzon <reflog@gmail.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
83a80a2422
Коммит
de6a57cdc3
@@ -46,6 +46,7 @@ type Routes struct {
|
|||||||
ChannelMember *mux.Router // 'api/v4/channels/{channel_id:[A-Za-z0-9]+}/members/{user_id:[A-Za-z0-9]+}'
|
ChannelMember *mux.Router // 'api/v4/channels/{channel_id:[A-Za-z0-9]+}/members/{user_id:[A-Za-z0-9]+}'
|
||||||
ChannelMembersForUser *mux.Router // 'api/v4/users/{user_id:[A-Za-z0-9]+}/teams/{team_id:[A-Za-z0-9]+}/channels/members'
|
ChannelMembersForUser *mux.Router // 'api/v4/users/{user_id:[A-Za-z0-9]+}/teams/{team_id:[A-Za-z0-9]+}/channels/members'
|
||||||
ChannelModerations *mux.Router // 'api/v4/channels/{channel_id:[A-Za-z0-9]+}/moderations'
|
ChannelModerations *mux.Router // 'api/v4/channels/{channel_id:[A-Za-z0-9]+}/moderations'
|
||||||
|
ChannelCategories *mux.Router // 'api/v4/users/{user_id:[A-Za-z0-9]+}/teams/{team_id:[A-Za-z0-9]+}/channels/categories'
|
||||||
|
|
||||||
Posts *mux.Router // 'api/v4/posts'
|
Posts *mux.Router // 'api/v4/posts'
|
||||||
Post *mux.Router // 'api/v4/posts/{post_id:[A-Za-z0-9]+}'
|
Post *mux.Router // 'api/v4/posts/{post_id:[A-Za-z0-9]+}'
|
||||||
@@ -160,6 +161,7 @@ func Init(configservice configservice.ConfigService, globalOptionsFunc app.AppOp
|
|||||||
api.BaseRoutes.ChannelMember = api.BaseRoutes.ChannelMembers.PathPrefix("/{user_id:[A-Za-z0-9]+}").Subrouter()
|
api.BaseRoutes.ChannelMember = api.BaseRoutes.ChannelMembers.PathPrefix("/{user_id:[A-Za-z0-9]+}").Subrouter()
|
||||||
api.BaseRoutes.ChannelMembersForUser = api.BaseRoutes.User.PathPrefix("/teams/{team_id:[A-Za-z0-9]+}/channels/members").Subrouter()
|
api.BaseRoutes.ChannelMembersForUser = api.BaseRoutes.User.PathPrefix("/teams/{team_id:[A-Za-z0-9]+}/channels/members").Subrouter()
|
||||||
api.BaseRoutes.ChannelModerations = api.BaseRoutes.Channel.PathPrefix("/moderations").Subrouter()
|
api.BaseRoutes.ChannelModerations = api.BaseRoutes.Channel.PathPrefix("/moderations").Subrouter()
|
||||||
|
api.BaseRoutes.ChannelCategories = api.BaseRoutes.User.PathPrefix("/teams/{team_id:[A-Za-z0-9]+}/channels/categories").Subrouter()
|
||||||
|
|
||||||
api.BaseRoutes.Posts = api.BaseRoutes.ApiRoot.PathPrefix("/posts").Subrouter()
|
api.BaseRoutes.Posts = api.BaseRoutes.ApiRoot.PathPrefix("/posts").Subrouter()
|
||||||
api.BaseRoutes.Post = api.BaseRoutes.Posts.PathPrefix("/{post_id:[A-Za-z0-9]+}").Subrouter()
|
api.BaseRoutes.Post = api.BaseRoutes.Posts.PathPrefix("/{post_id:[A-Za-z0-9]+}").Subrouter()
|
||||||
|
|||||||
260
api4/channel.go
260
api4/channel.go
@@ -35,6 +35,15 @@ func (api *API) InitChannel() {
|
|||||||
api.BaseRoutes.ChannelsForTeam.Handle("/search_autocomplete", api.ApiSessionRequired(autocompleteChannelsForTeamForSearch)).Methods("GET")
|
api.BaseRoutes.ChannelsForTeam.Handle("/search_autocomplete", api.ApiSessionRequired(autocompleteChannelsForTeamForSearch)).Methods("GET")
|
||||||
api.BaseRoutes.User.Handle("/teams/{team_id:[A-Za-z0-9]+}/channels", api.ApiSessionRequired(getChannelsForTeamForUser)).Methods("GET")
|
api.BaseRoutes.User.Handle("/teams/{team_id:[A-Za-z0-9]+}/channels", api.ApiSessionRequired(getChannelsForTeamForUser)).Methods("GET")
|
||||||
|
|
||||||
|
api.BaseRoutes.ChannelCategories.Handle("", api.ApiSessionRequired(getCategoriesForTeamForUser)).Methods("GET")
|
||||||
|
api.BaseRoutes.ChannelCategories.Handle("", api.ApiSessionRequired(createCategoryForTeamForUser)).Methods("POST")
|
||||||
|
api.BaseRoutes.ChannelCategories.Handle("", api.ApiSessionRequired(updateCategoriesForTeamForUser)).Methods("PUT")
|
||||||
|
api.BaseRoutes.ChannelCategories.Handle("/order", api.ApiSessionRequired(getCategoryOrderForTeamForUser)).Methods("GET")
|
||||||
|
api.BaseRoutes.ChannelCategories.Handle("/order", api.ApiSessionRequired(updateCategoryOrderForTeamForUser)).Methods("PUT")
|
||||||
|
api.BaseRoutes.ChannelCategories.Handle("/{category_id:[A-Za-z0-9]+}", api.ApiSessionRequired(getCategoryForTeamForUser)).Methods("GET")
|
||||||
|
api.BaseRoutes.ChannelCategories.Handle("/{category_id:[A-Za-z0-9]+}", api.ApiSessionRequired(updateCategoryForTeamForUser)).Methods("PUT")
|
||||||
|
api.BaseRoutes.ChannelCategories.Handle("/{category_id:[A-Za-z0-9]+}", api.ApiSessionRequired(deleteCategoryForTeamForUser)).Methods("DELETE")
|
||||||
|
|
||||||
api.BaseRoutes.Channel.Handle("", api.ApiSessionRequired(getChannel)).Methods("GET")
|
api.BaseRoutes.Channel.Handle("", api.ApiSessionRequired(getChannel)).Methods("GET")
|
||||||
api.BaseRoutes.Channel.Handle("", api.ApiSessionRequired(updateChannel)).Methods("PUT")
|
api.BaseRoutes.Channel.Handle("", api.ApiSessionRequired(updateChannel)).Methods("PUT")
|
||||||
api.BaseRoutes.Channel.Handle("/patch", api.ApiSessionRequired(patchChannel)).Methods("PUT")
|
api.BaseRoutes.Channel.Handle("/patch", api.ApiSessionRequired(patchChannel)).Methods("PUT")
|
||||||
@@ -1848,3 +1857,254 @@ func moveChannel(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Write([]byte(channel.ToJson()))
|
w.Write([]byte(channel.ToJson()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCategoriesForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId().RequireTeamId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
categories, err := c.App.GetSidebarCategories(c.Params.UserId, c.Params.TeamId)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(categories.ToJson())
|
||||||
|
}
|
||||||
|
|
||||||
|
func createCategoryForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId().RequireTeamId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("createCategoryForTeamForUser", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
|
||||||
|
categoryCreateRequest, err := model.SidebarCategoryFromJson(r.Body)
|
||||||
|
if err != nil || c.Params.UserId != categoryCreateRequest.UserId || c.Params.TeamId != categoryCreateRequest.TeamId {
|
||||||
|
c.SetInvalidParam("category")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if appErr := validateUserChannels("createCategoryForTeamForUser", c, c.Params.TeamId, c.Params.UserId, categoryCreateRequest.Channels); appErr != nil {
|
||||||
|
c.Err = appErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
category, appErr := c.App.CreateSidebarCategory(c.Params.UserId, c.Params.TeamId, categoryCreateRequest)
|
||||||
|
if appErr != nil {
|
||||||
|
c.Err = appErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
w.Write(category.ToJson())
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCategoryOrderForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId().RequireTeamId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
order, err := c.App.GetSidebarCategoryOrder(c.Params.UserId, c.Params.TeamId)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(model.ArrayToJson(order)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateCategoryOrderForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId().RequireTeamId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("updateCategoryOrderForTeamForUser", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
|
||||||
|
categoryOrder := model.ArrayFromJson(r.Body)
|
||||||
|
|
||||||
|
for _, categoryId := range categoryOrder {
|
||||||
|
if !c.App.SessionHasPermissionToCategory(*c.App.Session(), c.Params.UserId, c.Params.TeamId, categoryId) {
|
||||||
|
c.SetInvalidParam("category")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.App.UpdateSidebarCategoryOrder(c.Params.UserId, c.Params.TeamId, categoryOrder)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
w.Write([]byte(model.ArrayToJson(categoryOrder)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCategoryForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId().RequireTeamId().RequireCategoryId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToCategory(*c.App.Session(), c.Params.UserId, c.Params.TeamId, c.Params.CategoryId) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
categories, err := c.App.GetSidebarCategory(c.Params.CategoryId)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(categories.ToJson())
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateCategoriesForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId().RequireTeamId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToUser(*c.App.Session(), c.Params.UserId) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("updateCategoriesForTeamForUser", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
|
||||||
|
categoriesUpdateRequest, err := model.SidebarCategoriesFromJson(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
c.SetInvalidParam("category")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var channelsToCheck []string
|
||||||
|
for _, category := range categoriesUpdateRequest {
|
||||||
|
if !c.App.SessionHasPermissionToCategory(*c.App.Session(), c.Params.UserId, c.Params.TeamId, category.Id) {
|
||||||
|
c.SetInvalidParam("category")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
channelsToCheck = append(channelsToCheck, category.Channels...)
|
||||||
|
}
|
||||||
|
if appErr := validateUserChannels("updateCategoriesForTeamForUser", c, c.Params.TeamId, c.Params.UserId, channelsToCheck); appErr != nil {
|
||||||
|
c.Err = appErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
categories, appErr := c.App.UpdateSidebarCategories(c.Params.UserId, c.Params.TeamId, categoriesUpdateRequest)
|
||||||
|
if appErr != nil {
|
||||||
|
c.Err = appErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
w.Write(model.SidebarCategoriesWithChannelsToJson(categories))
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateUserChannels(operationName string, c *Context, teamId, userId string, channelIDs []string) *model.AppError {
|
||||||
|
channels, err := c.App.GetChannelsForUser(teamId, userId, false)
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("Api4."+operationName, "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, channelId := range channelIDs {
|
||||||
|
found := false
|
||||||
|
for _, channel := range *channels {
|
||||||
|
if channel.Id == channelId {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return model.NewAppError("Api4."+operationName, "api.invalid_channel", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateCategoryForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId().RequireTeamId().RequireCategoryId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToCategory(*c.App.Session(), c.Params.UserId, c.Params.TeamId, c.Params.CategoryId) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("updateCategoryForTeamForUser", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
|
||||||
|
categoryUpdateRequest, err := model.SidebarCategoryFromJson(r.Body)
|
||||||
|
if err != nil || categoryUpdateRequest.TeamId != c.Params.TeamId || categoryUpdateRequest.UserId != c.Params.UserId {
|
||||||
|
c.SetInvalidParam("category")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if appErr := validateUserChannels("updateCategoryForTeamForUser", c, c.Params.TeamId, c.Params.UserId, categoryUpdateRequest.Channels); appErr != nil {
|
||||||
|
c.Err = appErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
categoryUpdateRequest.Id = c.Params.CategoryId
|
||||||
|
|
||||||
|
categories, appErr := c.App.UpdateSidebarCategories(c.Params.UserId, c.Params.TeamId, []*model.SidebarCategoryWithChannels{categoryUpdateRequest})
|
||||||
|
if appErr != nil {
|
||||||
|
c.Err = appErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
w.Write(categories[0].ToJson())
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteCategoryForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId().RequireTeamId().RequireCategoryId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToCategory(*c.App.Session(), c.Params.UserId, c.Params.TeamId, c.Params.CategoryId) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec := c.MakeAuditRecord("deleteCategoryForTeamForUser", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
|
||||||
|
appErr := c.App.DeleteSidebarCategory(c.Params.UserId, c.Params.TeamId, c.Params.CategoryId)
|
||||||
|
if appErr != nil {
|
||||||
|
c.Err = appErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
ReturnStatusOK(w)
|
||||||
|
}
|
||||||
|
|||||||
@@ -3888,5 +3888,106 @@ func TestMoveChannel(t *testing.T) {
|
|||||||
require.NotNil(t, resp.Error)
|
require.NotNil(t, resp.Error)
|
||||||
CheckErrorMessage(t, resp, "app.channel.move_channel.members_do_not_match.error")
|
CheckErrorMessage(t, resp, "app.channel.move_channel.members_do_not_match.error")
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateCategoryForTeamForUser(t *testing.T) {
|
||||||
|
t.Run("should update the channel order of the Channels category", func(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
categories, resp := th.Client.GetSidebarCategoriesForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, "")
|
||||||
|
require.Nil(t, resp.Error)
|
||||||
|
require.Len(t, categories.Categories, 3)
|
||||||
|
require.Len(t, categories.Order, 3)
|
||||||
|
|
||||||
|
channelsCategory := categories.Categories[1]
|
||||||
|
require.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type)
|
||||||
|
require.Len(t, channelsCategory.Channels, 5) // Town Square, Off Topic, and the 3 channels created by InitBasic
|
||||||
|
|
||||||
|
// Should return the correct values from the API
|
||||||
|
updatedCategory := &model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: channelsCategory.SidebarCategory,
|
||||||
|
Channels: []string{channelsCategory.Channels[1], channelsCategory.Channels[0], channelsCategory.Channels[4], channelsCategory.Channels[3], channelsCategory.Channels[2]},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("UserId=" + th.BasicUser.Id)
|
||||||
|
t.Log("TeamId=" + th.BasicTeam.Id)
|
||||||
|
t.Log("category=" + channelsCategory.Id)
|
||||||
|
|
||||||
|
received, resp := th.Client.UpdateSidebarCategoryForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, channelsCategory.Id, updatedCategory)
|
||||||
|
assert.Nil(t, resp.Error)
|
||||||
|
assert.Equal(t, channelsCategory.Id, received.Id)
|
||||||
|
assert.Equal(t, updatedCategory.Channels, received.Channels)
|
||||||
|
|
||||||
|
// And when requesting the category later
|
||||||
|
received, resp = th.Client.GetSidebarCategoryForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, channelsCategory.Id, "")
|
||||||
|
assert.Nil(t, resp.Error)
|
||||||
|
assert.Equal(t, channelsCategory.Id, received.Id)
|
||||||
|
assert.Equal(t, updatedCategory.Channels, received.Channels)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should update the sort order of the DM category", func(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
categories, resp := th.Client.GetSidebarCategoriesForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, "")
|
||||||
|
require.Nil(t, resp.Error)
|
||||||
|
require.Len(t, categories.Categories, 3)
|
||||||
|
require.Len(t, categories.Order, 3)
|
||||||
|
|
||||||
|
dmsCategory := categories.Categories[2]
|
||||||
|
require.Equal(t, model.SidebarCategoryDirectMessages, dmsCategory.Type)
|
||||||
|
require.Equal(t, model.SidebarCategorySortRecent, dmsCategory.Sorting)
|
||||||
|
|
||||||
|
// Should return the correct values from the API
|
||||||
|
updatedCategory := &model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: dmsCategory.SidebarCategory,
|
||||||
|
Channels: dmsCategory.Channels,
|
||||||
|
}
|
||||||
|
updatedCategory.Sorting = model.SidebarCategorySortAlphabetical
|
||||||
|
|
||||||
|
received, resp := th.Client.UpdateSidebarCategoryForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, dmsCategory.Id, updatedCategory)
|
||||||
|
assert.Nil(t, resp.Error)
|
||||||
|
assert.Equal(t, dmsCategory.Id, received.Id)
|
||||||
|
assert.Equal(t, model.SidebarCategorySortAlphabetical, received.Sorting)
|
||||||
|
|
||||||
|
// And when requesting the category later
|
||||||
|
received, resp = th.Client.GetSidebarCategoryForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, dmsCategory.Id, "")
|
||||||
|
assert.Nil(t, resp.Error)
|
||||||
|
assert.Equal(t, dmsCategory.Id, received.Id)
|
||||||
|
assert.Equal(t, model.SidebarCategorySortAlphabetical, received.Sorting)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should update the display name of a custom category", func(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
customCategory, resp := th.Client.CreateSidebarCategoryForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, &model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: model.SidebarCategory{
|
||||||
|
UserId: th.BasicUser.Id,
|
||||||
|
TeamId: th.BasicTeam.Id,
|
||||||
|
DisplayName: "custom123",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.Nil(t, resp.Error)
|
||||||
|
require.Equal(t, "custom123", customCategory.DisplayName)
|
||||||
|
|
||||||
|
// Should return the correct values from the API
|
||||||
|
updatedCategory := &model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: customCategory.SidebarCategory,
|
||||||
|
Channels: customCategory.Channels,
|
||||||
|
}
|
||||||
|
updatedCategory.DisplayName = "abcCustom"
|
||||||
|
|
||||||
|
received, resp := th.Client.UpdateSidebarCategoryForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, customCategory.Id, updatedCategory)
|
||||||
|
assert.Nil(t, resp.Error)
|
||||||
|
assert.Equal(t, customCategory.Id, received.Id)
|
||||||
|
assert.Equal(t, updatedCategory.DisplayName, received.DisplayName)
|
||||||
|
|
||||||
|
// And when requesting the category later
|
||||||
|
received, resp = th.Client.GetSidebarCategoryForTeamForUser(th.BasicUser.Id, th.BasicTeam.Id, customCategory.Id, "")
|
||||||
|
assert.Nil(t, resp.Error)
|
||||||
|
assert.Equal(t, customCategory.Id, received.Id)
|
||||||
|
assert.Equal(t, updatedCategory.DisplayName, received.DisplayName)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -415,6 +415,7 @@ type AppIface interface {
|
|||||||
CreateRole(role *model.Role) (*model.Role, *model.AppError)
|
CreateRole(role *model.Role) (*model.Role, *model.AppError)
|
||||||
CreateScheme(scheme *model.Scheme) (*model.Scheme, *model.AppError)
|
CreateScheme(scheme *model.Scheme) (*model.Scheme, *model.AppError)
|
||||||
CreateSession(session *model.Session) (*model.Session, *model.AppError)
|
CreateSession(session *model.Session) (*model.Session, *model.AppError)
|
||||||
|
CreateSidebarCategory(userId, teamId string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError)
|
||||||
CreateTeam(team *model.Team) (*model.Team, *model.AppError)
|
CreateTeam(team *model.Team) (*model.Team, *model.AppError)
|
||||||
CreateTeamWithUser(team *model.Team, userId string) (*model.Team, *model.AppError)
|
CreateTeamWithUser(team *model.Team, userId string) (*model.Team, *model.AppError)
|
||||||
CreateTermsOfService(text, userId string) (*model.TermsOfService, *model.AppError)
|
CreateTermsOfService(text, userId string) (*model.TermsOfService, *model.AppError)
|
||||||
@@ -449,6 +450,7 @@ type AppIface interface {
|
|||||||
DeletePreferences(userId string, preferences model.Preferences) *model.AppError
|
DeletePreferences(userId string, preferences model.Preferences) *model.AppError
|
||||||
DeleteReactionForPost(reaction *model.Reaction) *model.AppError
|
DeleteReactionForPost(reaction *model.Reaction) *model.AppError
|
||||||
DeleteScheme(schemeId string) (*model.Scheme, *model.AppError)
|
DeleteScheme(schemeId string) (*model.Scheme, *model.AppError)
|
||||||
|
DeleteSidebarCategory(userId, teamId, categoryId string) *model.AppError
|
||||||
DeleteToken(token *model.Token) *model.AppError
|
DeleteToken(token *model.Token) *model.AppError
|
||||||
DiagnosticId() string
|
DiagnosticId() string
|
||||||
DisableAutoResponder(userId string, asAdmin bool) *model.AppError
|
DisableAutoResponder(userId string, asAdmin bool) *model.AppError
|
||||||
@@ -633,6 +635,9 @@ type AppIface interface {
|
|||||||
GetSession(token string) (*model.Session, *model.AppError)
|
GetSession(token string) (*model.Session, *model.AppError)
|
||||||
GetSessionById(sessionId string) (*model.Session, *model.AppError)
|
GetSessionById(sessionId string) (*model.Session, *model.AppError)
|
||||||
GetSessions(userId string) ([]*model.Session, *model.AppError)
|
GetSessions(userId string) ([]*model.Session, *model.AppError)
|
||||||
|
GetSidebarCategories(userId, teamId string) (*model.OrderedSidebarCategories, *model.AppError)
|
||||||
|
GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError)
|
||||||
|
GetSidebarCategoryOrder(userId, teamId string) ([]string, *model.AppError)
|
||||||
GetSinglePost(postId string) (*model.Post, *model.AppError)
|
GetSinglePost(postId string) (*model.Post, *model.AppError)
|
||||||
GetSiteURL() string
|
GetSiteURL() string
|
||||||
GetStatus(userId string) (*model.Status, *model.AppError)
|
GetStatus(userId string) (*model.Status, *model.AppError)
|
||||||
@@ -861,6 +866,7 @@ type AppIface interface {
|
|||||||
Session() *model.Session
|
Session() *model.Session
|
||||||
SessionCacheLength() int
|
SessionCacheLength() int
|
||||||
SessionHasPermissionTo(session model.Session, permission *model.Permission) bool
|
SessionHasPermissionTo(session model.Session, permission *model.Permission) bool
|
||||||
|
SessionHasPermissionToCategory(session model.Session, userId, teamId, categoryId string) bool
|
||||||
SessionHasPermissionToChannel(session model.Session, channelId string, permission *model.Permission) bool
|
SessionHasPermissionToChannel(session model.Session, channelId string, permission *model.Permission) bool
|
||||||
SessionHasPermissionToChannelByPost(session model.Session, postId string, permission *model.Permission) bool
|
SessionHasPermissionToChannelByPost(session model.Session, postId string, permission *model.Permission) bool
|
||||||
SessionHasPermissionToTeam(session model.Session, teamId string, permission *model.Permission) bool
|
SessionHasPermissionToTeam(session model.Session, teamId string, permission *model.Permission) bool
|
||||||
@@ -953,6 +959,8 @@ type AppIface interface {
|
|||||||
UpdateRole(role *model.Role) (*model.Role, *model.AppError)
|
UpdateRole(role *model.Role) (*model.Role, *model.AppError)
|
||||||
UpdateScheme(scheme *model.Scheme) (*model.Scheme, *model.AppError)
|
UpdateScheme(scheme *model.Scheme) (*model.Scheme, *model.AppError)
|
||||||
UpdateSessionsIsGuest(userId string, isGuest bool)
|
UpdateSessionsIsGuest(userId string, isGuest bool)
|
||||||
|
UpdateSidebarCategories(userId, teamId string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError)
|
||||||
|
UpdateSidebarCategoryOrder(userId, teamId string, categoryOrder []string) *model.AppError
|
||||||
UpdateTeam(team *model.Team) (*model.Team, *model.AppError)
|
UpdateTeam(team *model.Team) (*model.Team, *model.AppError)
|
||||||
UpdateTeamMemberRoles(teamId string, userId string, newRoles string) (*model.TeamMember, *model.AppError)
|
UpdateTeamMemberRoles(teamId string, userId string, newRoles string) (*model.TeamMember, *model.AppError)
|
||||||
UpdateTeamMemberSchemeRoles(teamId string, userId string, isSchemeGuest bool, isSchemeUser bool, isSchemeAdmin bool) (*model.TeamMember, *model.AppError)
|
UpdateTeamMemberSchemeRoles(teamId string, userId string, isSchemeGuest bool, isSchemeUser bool, isSchemeAdmin bool) (*model.TeamMember, *model.AppError)
|
||||||
|
|||||||
@@ -89,6 +89,14 @@ func (a *App) SessionHasPermissionToChannelByPost(session model.Session, postId
|
|||||||
return a.SessionHasPermissionTo(session, permission)
|
return a.SessionHasPermissionTo(session, permission)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) SessionHasPermissionToCategory(session model.Session, userId, teamId, categoryId string) bool {
|
||||||
|
if a.SessionHasPermissionTo(session, model.PERMISSION_EDIT_OTHER_USERS) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
category, err := a.GetSidebarCategory(categoryId)
|
||||||
|
return err == nil && category != nil && category.UserId == session.UserId && category.UserId == userId && category.TeamId == teamId
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) SessionHasPermissionToUser(session model.Session, userId string) bool {
|
func (a *App) SessionHasPermissionToUser(session model.Session, userId string) bool {
|
||||||
if userId == "" {
|
if userId == "" {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -2383,6 +2383,10 @@ func (a *App) MoveChannel(team *model.Team, channel *model.Channel, user *model.
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if appErr := a.Srv().Store.Channel().UpdateSidebarChannelCategoryOnMove(channel, team.Id); appErr != nil {
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
|
||||||
channel.TeamId = team.Id
|
channel.TeamId = team.Id
|
||||||
if _, err := a.Srv().Store.Channel().Update(channel); err != nil {
|
if _, err := a.Srv().Store.Channel().Update(channel); err != nil {
|
||||||
var appErr *model.AppError
|
var appErr *model.AppError
|
||||||
@@ -2598,3 +2602,70 @@ func (a *App) ClearChannelMembersCache(channelID string) {
|
|||||||
page++
|
page++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) createInitialSidebarCategories(user *model.User, team *model.Team) *model.AppError {
|
||||||
|
nErr := a.Srv().Store.Channel().CreateInitialSidebarCategories(user, team.Id)
|
||||||
|
|
||||||
|
if nErr != nil {
|
||||||
|
return model.NewAppError("createInitialSidebarCategories", "app.channel.create_initial_sidebar_categories.internal_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) GetSidebarCategories(userId, teamId string) (*model.OrderedSidebarCategories, *model.AppError) {
|
||||||
|
return a.Srv().Store.Channel().GetSidebarCategories(userId, teamId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) GetSidebarCategoryOrder(userId, teamId string) ([]string, *model.AppError) {
|
||||||
|
return a.Srv().Store.Channel().GetSidebarCategoryOrder(userId, teamId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
return a.Srv().Store.Channel().GetSidebarCategory(categoryId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) CreateSidebarCategory(userId, teamId string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
category, err := a.Srv().Store.Channel().CreateSidebarCategory(userId, teamId, newCategory)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_SIDEBAR_CATEGORY_CREATED, teamId, "", userId, nil)
|
||||||
|
message.Add("category_id", category.Id)
|
||||||
|
a.Publish(message)
|
||||||
|
return category, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) UpdateSidebarCategoryOrder(userId, teamId string, categoryOrder []string) *model.AppError {
|
||||||
|
err := a.Srv().Store.Channel().UpdateSidebarCategoryOrder(userId, teamId, categoryOrder)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_SIDEBAR_CATEGORY_ORDER_UPDATED, teamId, "", userId, nil)
|
||||||
|
message.Add("order", categoryOrder)
|
||||||
|
a.Publish(message)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) UpdateSidebarCategories(userId, teamId string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
result, err := a.Srv().Store.Channel().UpdateSidebarCategories(userId, teamId, categories)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_SIDEBAR_CATEGORY_UPDATED, teamId, "", userId, nil)
|
||||||
|
a.Publish(message)
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) DeleteSidebarCategory(userId, teamId, categoryId string) *model.AppError {
|
||||||
|
err := a.Srv().Store.Channel().DeleteSidebarCategory(categoryId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_SIDEBAR_CATEGORY_DELETED, teamId, "", userId, nil)
|
||||||
|
message.Add("category_id", categoryId)
|
||||||
|
a.Publish(message)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1795,3 +1795,66 @@ func TestMarkChannelsAsViewedPanic(t *testing.T) {
|
|||||||
_, err := th.App.MarkChannelsAsViewed([]string{"channelID"}, "userID", th.App.Session().Id)
|
_, err := th.App.MarkChannelsAsViewed([]string{"channelID"}, "userID", th.App.Session().Id)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSidebarCategory(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
basicChannel2 := th.CreateChannel(th.BasicTeam)
|
||||||
|
defer th.App.PermanentDeleteChannel(basicChannel2)
|
||||||
|
user := th.CreateUser()
|
||||||
|
defer th.App.Srv().Store.User().PermanentDelete(user.Id)
|
||||||
|
th.LinkUserToTeam(user, th.BasicTeam)
|
||||||
|
th.AddUserToChannel(user, basicChannel2)
|
||||||
|
|
||||||
|
var createdCategory *model.SidebarCategoryWithChannels
|
||||||
|
t.Run("CreateSidebarCategory", func(t *testing.T) {
|
||||||
|
catData := model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: model.SidebarCategory{
|
||||||
|
DisplayName: "TEST",
|
||||||
|
},
|
||||||
|
Channels: []string{th.BasicChannel.Id, basicChannel2.Id, basicChannel2.Id},
|
||||||
|
}
|
||||||
|
_, err := th.App.CreateSidebarCategory(user.Id, th.BasicTeam.Id, &catData)
|
||||||
|
require.NotNil(t, err, "Should return error due to duplicate IDs")
|
||||||
|
catData.Channels = []string{th.BasicChannel.Id, basicChannel2.Id}
|
||||||
|
cat, err := th.App.CreateSidebarCategory(user.Id, th.BasicTeam.Id, &catData)
|
||||||
|
require.Nil(t, err, "Expected no error")
|
||||||
|
require.NotNil(t, cat, "Expected category object, got nil")
|
||||||
|
createdCategory = cat
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UpdateSidebarCategories", func(t *testing.T) {
|
||||||
|
require.NotNil(t, createdCategory)
|
||||||
|
createdCategory.Channels = []string{th.BasicChannel.Id}
|
||||||
|
updatedCat, err := th.App.UpdateSidebarCategories(user.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{createdCategory})
|
||||||
|
require.Nil(t, err, "Expected no error")
|
||||||
|
require.NotNil(t, updatedCat, "Expected category object, got nil")
|
||||||
|
require.Len(t, updatedCat, 1)
|
||||||
|
require.Len(t, updatedCat[0].Channels, 1)
|
||||||
|
require.Equal(t, updatedCat[0].Channels[0], th.BasicChannel.Id)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UpdateSidebarCategoryOrder", func(t *testing.T) {
|
||||||
|
err := th.App.UpdateSidebarCategoryOrder(user.Id, th.BasicTeam.Id, []string{th.BasicChannel.Id, basicChannel2.Id})
|
||||||
|
require.NotNil(t, err, "Should return error due to invalid order")
|
||||||
|
|
||||||
|
actualOrder, err := th.App.GetSidebarCategoryOrder(user.Id, th.BasicTeam.Id)
|
||||||
|
require.Nil(t, err, "Should fetch order successfully")
|
||||||
|
|
||||||
|
actualOrder[2], actualOrder[3] = actualOrder[3], actualOrder[2]
|
||||||
|
err = th.App.UpdateSidebarCategoryOrder(user.Id, th.BasicTeam.Id, actualOrder)
|
||||||
|
require.Nil(t, err, "Should update order successfully")
|
||||||
|
|
||||||
|
actualOrder[2] = "asd"
|
||||||
|
err = th.App.UpdateSidebarCategoryOrder(user.Id, th.BasicTeam.Id, actualOrder)
|
||||||
|
require.NotNil(t, err, "Should return error due to invalid id")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("GetSidebarCategoryOrder", func(t *testing.T) {
|
||||||
|
catOrder, err := th.App.GetSidebarCategoryOrder(user.Id, th.BasicTeam.Id)
|
||||||
|
require.Nil(t, err, "Expected no error")
|
||||||
|
require.Len(t, catOrder, 4)
|
||||||
|
require.Equal(t, catOrder[1], createdCategory.Id, "the newly created category should be after favorites")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -2025,6 +2025,28 @@ func (a *OpenTracingAppLayer) CreateSession(session *model.Session) (*model.Sess
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) CreateSidebarCategory(userId string, teamId string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateSidebarCategory")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.CreateSidebarCategory(userId, teamId, newCategory)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) CreateTeam(team *model.Team) (*model.Team, *model.AppError) {
|
func (a *OpenTracingAppLayer) CreateTeam(team *model.Team) (*model.Team, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateTeam")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateTeam")
|
||||||
@@ -2857,6 +2879,28 @@ func (a *OpenTracingAppLayer) DeleteScheme(schemeId string) (*model.Scheme, *mod
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) DeleteSidebarCategory(userId string, teamId string, categoryId string) *model.AppError {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.DeleteSidebarCategory")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.DeleteSidebarCategory(userId, teamId, categoryId)
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) DeleteToken(token *model.Token) *model.AppError {
|
func (a *OpenTracingAppLayer) DeleteToken(token *model.Token) *model.AppError {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.DeleteToken")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.DeleteToken")
|
||||||
@@ -7539,6 +7583,72 @@ func (a *OpenTracingAppLayer) GetSessions(userId string) ([]*model.Session, *mod
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) GetSidebarCategories(userId string, teamId string) (*model.OrderedSidebarCategories, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetSidebarCategories")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.GetSidebarCategories(userId, teamId)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetSidebarCategory")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.GetSidebarCategory(categoryId)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) GetSidebarCategoryOrder(userId string, teamId string) ([]string, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetSidebarCategoryOrder")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.GetSidebarCategoryOrder(userId, teamId)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) GetSinglePost(postId string) (*model.Post, *model.AppError) {
|
func (a *OpenTracingAppLayer) GetSinglePost(postId string) (*model.Post, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetSinglePost")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetSinglePost")
|
||||||
@@ -12642,6 +12752,23 @@ func (a *OpenTracingAppLayer) SessionHasPermissionTo(session model.Session, perm
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) SessionHasPermissionToCategory(session model.Session, userId string, teamId string, categoryId string) bool {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToCategory")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.SessionHasPermissionToCategory(session, userId, teamId, categoryId)
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) SessionHasPermissionToChannel(session model.Session, channelId string, permission *model.Permission) bool {
|
func (a *OpenTracingAppLayer) SessionHasPermissionToChannel(session model.Session, channelId string, permission *model.Permission) bool {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToChannel")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToChannel")
|
||||||
@@ -14484,6 +14611,50 @@ func (a *OpenTracingAppLayer) UpdateSessionsIsGuest(userId string, isGuest bool)
|
|||||||
a.app.UpdateSessionsIsGuest(userId, isGuest)
|
a.app.UpdateSessionsIsGuest(userId, isGuest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) UpdateSidebarCategories(userId string, teamId string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateSidebarCategories")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.UpdateSidebarCategories(userId, teamId, categories)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) UpdateSidebarCategoryOrder(userId string, teamId string, categoryOrder []string) *model.AppError {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateSidebarCategoryOrder")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.UpdateSidebarCategoryOrder(userId, teamId, categoryOrder)
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) {
|
func (a *OpenTracingAppLayer) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateTeam")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateTeam")
|
||||||
|
|||||||
@@ -53,7 +53,13 @@ func (a *App) UpdatePreferences(userId string, preferences model.Preferences) *m
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PREFERENCES_CHANGED, "", "", userId, nil)
|
if err := a.Srv().Store.Channel().UpdateSidebarChannelsByPreferences(&preferences); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_SIDEBAR_CATEGORY_UPDATED, "", "", userId, nil)
|
||||||
|
a.Publish(message)
|
||||||
|
|
||||||
|
message = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PREFERENCES_CHANGED, "", "", userId, nil)
|
||||||
message.Add("preferences", preferences.ToJson())
|
message.Add("preferences", preferences.ToJson())
|
||||||
a.Publish(message)
|
a.Publish(message)
|
||||||
|
|
||||||
|
|||||||
16
app/team.go
16
app/team.go
@@ -653,6 +653,15 @@ func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := a.createInitialSidebarCategories(user, team); err != nil {
|
||||||
|
mlog.Error(
|
||||||
|
"Encountered an issue creating default sidebar categories.",
|
||||||
|
mlog.String("user_id", user.Id),
|
||||||
|
mlog.String("team_id", team.Id),
|
||||||
|
mlog.Err(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
shouldBeAdmin := team.Email == user.Email
|
shouldBeAdmin := team.Email == user.Email
|
||||||
|
|
||||||
if !user.IsGuest() {
|
if !user.IsGuest() {
|
||||||
@@ -969,6 +978,10 @@ func (a *App) RemoveTeamMemberFromTeam(teamMember *model.TeamMember, requestorId
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := a.Srv().Store.Channel().ClearSidebarOnTeamLeave(user.Id, teamMember.TeamId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// delete the preferences that set the last channel used in the team and other team specific preferences
|
// delete the preferences that set the last channel used in the team and other team specific preferences
|
||||||
if err := a.Srv().Store.Preference().DeleteCategory(user.Id, teamMember.TeamId); err != nil {
|
if err := a.Srv().Store.Preference().DeleteCategory(user.Id, teamMember.TeamId); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1031,8 +1044,7 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.RemoveTeamMemberFromTeam(teamMember, requestorId)
|
if err := a.RemoveTeamMemberFromTeam(teamMember, requestorId); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,21 @@ func TestAddUserToTeam(t *testing.T) {
|
|||||||
_, err = th.App.AddUserToTeam(th.BasicTeam.Id, ruser3.Id, "")
|
_, err = th.App.AddUserToTeam(th.BasicTeam.Id, ruser3.Id, "")
|
||||||
require.NotNil(t, err, "Should not have allowed restricted user3")
|
require.NotNil(t, err, "Should not have allowed restricted user3")
|
||||||
require.Equal(t, "JoinUserToTeam", err.Where, "Error should be JoinUserToTeam")
|
require.Equal(t, "JoinUserToTeam", err.Where, "Error should be JoinUserToTeam")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should set up initial sidebar categories when joining a team", func(t *testing.T) {
|
||||||
|
user := th.CreateUser()
|
||||||
|
team := th.CreateTeam()
|
||||||
|
|
||||||
|
_, err := th.App.AddUserToTeam(team.Id, user.Id, "")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
res, err := th.App.GetSidebarCategories(user.Id, team.Id)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Len(t, res.Categories, 3)
|
||||||
|
assert.Equal(t, model.SidebarCategoryFavorites, res.Categories[0].Type)
|
||||||
|
assert.Equal(t, model.SidebarCategoryChannels, res.Categories[1].Type)
|
||||||
|
assert.Equal(t, model.SidebarCategoryDirectMessages, res.Categories[2].Type)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,6 +404,27 @@ func TestAddUserToTeamByToken(t *testing.T) {
|
|||||||
require.NotNil(t, err, "Should not add restricted user")
|
require.NotNil(t, err, "Should not add restricted user")
|
||||||
require.Equal(t, "JoinUserToTeam", err.Where, "Error should be JoinUserToTeam")
|
require.Equal(t, "JoinUserToTeam", err.Where, "Error should be JoinUserToTeam")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("should set up initial sidebar categories when joining a team by token", func(t *testing.T) {
|
||||||
|
user := th.CreateUser()
|
||||||
|
team := th.CreateTeam()
|
||||||
|
|
||||||
|
token := model.NewToken(
|
||||||
|
TOKEN_TYPE_TEAM_INVITATION,
|
||||||
|
model.MapToJson(map[string]string{"teamId": team.Id}),
|
||||||
|
)
|
||||||
|
require.Nil(t, th.App.Srv().Store.Token().Save(token))
|
||||||
|
|
||||||
|
_, err := th.App.AddUserToTeamByToken(user.Id, token.Token)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
res, err := th.App.GetSidebarCategories(user.Id, team.Id)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Len(t, res.Categories, 3)
|
||||||
|
assert.Equal(t, model.SidebarCategoryFavorites, res.Categories[0].Type)
|
||||||
|
assert.Equal(t, model.SidebarCategoryChannels, res.Categories[1].Type)
|
||||||
|
assert.Equal(t, model.SidebarCategoryDirectMessages, res.Categories[2].Type)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddUserToTeamByTeamId(t *testing.T) {
|
func TestAddUserToTeamByTeamId(t *testing.T) {
|
||||||
|
|||||||
44
i18n/en.json
44
i18n/en.json
@@ -1428,6 +1428,10 @@
|
|||||||
"id": "api.incoming_webhook.invalid_username.app_error",
|
"id": "api.incoming_webhook.invalid_username.app_error",
|
||||||
"translation": "Invalid username."
|
"translation": "Invalid username."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.invalid_channel",
|
||||||
|
"translation": "Channel listed in the request doesn't belong to the user"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.io_error",
|
"id": "api.io_error",
|
||||||
"translation": "input/output error"
|
"translation": "input/output error"
|
||||||
@@ -3030,6 +3034,10 @@
|
|||||||
"id": "app.channel.create_direct_channel.internal_error",
|
"id": "app.channel.create_direct_channel.internal_error",
|
||||||
"translation": "Unable to save direct channel."
|
"translation": "Unable to save direct channel."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "app.channel.create_initial_sidebar_categories.internal_error",
|
||||||
|
"translation": "Unable to create initial sidebar categories for user."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "app.channel.delete.app_error",
|
"id": "app.channel.delete.app_error",
|
||||||
"translation": "Unable to delete the channel."
|
"translation": "Unable to delete the channel."
|
||||||
@@ -4862,6 +4870,14 @@
|
|||||||
"id": "migrations.worker.run_migration.unknown_key",
|
"id": "migrations.worker.run_migration.unknown_key",
|
||||||
"translation": "Unable to run migration job due to unknown migration key."
|
"translation": "Unable to run migration job due to unknown migration key."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "migrations.worker.run_sidebar_categories_phase_2_migration.internal_error",
|
||||||
|
"translation": "Migration failed due to database error."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "migrations.worker.run_sidebar_categories_phase_2_migration.invalid_progress",
|
||||||
|
"translation": "Migration failed due to invalid progress data."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "model.access.is_valid.access_token.app_error",
|
"id": "model.access.is_valid.access_token.app_error",
|
||||||
"translation": "Invalid access token."
|
"translation": "Invalid access token."
|
||||||
@@ -6194,6 +6210,18 @@
|
|||||||
"id": "searchengine.bleve.disabled.error",
|
"id": "searchengine.bleve.disabled.error",
|
||||||
"translation": "Error purging Bleve indexes: engine is disabled"
|
"translation": "Error purging Bleve indexes: engine is disabled"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "sidebar.category.channels",
|
||||||
|
"translation": "Channels"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sidebar.category.dm",
|
||||||
|
"translation": "Direct Messages"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "sidebar.category.favorites",
|
||||||
|
"translation": "Favorites"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "store.insert_error",
|
"id": "store.insert_error",
|
||||||
"translation": "insert error"
|
"translation": "insert error"
|
||||||
@@ -6426,6 +6454,22 @@
|
|||||||
"id": "store.sql_channel.search_group_channels.app_error",
|
"id": "store.sql_channel.search_group_channels.app_error",
|
||||||
"translation": "Unable to get the group channels for the given user and term."
|
"translation": "Unable to get the group channels for the given user and term."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_channel.sidebar_categories.app_error",
|
||||||
|
"translation": "Failed to insert record to database."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_channel.sidebar_categories.commit_transaction.app_error",
|
||||||
|
"translation": "Unable to commit transaction."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_channel.sidebar_categories.delete_invalid.app_error",
|
||||||
|
"translation": "Unable to delete non-custom category."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_channel.sidebar_categories.open_transaction.app_error",
|
||||||
|
"translation": "Failed to open the database transaction."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "store.sql_channel.update_last_viewed_at.app_error",
|
"id": "store.sql_channel.update_last_viewed_at.app_error",
|
||||||
"translation": "Unable to update the last viewed at time."
|
"translation": "Unable to update the last viewed at time."
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ func init() {
|
|||||||
func MakeMigrationsList() []string {
|
func MakeMigrationsList() []string {
|
||||||
return []string{
|
return []string{
|
||||||
model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2,
|
model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2,
|
||||||
|
model.MIGRATION_KEY_SIDEBAR_CATEGORIES_PHASE_2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
128
migrations/sidebar_categories_phase_2.go
Обычный файл
128
migrations/sidebar_categories_phase_2.go
Обычный файл
@@ -0,0 +1,128 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProgressStep string
|
||||||
|
|
||||||
|
const (
|
||||||
|
StepCategories ProgressStep = "populateSidebarCategories"
|
||||||
|
StepFavorites ProgressStep = "migrateFavoriteChannelToSidebarChannels"
|
||||||
|
StepEnd ProgressStep = "endMigration"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Progress struct {
|
||||||
|
CurrentStep ProgressStep `json:"current_state"`
|
||||||
|
LastTeamId string `json:"last_team_id"`
|
||||||
|
LastChannelId string `json:"last_channel_id"`
|
||||||
|
LastUserId string `json:"last_user"`
|
||||||
|
LastSortOrder int64 `json:"last_sort_order"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Progress) ToJson() string {
|
||||||
|
b, _ := json.Marshal(p)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProgressFromJson(data io.Reader) *Progress {
|
||||||
|
var o *Progress
|
||||||
|
json.NewDecoder(data).Decode(&o)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Progress) IsValid() bool {
|
||||||
|
if len(p.LastChannelId) != 26 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.LastTeamId) != 26 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.LastUserId) != 26 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch p.CurrentStep {
|
||||||
|
case StepCategories, StepFavorites:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProgress(step ProgressStep) *Progress {
|
||||||
|
progress := new(Progress)
|
||||||
|
progress.CurrentStep = step
|
||||||
|
progress.LastChannelId = strings.Repeat("0", 26)
|
||||||
|
progress.LastTeamId = strings.Repeat("0", 26)
|
||||||
|
progress.LastUserId = strings.Repeat("0", 26)
|
||||||
|
progress.LastSortOrder = 0
|
||||||
|
return progress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *Worker) runSidebarCategoriesPhase2Migration(lastDone string) (bool, string, *model.AppError) {
|
||||||
|
var progress *Progress
|
||||||
|
if len(lastDone) == 0 {
|
||||||
|
progress = newProgress(StepCategories)
|
||||||
|
} else {
|
||||||
|
progress = ProgressFromJson(strings.NewReader(lastDone))
|
||||||
|
if !progress.IsValid() {
|
||||||
|
return false, "", model.NewAppError("MigrationsWorker.runSidebarCategoriesPhase2Migration", "migrations.worker.run_sidebar_categories_phase_2_migration.invalid_progress", map[string]interface{}{"progress": progress.ToJson()}, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result map[string]interface{}
|
||||||
|
var nErr error
|
||||||
|
var nextStep ProgressStep
|
||||||
|
switch progress.CurrentStep {
|
||||||
|
case StepCategories:
|
||||||
|
result, nErr = worker.srv.Store.Channel().MigrateSidebarCategories(progress.LastTeamId, progress.LastUserId)
|
||||||
|
nextStep = StepFavorites
|
||||||
|
case StepFavorites:
|
||||||
|
result, nErr = worker.srv.Store.Channel().MigrateFavoritesToSidebarChannels(progress.LastUserId, progress.LastSortOrder)
|
||||||
|
nextStep = StepEnd
|
||||||
|
default:
|
||||||
|
return false, "", model.NewAppError("MigrationsWorker.runSidebarCategoriesPhase2Migration", "migrations.worker.run_sidebar_categories_phase_2_migration.invalid_progress", map[string]interface{}{"progress": progress.ToJson()}, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nErr != nil {
|
||||||
|
return false, progress.ToJson(), model.NewAppError("MigrationsWorker.runSidebarCategoriesPhase2Migration", "migrations.worker.run_sidebar_categories_phase_2_migration.internal_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
// We haven't progressed. That means that we've reached the end of this stage of the migration, and should now advance to the next stage or stop
|
||||||
|
if nextStep != StepEnd {
|
||||||
|
progress = newProgress(nextStep)
|
||||||
|
return false, progress.ToJson(), nil
|
||||||
|
}
|
||||||
|
return true, progress.ToJson(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.LastChannelId = strings.Repeat("0", 26)
|
||||||
|
progress.LastTeamId = strings.Repeat("0", 26)
|
||||||
|
progress.LastUserId = strings.Repeat("0", 26)
|
||||||
|
progress.LastSortOrder = 0
|
||||||
|
if val, ok := result["UserId"].(string); ok {
|
||||||
|
progress.LastUserId = val
|
||||||
|
}
|
||||||
|
if val, ok := result["TeamId"].(string); ok {
|
||||||
|
progress.LastTeamId = val
|
||||||
|
}
|
||||||
|
if val, ok := result["ChannelId"].(string); ok {
|
||||||
|
progress.LastChannelId = val
|
||||||
|
}
|
||||||
|
if val, ok := result["SortOrder"].(int64); ok {
|
||||||
|
progress.LastSortOrder = val
|
||||||
|
}
|
||||||
|
return false, progress.ToJson(), nil
|
||||||
|
}
|
||||||
@@ -150,6 +150,8 @@ func (worker *Worker) runMigration(key string, lastDone string) (bool, string, *
|
|||||||
var err *model.AppError
|
var err *model.AppError
|
||||||
|
|
||||||
switch key {
|
switch key {
|
||||||
|
case model.MIGRATION_KEY_SIDEBAR_CATEGORIES_PHASE_2:
|
||||||
|
done, progress, err = worker.runSidebarCategoriesPhase2Migration(lastDone)
|
||||||
case model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2:
|
case model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2:
|
||||||
done, progress, err = worker.runAdvancedPermissionsPhase2Migration(lastDone)
|
done, progress, err = worker.runAdvancedPermissionsPhase2Migration(lastDone)
|
||||||
default:
|
default:
|
||||||
|
|||||||
111
model/channel_sidebar.go
Обычный файл
111
model/channel_sidebar.go
Обычный файл
@@ -0,0 +1,111 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SidebarCategoryType string
|
||||||
|
type SidebarCategorySorting string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Each sidebar category has a 'type'. System categories are Channels, Favorites and DMs
|
||||||
|
// All user-created categories will have type Custom
|
||||||
|
SidebarCategoryChannels SidebarCategoryType = "channels"
|
||||||
|
SidebarCategoryDirectMessages SidebarCategoryType = "direct_messages"
|
||||||
|
SidebarCategoryFavorites SidebarCategoryType = "favorites"
|
||||||
|
SidebarCategoryCustom SidebarCategoryType = "custom"
|
||||||
|
// Increment to use when adding/reordering things in the sidebar
|
||||||
|
MinimalSidebarSortDistance = 10
|
||||||
|
// Default Sort Orders for categories
|
||||||
|
DefaultSidebarSortOrderFavorites = 0
|
||||||
|
DefaultSidebarSortOrderChannels = DefaultSidebarSortOrderFavorites + MinimalSidebarSortDistance
|
||||||
|
DefaultSidebarSortOrderDMs = DefaultSidebarSortOrderChannels + MinimalSidebarSortDistance
|
||||||
|
// Sorting modes
|
||||||
|
// default for all categories except DMs (behaves like manual)
|
||||||
|
SidebarCategorySortDefault SidebarCategorySorting = ""
|
||||||
|
// sort manually
|
||||||
|
SidebarCategorySortManual SidebarCategorySorting = "manual"
|
||||||
|
// sort by recency (default for DMs)
|
||||||
|
SidebarCategorySortRecent SidebarCategorySorting = "recent"
|
||||||
|
// sort by display name alphabetically
|
||||||
|
SidebarCategorySortAlphabetical SidebarCategorySorting = "alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SidebarCategory represents the corresponding DB table
|
||||||
|
// SortOrder is never returned to the user and only used for queries
|
||||||
|
type SidebarCategory struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
TeamId string `json:"team_id"`
|
||||||
|
SortOrder int64 `json:"-"`
|
||||||
|
Sorting SidebarCategorySorting `json:"sorting"`
|
||||||
|
Type SidebarCategoryType `json:"type"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SidebarCategoryWithChannels combines data from SidebarCategory table with the Channel IDs that belong to that category
|
||||||
|
type SidebarCategoryWithChannels struct {
|
||||||
|
SidebarCategory
|
||||||
|
Channels []string `json:"channel_ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SidebarCategoryOrder []string
|
||||||
|
|
||||||
|
// OrderedSidebarCategories combines categories, their channel IDs and an array of Category IDs, sorted
|
||||||
|
type OrderedSidebarCategories struct {
|
||||||
|
Categories SidebarCategoriesWithChannels `json:"categories"`
|
||||||
|
Order SidebarCategoryOrder `json:"order"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SidebarChannel struct {
|
||||||
|
ChannelId string `json:"channel_id"`
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
CategoryId string `json:"category_id"`
|
||||||
|
SortOrder int64 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SidebarChannels []*SidebarChannel
|
||||||
|
type SidebarCategoriesWithChannels []*SidebarCategoryWithChannels
|
||||||
|
|
||||||
|
func SidebarCategoryFromJson(data io.Reader) (*SidebarCategoryWithChannels, error) {
|
||||||
|
var o *SidebarCategoryWithChannels
|
||||||
|
err := json.NewDecoder(data).Decode(&o)
|
||||||
|
return o, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SidebarCategoriesFromJson(data io.Reader) ([]*SidebarCategoryWithChannels, error) {
|
||||||
|
var o []*SidebarCategoryWithChannels
|
||||||
|
err := json.NewDecoder(data).Decode(&o)
|
||||||
|
return o, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func OrderedSidebarCategoriesFromJson(data io.Reader) (*OrderedSidebarCategories, error) {
|
||||||
|
var o *OrderedSidebarCategories
|
||||||
|
err := json.NewDecoder(data).Decode(&o)
|
||||||
|
return o, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o SidebarCategoryWithChannels) ToJson() []byte {
|
||||||
|
b, _ := json.Marshal(o)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func SidebarCategoriesWithChannelsToJson(o []*SidebarCategoryWithChannels) []byte {
|
||||||
|
if b, err := json.Marshal(o); err != nil {
|
||||||
|
return []byte("[]")
|
||||||
|
} else {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OrderedSidebarCategories) ToJson() []byte {
|
||||||
|
if b, err := json.Marshal(o); err != nil {
|
||||||
|
return []byte("[]")
|
||||||
|
} else {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -174,6 +174,10 @@ func (c *Client4) GetUserRoute(userId string) string {
|
|||||||
return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
|
return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client4) GetUserCategoryRoute(userID, teamID string) string {
|
||||||
|
return c.GetUserRoute(userID) + c.GetTeamRoute(teamID) + "/channels/categories"
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client4) GetUserAccessTokensRoute() string {
|
func (c *Client4) GetUserAccessTokensRoute() string {
|
||||||
return fmt.Sprintf(c.GetUsersRoute() + "/tokens")
|
return fmt.Sprintf(c.GetUsersRoute() + "/tokens")
|
||||||
}
|
}
|
||||||
@@ -5212,3 +5216,83 @@ func (c *Client4) GetGroupStats(groupID string) (*GroupStats, *Response) {
|
|||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
return GroupStatsFromJson(r.Body), BuildResponse(r)
|
return GroupStatsFromJson(r.Body), BuildResponse(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client4) GetSidebarCategoriesForTeamForUser(userID, teamID, etag string) (*OrderedSidebarCategories, *Response) {
|
||||||
|
route := c.GetUserCategoryRoute(userID, teamID)
|
||||||
|
r, appErr := c.DoApiGet(route, etag)
|
||||||
|
if appErr != nil {
|
||||||
|
return nil, BuildErrorResponse(r, appErr)
|
||||||
|
}
|
||||||
|
cat, err := OrderedSidebarCategoriesFromJson(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildErrorResponse(r, NewAppError("Client4.GetSidebarCategoriesForTeamForUser", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode))
|
||||||
|
}
|
||||||
|
return cat, BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client4) CreateSidebarCategoryForTeamForUser(userID, teamID string, category *SidebarCategoryWithChannels) (*SidebarCategoryWithChannels, *Response) {
|
||||||
|
payload, _ := json.Marshal(category)
|
||||||
|
route := c.GetUserCategoryRoute(userID, teamID)
|
||||||
|
r, appErr := c.doApiPostBytes(route, payload)
|
||||||
|
if appErr != nil {
|
||||||
|
return nil, BuildErrorResponse(r, appErr)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
cat, err := SidebarCategoryFromJson(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildErrorResponse(r, NewAppError("Client4.CreateSidebarCategoryForTeamForUser", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode))
|
||||||
|
}
|
||||||
|
return cat, BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client4) GetSidebarCategoryOrderForTeamForUser(userID, teamID, etag string) ([]string, *Response) {
|
||||||
|
route := c.GetUserCategoryRoute(userID, teamID) + "/order"
|
||||||
|
r, err := c.DoApiGet(route, etag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
return ArrayFromJson(r.Body), BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client4) UpdateSidebarCategoryOrderForTeamForUser(userID, teamID string, order []string) ([]string, *Response) {
|
||||||
|
payload, _ := json.Marshal(order)
|
||||||
|
route := c.GetUserCategoryRoute(userID, teamID) + "/order"
|
||||||
|
r, err := c.doApiPutBytes(route, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
return ArrayFromJson(r.Body), BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client4) GetSidebarCategoryForTeamForUser(userID, teamID, categoryID, etag string) (*SidebarCategoryWithChannels, *Response) {
|
||||||
|
route := c.GetUserCategoryRoute(userID, teamID) + "/" + categoryID
|
||||||
|
r, appErr := c.DoApiGet(route, etag)
|
||||||
|
if appErr != nil {
|
||||||
|
return nil, BuildErrorResponse(r, appErr)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
cat, err := SidebarCategoryFromJson(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError(c.GetUserRoute(userID), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cat, BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client4) UpdateSidebarCategoryForTeamForUser(userID, teamID, categoryID string, category *SidebarCategoryWithChannels) (*SidebarCategoryWithChannels, *Response) {
|
||||||
|
payload, _ := json.Marshal(category)
|
||||||
|
route := c.GetUserCategoryRoute(userID, teamID) + "/" + categoryID
|
||||||
|
r, appErr := c.doApiPutBytes(route, payload)
|
||||||
|
if appErr != nil {
|
||||||
|
return nil, BuildErrorResponse(r, appErr)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
cat, err := SidebarCategoryFromJson(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError(c.GetUserRoute(userID), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cat, BuildResponse(r)
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,4 +17,6 @@ const (
|
|||||||
MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS = "add_manage_guests_permissions"
|
MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS = "add_manage_guests_permissions"
|
||||||
MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS = "channel_moderations_permissions"
|
MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS = "channel_moderations_permissions"
|
||||||
MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION = "add_use_group_mentions_permission"
|
MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION = "add_use_group_mentions_permission"
|
||||||
|
|
||||||
|
MIGRATION_KEY_SIDEBAR_CATEGORIES_PHASE_2 = "migration_sidebar_categories_phase_2"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show"
|
PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show"
|
||||||
|
PREFERENCE_CATEGORY_GROUP_CHANNEL_SHOW = "group_channel_show"
|
||||||
PREFERENCE_CATEGORY_TUTORIAL_STEPS = "tutorial_step"
|
PREFERENCE_CATEGORY_TUTORIAL_STEPS = "tutorial_step"
|
||||||
PREFERENCE_CATEGORY_ADVANCED_SETTINGS = "advanced_settings"
|
PREFERENCE_CATEGORY_ADVANCED_SETTINGS = "advanced_settings"
|
||||||
PREFERENCE_CATEGORY_FLAGGED_POST = "flagged_post"
|
PREFERENCE_CATEGORY_FLAGGED_POST = "flagged_post"
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ const (
|
|||||||
WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_TEAM = "received_group_not_associated_to_team"
|
WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_TEAM = "received_group_not_associated_to_team"
|
||||||
WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_CHANNEL = "received_group_associated_to_channel"
|
WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_CHANNEL = "received_group_associated_to_channel"
|
||||||
WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_CHANNEL = "received_group_not_associated_to_channel"
|
WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_CHANNEL = "received_group_not_associated_to_channel"
|
||||||
|
WEBSOCKET_EVENT_SIDEBAR_CATEGORY_CREATED = "sidebar_category_created"
|
||||||
|
WEBSOCKET_EVENT_SIDEBAR_CATEGORY_UPDATED = "sidebar_category_updated"
|
||||||
|
WEBSOCKET_EVENT_SIDEBAR_CATEGORY_DELETED = "sidebar_category_deleted"
|
||||||
|
WEBSOCKET_EVENT_SIDEBAR_CATEGORY_ORDER_UPDATED = "sidebar_category_order_updated"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebSocketMessage interface {
|
type WebSocketMessage interface {
|
||||||
|
|||||||
@@ -576,6 +576,24 @@ func (s *OpenTracingLayerChannelStore) ClearCaches() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) ClearSidebarOnTeamLeave(userId string, teamId string) *model.AppError {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.ClearSidebarOnTeamLeave")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := s.ChannelStore.ClearSidebarOnTeamLeave(userId, teamId)
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, *model.AppError) {
|
func (s *OpenTracingLayerChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, *model.AppError) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CountPostsAfter")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CountPostsAfter")
|
||||||
@@ -612,6 +630,42 @@ func (s *OpenTracingLayerChannelStore) CreateDirectChannel(userId *model.User, o
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) CreateInitialSidebarCategories(user *model.User, teamId string) error {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CreateInitialSidebarCategories")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := s.ChannelStore.CreateInitialSidebarCategories(user, teamId)
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userId string, teamId string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CreateSidebarCategory")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.CreateSidebarCategory(userId, teamId, newCategory)
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) Delete(channelId string, time int64) error {
|
func (s *OpenTracingLayerChannelStore) Delete(channelId string, time int64) error {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Delete")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Delete")
|
||||||
@@ -630,6 +684,24 @@ func (s *OpenTracingLayerChannelStore) Delete(channelId string, time int64) erro
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) DeleteSidebarCategory(categoryId string) *model.AppError {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.DeleteSidebarCategory")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := s.ChannelStore.DeleteSidebarCategory(categoryId)
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) Get(id string, allowFromCache bool) (*model.Channel, error) {
|
func (s *OpenTracingLayerChannelStore) Get(id string, allowFromCache bool) (*model.Channel, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Get")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Get")
|
||||||
@@ -1327,6 +1399,60 @@ func (s *OpenTracingLayerChannelStore) GetPublicChannelsForTeam(teamId string, o
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) GetSidebarCategories(userId string, teamId string) (*model.OrderedSidebarCategories, *model.AppError) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategories")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.GetSidebarCategories(userId, teamId)
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategory")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.GetSidebarCategory(categoryId)
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) GetSidebarCategoryOrder(userId string, teamId string) ([]string, *model.AppError) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategoryOrder")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.GetSidebarCategoryOrder(userId, teamId)
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) GetTeamChannels(teamId string) (*model.ChannelList, *model.AppError) {
|
func (s *OpenTracingLayerChannelStore) GetTeamChannels(teamId string) (*model.ChannelList, *model.AppError) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetTeamChannels")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetTeamChannels")
|
||||||
@@ -1503,6 +1629,24 @@ func (s *OpenTracingLayerChannelStore) MigrateChannelMembers(fromChannelId strin
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) MigrateFavoritesToSidebarChannels(lastUserId string, runningOrder int64) (map[string]interface{}, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.MigrateFavoritesToSidebarChannels")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.MigrateFavoritesToSidebarChannels(lastUserId, runningOrder)
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) MigratePublicChannels() error {
|
func (s *OpenTracingLayerChannelStore) MigratePublicChannels() error {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.MigratePublicChannels")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.MigratePublicChannels")
|
||||||
@@ -1521,6 +1665,24 @@ func (s *OpenTracingLayerChannelStore) MigratePublicChannels() error {
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) MigrateSidebarCategories(fromTeamId string, fromUserId string) (map[string]interface{}, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.MigrateSidebarCategories")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.MigrateSidebarCategories(fromTeamId, fromUserId)
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) PermanentDelete(channelId string) error {
|
func (s *OpenTracingLayerChannelStore) PermanentDelete(channelId string) error {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.PermanentDelete")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.PermanentDelete")
|
||||||
@@ -1989,6 +2151,78 @@ func (s *OpenTracingLayerChannelStore) UpdateMultipleMembers(members []*model.Ch
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) UpdateSidebarCategories(userId string, teamId string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UpdateSidebarCategories")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.UpdateSidebarCategories(userId, teamId, categories)
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) UpdateSidebarCategoryOrder(userId string, teamId string, categoryOrder []string) *model.AppError {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UpdateSidebarCategoryOrder")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := s.ChannelStore.UpdateSidebarCategoryOrder(userId, teamId, categoryOrder)
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) UpdateSidebarChannelCategoryOnMove(channel *model.Channel, newTeamId string) *model.AppError {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UpdateSidebarChannelCategoryOnMove")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := s.ChannelStore.UpdateSidebarChannelCategoryOnMove(channel, newTeamId)
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) UpdateSidebarChannelsByPreferences(preferences *model.Preferences) *model.AppError {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UpdateSidebarChannelsByPreferences")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := s.ChannelStore.UpdateSidebarChannelsByPreferences(preferences)
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) UserBelongsToChannels(userId string, channelIds []string) (bool, *model.AppError) {
|
func (s *OpenTracingLayerChannelStore) UserBelongsToChannels(userId string, channelIds []string) (bool, *model.AppError) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UserBelongsToChannels")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UserBelongsToChannels")
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/v5/model"
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
"github.com/mattermost/mattermost-server/v5/services/cache2"
|
"github.com/mattermost/mattermost-server/v5/services/cache2"
|
||||||
"github.com/mattermost/mattermost-server/v5/store"
|
"github.com/mattermost/mattermost-server/v5/store"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/utils"
|
||||||
|
|
||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -390,6 +391,19 @@ func newSqlChannelStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface)
|
|||||||
tablePublicChannels.SetUniqueTogether("Name", "TeamId")
|
tablePublicChannels.SetUniqueTogether("Name", "TeamId")
|
||||||
tablePublicChannels.ColMap("Header").SetMaxSize(1024)
|
tablePublicChannels.ColMap("Header").SetMaxSize(1024)
|
||||||
tablePublicChannels.ColMap("Purpose").SetMaxSize(250)
|
tablePublicChannels.ColMap("Purpose").SetMaxSize(250)
|
||||||
|
|
||||||
|
tableSidebarCategories := db.AddTableWithName(model.SidebarCategory{}, "SidebarCategories").SetKeys(false, "Id")
|
||||||
|
tableSidebarCategories.ColMap("Id").SetMaxSize(26)
|
||||||
|
tableSidebarCategories.ColMap("UserId").SetMaxSize(26)
|
||||||
|
tableSidebarCategories.ColMap("TeamId").SetMaxSize(26)
|
||||||
|
tableSidebarCategories.ColMap("Sorting").SetMaxSize(64)
|
||||||
|
tableSidebarCategories.ColMap("Type").SetMaxSize(64)
|
||||||
|
tableSidebarCategories.ColMap("DisplayName").SetMaxSize(64)
|
||||||
|
|
||||||
|
tableSidebarChannels := db.AddTableWithName(model.SidebarChannel{}, "SidebarChannels").SetKeys(false, "ChannelId", "UserId", "CategoryId")
|
||||||
|
tableSidebarChannels.ColMap("ChannelId").SetMaxSize(26)
|
||||||
|
tableSidebarChannels.ColMap("UserId").SetMaxSize(26)
|
||||||
|
tableSidebarChannels.ColMap("CategoryId").SetMaxSize(26)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
@@ -423,6 +437,217 @@ func (s SqlChannelStore) createIndexesIfNotExists() {
|
|||||||
s.CreateIndexIfNotExists("idx_channels_scheme_id", "Channels", "SchemeId")
|
s.CreateIndexIfNotExists("idx_channels_scheme_id", "Channels", "SchemeId")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MigrateSidebarCategories creates 3 initial categories for all existing user/team pairs
|
||||||
|
// **IMPORTANT** This function should only be called from the migration task and shouldn't be used by itself
|
||||||
|
func (s SqlChannelStore) MigrateSidebarCategories(fromTeamId, fromUserId string) (map[string]interface{}, error) {
|
||||||
|
var userTeamMap []struct {
|
||||||
|
UserId string
|
||||||
|
TeamId string
|
||||||
|
Locale *string
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
|
||||||
|
if _, err := transaction.Select(&userTeamMap, "SELECT TeamId, UserId, Users.Locale FROM TeamMembers LEFT JOIN Users ON Users.Id=UserId WHERE (TeamId, UserId) > (:FromTeamId, :FromUserId) ORDER BY TeamId, UserId LIMIT 100", map[string]interface{}{"FromTeamId": fromTeamId, "FromUserId": fromUserId}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(userTeamMap) == 0 {
|
||||||
|
// No more team members in query result means that the migration has finished.
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, u := range userTeamMap {
|
||||||
|
locale := "en"
|
||||||
|
if u.Locale != nil {
|
||||||
|
locale = *u.Locale
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.createInitialSidebarCategoriesT(transaction, &model.User{Id: u.UserId, Locale: locale}, u.TeamId); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := transaction.Commit(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
data["TeamId"] = userTeamMap[len(userTeamMap)-1].TeamId
|
||||||
|
data["UserId"] = userTeamMap[len(userTeamMap)-1].UserId
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) CreateInitialSidebarCategories(user *model.User, teamId string) error {
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
|
||||||
|
if err := s.createInitialSidebarCategoriesT(transaction, user, teamId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := transaction.Commit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) createInitialSidebarCategoriesT(transaction *gorp.Transaction, user *model.User, teamId string) error {
|
||||||
|
T := utils.GetUserTranslations(user.Locale)
|
||||||
|
|
||||||
|
selectQuery, selectParams, _ := s.getQueryBuilder().
|
||||||
|
Select("Type").
|
||||||
|
From("SidebarCategories").
|
||||||
|
Where(sq.Eq{
|
||||||
|
"UserId": user.Id,
|
||||||
|
"TeamId": teamId,
|
||||||
|
"Type": []model.SidebarCategoryType{model.SidebarCategoryFavorites, model.SidebarCategoryChannels, model.SidebarCategoryDirectMessages},
|
||||||
|
}).ToSql()
|
||||||
|
|
||||||
|
var existingTypes []model.SidebarCategoryType
|
||||||
|
_, err := transaction.Select(&existingTypes, selectQuery, selectParams...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCategoryOfType := func(categoryType model.SidebarCategoryType) bool {
|
||||||
|
for _, existingType := range existingTypes {
|
||||||
|
if categoryType == existingType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasCategoryOfType(model.SidebarCategoryFavorites) {
|
||||||
|
if err := transaction.Insert(&model.SidebarCategory{
|
||||||
|
DisplayName: T("sidebar.category.favorites"),
|
||||||
|
Id: model.NewId(),
|
||||||
|
UserId: user.Id,
|
||||||
|
TeamId: teamId,
|
||||||
|
Sorting: model.SidebarCategorySortDefault,
|
||||||
|
SortOrder: model.DefaultSidebarSortOrderFavorites,
|
||||||
|
Type: model.SidebarCategoryFavorites,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasCategoryOfType(model.SidebarCategoryChannels) {
|
||||||
|
if err := transaction.Insert(&model.SidebarCategory{
|
||||||
|
DisplayName: T("sidebar.category.channels"),
|
||||||
|
Id: model.NewId(),
|
||||||
|
UserId: user.Id,
|
||||||
|
TeamId: teamId,
|
||||||
|
Sorting: model.SidebarCategorySortDefault,
|
||||||
|
SortOrder: model.DefaultSidebarSortOrderChannels,
|
||||||
|
Type: model.SidebarCategoryChannels,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasCategoryOfType(model.SidebarCategoryDirectMessages) {
|
||||||
|
if err := transaction.Insert(&model.SidebarCategory{
|
||||||
|
DisplayName: T("sidebar.category.dm"),
|
||||||
|
Id: model.NewId(),
|
||||||
|
UserId: user.Id,
|
||||||
|
TeamId: teamId,
|
||||||
|
Sorting: model.SidebarCategorySortRecent,
|
||||||
|
SortOrder: model.DefaultSidebarSortOrderDMs,
|
||||||
|
Type: model.SidebarCategoryDirectMessages,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type userMembership struct {
|
||||||
|
UserId string
|
||||||
|
ChannelId string
|
||||||
|
CategoryId string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) migrateMembershipToSidebar(transaction *gorp.Transaction, runningOrder *int64, sql string, args ...interface{}) ([]userMembership, error) {
|
||||||
|
var memberships []userMembership
|
||||||
|
if _, err := transaction.Select(&memberships, sql, args...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, favorite := range memberships {
|
||||||
|
sql, args, _ := s.getQueryBuilder().
|
||||||
|
Insert("SidebarChannels").
|
||||||
|
Columns("ChannelId", "UserId", "CategoryId", "SortOrder").
|
||||||
|
Values(favorite.ChannelId, favorite.UserId, favorite.CategoryId, *runningOrder).ToSql()
|
||||||
|
|
||||||
|
if _, err := transaction.Exec(sql, args...); err != nil && !IsUniqueConstraintError(err, []string{"UserId", "PRIMARY"}) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
*runningOrder = *runningOrder + model.MinimalSidebarSortDistance
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := transaction.Commit(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return memberships, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MigrateFavoritesToSidebarChannels populates the SidebarChannels table by analyzing existing user preferences for favorites
|
||||||
|
// **IMPORTANT** This function should only be called from the migration task and shouldn't be used by itself
|
||||||
|
func (s SqlChannelStore) MigrateFavoritesToSidebarChannels(lastUserId string, runningOrder int64) (map[string]interface{}, error) {
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
|
||||||
|
sb := s.
|
||||||
|
getQueryBuilder().
|
||||||
|
Select("Preferences.UserId", "Preferences.Name AS ChannelId", "SidebarCategories.Id AS CategoryId").
|
||||||
|
From("Preferences").
|
||||||
|
Where(sq.And{
|
||||||
|
sq.Eq{"Preferences.Category": model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL},
|
||||||
|
sq.NotEq{"Preferences.Value": "false"},
|
||||||
|
sq.NotEq{"SidebarCategories.Id": nil},
|
||||||
|
sq.Gt{"Preferences.UserId": lastUserId},
|
||||||
|
}).
|
||||||
|
LeftJoin("Channels ON (Channels.Id=Preferences.Name)").
|
||||||
|
LeftJoin("SidebarCategories ON (SidebarCategories.UserId=Preferences.UserId AND SidebarCategories.Type='"+string(model.SidebarCategoryFavorites)+"' AND (SidebarCategories.TeamId=Channels.TeamId OR Channels.TeamId=''))").
|
||||||
|
OrderBy("Preferences.UserId", "Channels.Name DESC").
|
||||||
|
Limit(100)
|
||||||
|
|
||||||
|
sql, args, err := sb.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userFavorites, err := s.migrateMembershipToSidebar(transaction, &runningOrder, sql, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(userFavorites) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
data["UserId"] = userFavorites[len(userFavorites)-1].UserId
|
||||||
|
data["SortOrder"] = runningOrder
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
// MigratePublicChannels initializes the PublicChannels table with data created before this version
|
// MigratePublicChannels initializes the PublicChannels table with data created before this version
|
||||||
// of the Mattermost server kept it up-to-date.
|
// of the Mattermost server kept it up-to-date.
|
||||||
func (s SqlChannelStore) MigratePublicChannels() error {
|
func (s SqlChannelStore) MigratePublicChannels() error {
|
||||||
@@ -1938,6 +2163,21 @@ func (s SqlChannelStore) RemoveMembers(channelId string, userIds []string) *mode
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError)
|
return model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cleanup sidebarchannels table if the user is no longer a member of that channel
|
||||||
|
sql, args, err = s.getQueryBuilder().
|
||||||
|
Delete("SidebarChannels").
|
||||||
|
Where(sq.And{
|
||||||
|
sq.Eq{"ChannelId": channelId},
|
||||||
|
sq.Eq{"UserId": userIds},
|
||||||
|
}).ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
_, err = s.GetMaster().Exec(sql, args...)
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3206,3 +3446,569 @@ func (s SqlChannelStore) GroupSyncedChannelCount() (int64, *model.AppError) {
|
|||||||
|
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sidebarCategoryForJoin struct {
|
||||||
|
model.SidebarCategory
|
||||||
|
ChannelId *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SqlChannelStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
|
||||||
|
categoriesWithOrder, appErr := s.getSidebarCategoriesT(transaction, userId, teamId)
|
||||||
|
if appErr != nil {
|
||||||
|
return nil, appErr
|
||||||
|
}
|
||||||
|
if len(categoriesWithOrder.Categories) < 1 {
|
||||||
|
return nil, model.NewAppError("SqlChannelStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
newOrder := categoriesWithOrder.Order
|
||||||
|
newCategoryId := model.NewId()
|
||||||
|
newCategorySortOrder := 0
|
||||||
|
/*
|
||||||
|
When a new category is created, it should be placed as follows:
|
||||||
|
1. If the Favorites category is first, the new category should be placed after it
|
||||||
|
2. Otherwise, the new category should be placed first.
|
||||||
|
*/
|
||||||
|
if categoriesWithOrder.Categories[0].Type == model.SidebarCategoryFavorites {
|
||||||
|
newOrder = append([]string{newOrder[0], newCategoryId}, newOrder[1:]...)
|
||||||
|
newCategorySortOrder = model.MinimalSidebarSortDistance
|
||||||
|
} else {
|
||||||
|
newOrder = append([]string{newCategoryId}, newOrder...)
|
||||||
|
}
|
||||||
|
|
||||||
|
category := &model.SidebarCategory{
|
||||||
|
DisplayName: newCategory.DisplayName,
|
||||||
|
Id: newCategoryId,
|
||||||
|
UserId: userId,
|
||||||
|
TeamId: teamId,
|
||||||
|
Sorting: model.SidebarCategorySortDefault,
|
||||||
|
SortOrder: int64(model.MinimalSidebarSortDistance * len(newOrder)), // first we place it at the end of the list
|
||||||
|
Type: model.SidebarCategoryCustom,
|
||||||
|
}
|
||||||
|
if err = transaction.Insert(category); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
var channels []interface{}
|
||||||
|
runningOrder := 0
|
||||||
|
for _, channelID := range newCategory.Channels {
|
||||||
|
channels = append(channels, &model.SidebarChannel{
|
||||||
|
ChannelId: channelID,
|
||||||
|
CategoryId: newCategoryId,
|
||||||
|
SortOrder: int64(runningOrder),
|
||||||
|
UserId: userId,
|
||||||
|
})
|
||||||
|
runningOrder += model.MinimalSidebarSortDistance
|
||||||
|
}
|
||||||
|
if err = transaction.Insert(channels...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we re-order the categories according to the new order
|
||||||
|
if appErr := s.updateSidebarCategoryOrderT(transaction, userId, teamId, newOrder); appErr != nil {
|
||||||
|
return nil, appErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.Commit(); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlChannelStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch category to return proper sort order
|
||||||
|
category.SortOrder = int64(newCategorySortOrder)
|
||||||
|
result := &model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: *category,
|
||||||
|
Channels: newCategory.Channels,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) completePopulatingCategoryChannels(category *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
if category.Type == model.SidebarCategoryCustom || category.Type == model.SidebarCategoryFavorites {
|
||||||
|
return category, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var channelTypeFilter sq.Sqlizer
|
||||||
|
if category.Type == model.SidebarCategoryDirectMessages {
|
||||||
|
// any DM/GM channels that aren't in any category should be returned as part of the Direct Messages category
|
||||||
|
channelTypeFilter = sq.Eq{"Channels.Type": []string{model.CHANNEL_DIRECT, model.CHANNEL_GROUP}}
|
||||||
|
} else if category.Type == model.SidebarCategoryChannels {
|
||||||
|
// any public/private channels that are on the current team and aren't in any category should be returned as part of the Channels category
|
||||||
|
channelTypeFilter = sq.And{
|
||||||
|
sq.Eq{"Channels.Type": []string{model.CHANNEL_OPEN, model.CHANNEL_PRIVATE}},
|
||||||
|
sq.Eq{"Channels.TeamId": category.TeamId},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A subquery that is true if the channel does not have a SidebarChannel entry for the current user on the current team
|
||||||
|
doesNotHaveSidebarChannel := sq.Select("1").
|
||||||
|
Prefix("NOT EXISTS (").
|
||||||
|
From("SidebarChannels").
|
||||||
|
Join("SidebarCategories on SidebarChannels.CategoryId=SidebarCategories.Id").
|
||||||
|
Where(sq.And{
|
||||||
|
sq.Expr("SidebarChannels.ChannelId = ChannelMembers.ChannelId"),
|
||||||
|
sq.Eq{"SidebarCategories.UserId": category.UserId},
|
||||||
|
sq.Eq{"SidebarCategories.TeamId": category.TeamId},
|
||||||
|
}).
|
||||||
|
Suffix(")")
|
||||||
|
|
||||||
|
var channels []string
|
||||||
|
sql, args, _ := s.getQueryBuilder().
|
||||||
|
Select("Id").
|
||||||
|
From("ChannelMembers").
|
||||||
|
LeftJoin("Channels ON Channels.Id=ChannelMembers.ChannelId").
|
||||||
|
Where(sq.And{
|
||||||
|
sq.Eq{"ChannelMembers.UserId": category.UserId},
|
||||||
|
channelTypeFilter,
|
||||||
|
sq.Eq{"Channels.DeleteAt": 0},
|
||||||
|
doesNotHaveSidebarChannel,
|
||||||
|
}).
|
||||||
|
OrderBy("DisplayName ASC").ToSql()
|
||||||
|
|
||||||
|
if _, err := s.GetReplica().Select(&channels, sql, args...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.completePopulatingCategoryChannels", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusNotFound)
|
||||||
|
}
|
||||||
|
category.Channels = append(channels, category.Channels...)
|
||||||
|
return category, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
var categories []*sidebarCategoryForJoin
|
||||||
|
sql, args, _ := s.getQueryBuilder().
|
||||||
|
Select("SidebarCategories.*", "SidebarChannels.ChannelId").
|
||||||
|
From("SidebarCategories").
|
||||||
|
LeftJoin("SidebarChannels ON SidebarChannels.CategoryId=SidebarCategories.Id").
|
||||||
|
Where(sq.Eq{"SidebarCategories.Id": categoryId}).
|
||||||
|
OrderBy("SidebarChannels.SortOrder ASC").ToSql()
|
||||||
|
if _, err := s.GetReplica().Select(&categories, sql, args...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.GetSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusNotFound)
|
||||||
|
}
|
||||||
|
result := &model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: categories[0].SidebarCategory,
|
||||||
|
Channels: make([]string, 0),
|
||||||
|
}
|
||||||
|
for _, category := range categories {
|
||||||
|
if category.ChannelId != nil {
|
||||||
|
result.Channels = append(result.Channels, *category.ChannelId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.completePopulatingCategoryChannels(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) getSidebarCategoriesT(transaction *gorp.Transaction, userId, teamId string) (*model.OrderedSidebarCategories, *model.AppError) {
|
||||||
|
oc := model.OrderedSidebarCategories{
|
||||||
|
Categories: make(model.SidebarCategoriesWithChannels, 0),
|
||||||
|
Order: make([]string, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
var categories []*sidebarCategoryForJoin
|
||||||
|
sql, args, _ := s.getQueryBuilder().
|
||||||
|
Select("SidebarCategories.*", "SidebarChannels.ChannelId").
|
||||||
|
From("SidebarCategories").
|
||||||
|
LeftJoin("SidebarChannels ON SidebarChannels.CategoryId=Id").
|
||||||
|
Where(sq.And{
|
||||||
|
sq.Eq{"SidebarCategories.UserId": userId},
|
||||||
|
sq.Eq{"SidebarCategories.TeamId": teamId},
|
||||||
|
}).
|
||||||
|
OrderBy("SidebarCategories.SortOrder ASC, SidebarChannels.SortOrder ASC").ToSql()
|
||||||
|
|
||||||
|
if _, err := s.GetReplica().Select(&categories, sql, args...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.GetSidebarCategories", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusNotFound)
|
||||||
|
}
|
||||||
|
for _, category := range categories {
|
||||||
|
var prevCategory *model.SidebarCategoryWithChannels
|
||||||
|
for _, existing := range oc.Categories {
|
||||||
|
if existing.Id == category.Id {
|
||||||
|
prevCategory = existing
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if prevCategory == nil {
|
||||||
|
prevCategory = &model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: category.SidebarCategory,
|
||||||
|
Channels: make([]string, 0),
|
||||||
|
}
|
||||||
|
oc.Categories = append(oc.Categories, prevCategory)
|
||||||
|
oc.Order = append(oc.Order, category.Id)
|
||||||
|
}
|
||||||
|
if category.ChannelId != nil {
|
||||||
|
prevCategory.Channels = append(prevCategory.Channels, *category.ChannelId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, category := range oc.Categories {
|
||||||
|
if _, err := s.completePopulatingCategoryChannels(category); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &oc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) GetSidebarCategories(userId, teamId string) (*model.OrderedSidebarCategories, *model.AppError) {
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SqlChannelStore.GetSidebarCategories", "store.sql_channel.sidebar_categories.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
|
||||||
|
oc, appErr := s.getSidebarCategoriesT(transaction, userId, teamId)
|
||||||
|
if appErr != nil {
|
||||||
|
return nil, appErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.Commit(); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlChannelStore.GetSidebarCategories", "store.sql_channel.sidebar_categories.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return oc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) GetSidebarCategoryOrder(userId, teamId string) ([]string, *model.AppError) {
|
||||||
|
var ids []string
|
||||||
|
|
||||||
|
sql, args, _ := s.getQueryBuilder().
|
||||||
|
Select("Id").
|
||||||
|
From("SidebarCategories").
|
||||||
|
Where(sq.And{
|
||||||
|
sq.Eq{"UserId": userId},
|
||||||
|
sq.Eq{"TeamId": teamId},
|
||||||
|
}).
|
||||||
|
OrderBy("SidebarCategories.SortOrder ASC").ToSql()
|
||||||
|
|
||||||
|
if _, err := s.GetReplica().Select(&ids, sql, args...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.GetSidebarCategoryOrder", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusNotFound)
|
||||||
|
}
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) updateSidebarCategoryOrderT(transaction *gorp.Transaction, userId, teamId string, categoryOrder []string) *model.AppError {
|
||||||
|
var newOrder []interface{}
|
||||||
|
runningOrder := 0
|
||||||
|
for _, categoryId := range categoryOrder {
|
||||||
|
newOrder = append(newOrder, &model.SidebarCategory{
|
||||||
|
Id: categoryId,
|
||||||
|
SortOrder: int64(runningOrder),
|
||||||
|
})
|
||||||
|
runningOrder += model.MinimalSidebarSortDistance
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's a bug in gorp where UpdateColumns messes up the stored query for any other attempt to use .Update or
|
||||||
|
// .UpdateColumns on this table, so it's okay to use here as long as we don't use those methods for SidebarCategories
|
||||||
|
// anywhere else.
|
||||||
|
if _, err := transaction.UpdateColumns(func(col *gorp.ColumnMap) bool {
|
||||||
|
return col.ColumnName == "SortOrder"
|
||||||
|
}, newOrder...); err != nil {
|
||||||
|
return model.NewAppError("SqlPostStore.UpdateSidebarCategoryOrder", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) UpdateSidebarCategoryOrder(userId, teamId string, categoryOrder []string) *model.AppError {
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.UpdateSidebarCategoryOrder", "store.sql_channel.sidebar_categories.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
|
||||||
|
// Ensure no invalid categories are included and that no categories are left out
|
||||||
|
existingOrder, appErr := s.GetSidebarCategoryOrder(userId, teamId)
|
||||||
|
if appErr != nil {
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
if len(existingOrder) != len(categoryOrder) {
|
||||||
|
return model.NewAppError("SqlPostStore.UpdateSidebarCategoryOrder", "store.sql_channel.sidebar_categories.app_error", nil, "Cannot update category order, passed list of categories different size than in DB", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
for _, originalCategoryId := range existingOrder {
|
||||||
|
found := false
|
||||||
|
for _, newCategoryId := range categoryOrder {
|
||||||
|
if newCategoryId == originalCategoryId {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return model.NewAppError("SqlPostStore.UpdateSidebarCategoryOrder", "store.sql_channel.sidebar_categories.app_error", nil, "Cannot update category order, passed list of categories contains unrecognized category IDs", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if appErr := s.updateSidebarCategoryOrderT(transaction, userId, teamId, categoryOrder); appErr != nil {
|
||||||
|
return appErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.Commit(); err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.UpdateSidebarCategoryOrder", "store.sql_channel.sidebar_categories.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SqlChannelStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
|
||||||
|
updatedCategories := []*model.SidebarCategoryWithChannels{}
|
||||||
|
for _, category := range categories {
|
||||||
|
originalCategory, appErr := s.GetSidebarCategory(category.Id)
|
||||||
|
if appErr != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, appErr.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy category to avoid modifying an argument
|
||||||
|
updatedCategory := &model.SidebarCategoryWithChannels{
|
||||||
|
SidebarCategory: category.SidebarCategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent any changes to read-only fields of SidebarCategories
|
||||||
|
updatedCategory.UserId = originalCategory.UserId
|
||||||
|
updatedCategory.TeamId = originalCategory.TeamId
|
||||||
|
updatedCategory.SortOrder = originalCategory.SortOrder
|
||||||
|
updatedCategory.Type = originalCategory.Type
|
||||||
|
|
||||||
|
if updatedCategory.Type != model.SidebarCategoryCustom {
|
||||||
|
updatedCategory.DisplayName = originalCategory.DisplayName
|
||||||
|
}
|
||||||
|
|
||||||
|
if category.Type != model.SidebarCategoryDirectMessages {
|
||||||
|
updatedCategory.Channels = make([]string, len(category.Channels))
|
||||||
|
copy(updatedCategory.Channels, category.Channels)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateQuery, updateParams, _ := s.getQueryBuilder().
|
||||||
|
Update("SidebarCategories").
|
||||||
|
Set("DisplayName", updatedCategory.DisplayName).
|
||||||
|
Set("Sorting", updatedCategory.Sorting).
|
||||||
|
Where(sq.Eq{"Id": updatedCategory.Id}).ToSql()
|
||||||
|
|
||||||
|
if _, err = transaction.Exec(updateQuery, updateParams...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are updating DM category, it's order can't channel order cannot be changed.
|
||||||
|
if category.Type != model.SidebarCategoryDirectMessages {
|
||||||
|
// Remove any SidebarChannels entries that were either:
|
||||||
|
// - previously in this category (and any ones that are still in the category will be recreated below)
|
||||||
|
// - in another category and are being added to this category
|
||||||
|
sql, args, _ := s.getQueryBuilder().
|
||||||
|
Delete("SidebarChannels").
|
||||||
|
Where(
|
||||||
|
sq.And{
|
||||||
|
sq.Or{
|
||||||
|
sq.Eq{"ChannelId": originalCategory.Channels},
|
||||||
|
sq.Eq{"ChannelId": updatedCategory.Channels},
|
||||||
|
},
|
||||||
|
sq.Eq{"CategoryId": category.Id},
|
||||||
|
},
|
||||||
|
).ToSql()
|
||||||
|
|
||||||
|
if _, err = transaction.Exec(sql, args...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
var channels []interface{}
|
||||||
|
runningOrder := 0
|
||||||
|
for _, channelID := range category.Channels {
|
||||||
|
channels = append(channels, &model.SidebarChannel{
|
||||||
|
ChannelId: channelID,
|
||||||
|
CategoryId: category.Id,
|
||||||
|
SortOrder: int64(runningOrder),
|
||||||
|
UserId: userId,
|
||||||
|
})
|
||||||
|
runningOrder += model.MinimalSidebarSortDistance
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.Insert(channels...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the favorites preferences based on channels moving into or out of the Favorites category for compatibility
|
||||||
|
if category.Type == model.SidebarCategoryFavorites {
|
||||||
|
// Remove any old favorites
|
||||||
|
sql, args, _ := s.getQueryBuilder().Delete("Preferences").Where(
|
||||||
|
sq.Eq{
|
||||||
|
"Name": originalCategory.Channels,
|
||||||
|
"Category": model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL,
|
||||||
|
},
|
||||||
|
).ToSql()
|
||||||
|
|
||||||
|
if _, err = transaction.Exec(sql, args...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// And then add the new ones
|
||||||
|
var preferences []interface{}
|
||||||
|
|
||||||
|
for _, channelID := range category.Channels {
|
||||||
|
preferences = append(preferences, &model.Preference{
|
||||||
|
Name: channelID,
|
||||||
|
UserId: userId,
|
||||||
|
Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL,
|
||||||
|
Value: "true",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.Insert(preferences...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Remove any old favorites that might have been in this category
|
||||||
|
sql, args, _ := s.getQueryBuilder().Delete("Preferences").Where(
|
||||||
|
sq.Eq{
|
||||||
|
"Name": category.Channels,
|
||||||
|
"Category": model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL,
|
||||||
|
},
|
||||||
|
).ToSql()
|
||||||
|
|
||||||
|
if _, err = transaction.Exec(sql, args...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedCategories = append(updatedCategories, updatedCategory)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = transaction.Commit(); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlChannelStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure Channels are populated for Channels/Direct Messages category if they change
|
||||||
|
for i, updatedCategory := range updatedCategories {
|
||||||
|
populated, err := s.completePopulatingCategoryChannels(updatedCategory)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.UpdateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedCategories[i] = populated
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedCategories, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSidebarChannelByPreference is called when the Preference table is being updated to keep SidebarCategories in sync
|
||||||
|
// At the moment, it's only handling Favorites and NOT DMs/GMs (those will be handled client side)
|
||||||
|
func (s SqlChannelStore) UpdateSidebarChannelsByPreferences(preferences *model.Preferences) *model.AppError {
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.UpdateSidebarChannelsByPreferences", "store.sql_channel.sidebar_categories.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
for _, preference := range *preferences {
|
||||||
|
if preference.Category != model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"UserId": preference.UserId,
|
||||||
|
"ChannelId": preference.Name,
|
||||||
|
"CategoryType": model.SidebarCategoryFavorites,
|
||||||
|
}
|
||||||
|
// if new preference is false - remove the channel from the appropriate sidebar category
|
||||||
|
if preference.Value == "false" {
|
||||||
|
var deleteQuery string
|
||||||
|
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
||||||
|
deleteQuery = "DELETE SidebarChannels FROM SidebarChannels LEFT JOIN SidebarCategories ON SidebarCategories.Id = SidebarChannels.CategoryId WHERE SidebarCategories.Type=:CategoryType AND SidebarCategories.UserId=:UserId AND SidebarChannels.UserId=:UserId AND ChannelId=:ChannelId"
|
||||||
|
} else {
|
||||||
|
deleteQuery = "DELETE FROM SidebarChannels USING SidebarChannels AS chan LEFT OUTER JOIN SidebarCategories AS cat ON cat.Id = chan.CategoryId WHERE cat.Type=:CategoryType AND cat.UserId = :UserId AND chan.UserId = :UserId AND cat.TeamId = :TeamId AND chan.ChannelId=:ChannelId"
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := transaction.Exec(deleteQuery, params); err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.UpdateSidebarChannelByPreference", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// otherwise - insert new channel into the apropriate category. ignore duplicate error
|
||||||
|
if _, err := transaction.Exec("INSERT INTO SidebarChannels (ChannelId, UserId, CategoryId, SortOrder) SELECT Id AS CategoryId, :UserId AS UserId, :ChannelId AS ChannelId, MAX(SidebarChannels.SortOrder)+10 FROM SidebarCategories INNER JOIN SidebarChannels ON SidebarChannels.CategoryId = SidebarCategories.Id WHERE SidebarCategories.Type=:CategoryType AND SidebarCategories.UserId=:UserId GROUP BY SidebarChannels.CategoryId, SidebarCategories.Id", params); err != nil && !IsUniqueConstraintError(err, []string{"UserId"}) {
|
||||||
|
return model.NewAppError("SqlChannelStore.UpdateSidebarChannelByPreference", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := transaction.Commit(); err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.UpdateSidebarChannelByPreference", "store.sql_channel.sidebar_categories.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) UpdateSidebarChannelCategoryOnMove(channel *model.Channel, newTeamId string) *model.AppError {
|
||||||
|
// if channel is being moved, remove it from the categories, since it's possible that there's no matching category in the new team
|
||||||
|
if _, err := s.GetMaster().Exec("DELETE FROM SidebarChannels WHERE ChannelId=:ChannelId", map[string]interface{}{"ChannelId": channel.Id}); err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.UpdateSidebarChannelCategoryOnMove", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) ClearSidebarOnTeamLeave(userId, teamId string) *model.AppError {
|
||||||
|
// if user leaves the team, clean his team related entries in sidebar channels and categories
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"UserId": userId,
|
||||||
|
"TeamId": teamId,
|
||||||
|
}
|
||||||
|
|
||||||
|
var deleteQuery string
|
||||||
|
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
||||||
|
deleteQuery = "DELETE SidebarChannels FROM SidebarChannels LEFT JOIN SidebarCategories ON SidebarCategories.Id = SidebarChannels.CategoryId WHERE SidebarCategories.TeamId=:TeamId AND SidebarCategories.UserId=:UserId"
|
||||||
|
} else {
|
||||||
|
deleteQuery = "DELETE FROM SidebarChannels USING SidebarChannels AS chan LEFT OUTER JOIN SidebarCategories AS cat ON cat.Id = chan.CategoryId WHERE cat.UserId = :UserId AND cat.TeamId = :TeamId"
|
||||||
|
}
|
||||||
|
if _, err := s.GetMaster().Exec(deleteQuery, params); err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.ClearSidebarOnTeamLeave", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
if _, err := s.GetMaster().Exec("DELETE FROM SidebarCategories WHERE SidebarCategories.TeamId = :TeamId AND SidebarCategories.UserId = :UserId", params); err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.ClearSidebarOnTeamLeave", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSidebarCategory removes a custom category and moves any channels into it into the Channels and Direct Messages
|
||||||
|
// categories respectively. Assumes that the provided user ID and team ID match the given category ID.
|
||||||
|
func (s SqlChannelStore) DeleteSidebarCategory(categoryId string) *model.AppError {
|
||||||
|
transaction, err := s.GetMaster().Begin()
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.DeleteSidebarCategory", "store.sql_channel.sidebar_categories.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
defer finalizeTransaction(transaction)
|
||||||
|
|
||||||
|
// Ensure that we're deleting a custom category
|
||||||
|
var category *model.SidebarCategory
|
||||||
|
if err = transaction.SelectOne(&category, "SELECT * FROM SidebarCategories WHERE Id = :Id", map[string]interface{}{"Id": categoryId}); err != nil {
|
||||||
|
return model.NewAppError("SqlPostStore.DeleteSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if category.Type != model.SidebarCategoryCustom {
|
||||||
|
return model.NewAppError("SqlPostStore.DeleteSidebarCategory", "store.sql_channel.sidebar_categories.delete_invalid.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the channels in the category
|
||||||
|
sql, args, _ := s.getQueryBuilder().
|
||||||
|
Delete("SidebarChannels").
|
||||||
|
Where(sq.Eq{"CategoryId": categoryId}).ToSql()
|
||||||
|
|
||||||
|
if _, err := transaction.Exec(sql, args...); err != nil {
|
||||||
|
return model.NewAppError("SqlPostStore.DeleteSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the category itself
|
||||||
|
sql, args, _ = s.getQueryBuilder().
|
||||||
|
Delete("SidebarCategories").
|
||||||
|
Where(sq.Eq{"Id": categoryId}).ToSql()
|
||||||
|
|
||||||
|
if _, err := transaction.Exec(sql, args...); err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.DeleteSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := transaction.Commit(); err != nil {
|
||||||
|
return model.NewAppError("SqlChannelStore.DeleteSidebarCategory", "store.sql_channel.sidebar_categories.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ type SqlStore interface {
|
|||||||
CreateUniqueIndexIfNotExists(indexName string, tableName string, columnName string) bool
|
CreateUniqueIndexIfNotExists(indexName string, tableName string, columnName string) bool
|
||||||
CreateIndexIfNotExists(indexName string, tableName string, columnName string) bool
|
CreateIndexIfNotExists(indexName string, tableName string, columnName string) bool
|
||||||
CreateCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool
|
CreateCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool
|
||||||
|
CreateUniqueCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool
|
||||||
CreateFullTextIndexIfNotExists(indexName string, tableName string, columnName string) bool
|
CreateFullTextIndexIfNotExists(indexName string, tableName string, columnName string) bool
|
||||||
RemoveIndexIfExists(indexName string, tableName string) bool
|
RemoveIndexIfExists(indexName string, tableName string) bool
|
||||||
GetAllConns() []*gorp.DbMap
|
GetAllConns() []*gorp.DbMap
|
||||||
|
|||||||
@@ -855,6 +855,10 @@ func (ss *SqlSupplier) CreateCompositeIndexIfNotExists(indexName string, tableNa
|
|||||||
return ss.createIndexIfNotExists(indexName, tableName, columnNames, INDEX_TYPE_DEFAULT, false)
|
return ss.createIndexIfNotExists(indexName, tableName, columnNames, INDEX_TYPE_DEFAULT, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ss *SqlSupplier) CreateUniqueCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool {
|
||||||
|
return ss.createIndexIfNotExists(indexName, tableName, columnNames, INDEX_TYPE_DEFAULT, true)
|
||||||
|
}
|
||||||
|
|
||||||
func (ss *SqlSupplier) CreateFullTextIndexIfNotExists(indexName string, tableName string, columnName string) bool {
|
func (ss *SqlSupplier) CreateFullTextIndexIfNotExists(indexName string, tableName string, columnName string) bool {
|
||||||
return ss.createIndexIfNotExists(indexName, tableName, []string{columnName}, INDEX_TYPE_FULL_TEXT, false)
|
return ss.createIndexIfNotExists(indexName, tableName, []string{columnName}, INDEX_TYPE_FULL_TEXT, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ type ChannelStore interface {
|
|||||||
CreateDirectChannel(userId *model.User, otherUserId *model.User) (*model.Channel, error)
|
CreateDirectChannel(userId *model.User, otherUserId *model.User) (*model.Channel, error)
|
||||||
SaveDirectChannel(channel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) (*model.Channel, error)
|
SaveDirectChannel(channel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) (*model.Channel, error)
|
||||||
Update(channel *model.Channel) (*model.Channel, error)
|
Update(channel *model.Channel) (*model.Channel, error)
|
||||||
|
UpdateSidebarChannelCategoryOnMove(channel *model.Channel, newTeamId string) *model.AppError
|
||||||
|
ClearSidebarOnTeamLeave(userId, teamId string) *model.AppError
|
||||||
Get(id string, allowFromCache bool) (*model.Channel, error)
|
Get(id string, allowFromCache bool) (*model.Channel, error)
|
||||||
InvalidateChannel(id string)
|
InvalidateChannel(id string)
|
||||||
InvalidateChannelByName(teamId, name string)
|
InvalidateChannelByName(teamId, name string)
|
||||||
@@ -214,6 +216,17 @@ type ChannelStore interface {
|
|||||||
ResetAllChannelSchemes() *model.AppError
|
ResetAllChannelSchemes() *model.AppError
|
||||||
ClearAllCustomRoleAssignments() *model.AppError
|
ClearAllCustomRoleAssignments() *model.AppError
|
||||||
MigratePublicChannels() error
|
MigratePublicChannels() error
|
||||||
|
MigrateSidebarCategories(fromTeamId, fromUserId string) (map[string]interface{}, error)
|
||||||
|
CreateInitialSidebarCategories(user *model.User, teamId string) error
|
||||||
|
MigrateFavoritesToSidebarChannels(lastUserId string, runningOrder int64) (map[string]interface{}, error)
|
||||||
|
GetSidebarCategories(userId, teamId string) (*model.OrderedSidebarCategories, *model.AppError)
|
||||||
|
GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError)
|
||||||
|
GetSidebarCategoryOrder(userId, teamId string) ([]string, *model.AppError)
|
||||||
|
CreateSidebarCategory(userId, teamId string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError)
|
||||||
|
UpdateSidebarCategoryOrder(userId, teamId string, categoryOrder []string) *model.AppError
|
||||||
|
UpdateSidebarCategories(userId, teamId string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError)
|
||||||
|
UpdateSidebarChannelsByPreferences(preferences *model.Preferences) *model.AppError
|
||||||
|
DeleteSidebarCategory(categoryId string) *model.AppError
|
||||||
GetAllChannelsForExportAfter(limit int, afterId string) ([]*model.ChannelForExport, *model.AppError)
|
GetAllChannelsForExportAfter(limit int, afterId string) ([]*model.ChannelForExport, *model.AppError)
|
||||||
GetAllDirectChannelsForExportAfter(limit int, afterId string) ([]*model.DirectChannelForExport, *model.AppError)
|
GetAllDirectChannelsForExportAfter(limit int, afterId string) ([]*model.DirectChannelForExport, *model.AppError)
|
||||||
GetChannelMembersForExport(userId string, teamId string) ([]*model.ChannelMemberForExport, *model.AppError)
|
GetChannelMembersForExport(userId string, teamId string) ([]*model.ChannelMemberForExport, *model.AppError)
|
||||||
|
|||||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -132,6 +132,22 @@ func (_m *ChannelStore) ClearCaches() {
|
|||||||
_m.Called()
|
_m.Called()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearSidebarOnTeamLeave provides a mock function with given fields: userId, teamId
|
||||||
|
func (_m *ChannelStore) ClearSidebarOnTeamLeave(userId string, teamId string) *model.AppError {
|
||||||
|
ret := _m.Called(userId, teamId)
|
||||||
|
|
||||||
|
var r0 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string) *model.AppError); ok {
|
||||||
|
r0 = rf(userId, teamId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
// CountPostsAfter provides a mock function with given fields: channelId, timestamp, userId
|
// CountPostsAfter provides a mock function with given fields: channelId, timestamp, userId
|
||||||
func (_m *ChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, *model.AppError) {
|
func (_m *ChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, *model.AppError) {
|
||||||
ret := _m.Called(channelId, timestamp, userId)
|
ret := _m.Called(channelId, timestamp, userId)
|
||||||
@@ -178,6 +194,45 @@ func (_m *ChannelStore) CreateDirectChannel(userId *model.User, otherUserId *mod
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateInitialSidebarCategories provides a mock function with given fields: user, teamId
|
||||||
|
func (_m *ChannelStore) CreateInitialSidebarCategories(user *model.User, teamId string) error {
|
||||||
|
ret := _m.Called(user, teamId)
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.User, string) error); ok {
|
||||||
|
r0 = rf(user, teamId)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSidebarCategory provides a mock function with given fields: userId, teamId, newCategory
|
||||||
|
func (_m *ChannelStore) CreateSidebarCategory(userId string, teamId string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
ret := _m.Called(userId, teamId, newCategory)
|
||||||
|
|
||||||
|
var r0 *model.SidebarCategoryWithChannels
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels) *model.SidebarCategoryWithChannels); ok {
|
||||||
|
r0 = rf(userId, teamId, newCategory)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.SidebarCategoryWithChannels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(1).(func(string, string, *model.SidebarCategoryWithChannels) *model.AppError); ok {
|
||||||
|
r1 = rf(userId, teamId, newCategory)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// Delete provides a mock function with given fields: channelId, time
|
// Delete provides a mock function with given fields: channelId, time
|
||||||
func (_m *ChannelStore) Delete(channelId string, time int64) error {
|
func (_m *ChannelStore) Delete(channelId string, time int64) error {
|
||||||
ret := _m.Called(channelId, time)
|
ret := _m.Called(channelId, time)
|
||||||
@@ -192,6 +247,22 @@ func (_m *ChannelStore) Delete(channelId string, time int64) error {
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteSidebarCategory provides a mock function with given fields: categoryId
|
||||||
|
func (_m *ChannelStore) DeleteSidebarCategory(categoryId string) *model.AppError {
|
||||||
|
ret := _m.Called(categoryId)
|
||||||
|
|
||||||
|
var r0 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
|
||||||
|
r0 = rf(categoryId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
// Get provides a mock function with given fields: id, allowFromCache
|
// Get provides a mock function with given fields: id, allowFromCache
|
||||||
func (_m *ChannelStore) Get(id string, allowFromCache bool) (*model.Channel, error) {
|
func (_m *ChannelStore) Get(id string, allowFromCache bool) (*model.Channel, error) {
|
||||||
ret := _m.Called(id, allowFromCache)
|
ret := _m.Called(id, allowFromCache)
|
||||||
@@ -1126,6 +1197,81 @@ func (_m *ChannelStore) GetPublicChannelsForTeam(teamId string, offset int, limi
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSidebarCategories provides a mock function with given fields: userId, teamId
|
||||||
|
func (_m *ChannelStore) GetSidebarCategories(userId string, teamId string) (*model.OrderedSidebarCategories, *model.AppError) {
|
||||||
|
ret := _m.Called(userId, teamId)
|
||||||
|
|
||||||
|
var r0 *model.OrderedSidebarCategories
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string) *model.OrderedSidebarCategories); ok {
|
||||||
|
r0 = rf(userId, teamId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.OrderedSidebarCategories)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(1).(func(string, string) *model.AppError); ok {
|
||||||
|
r1 = rf(userId, teamId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSidebarCategory provides a mock function with given fields: categoryId
|
||||||
|
func (_m *ChannelStore) GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
ret := _m.Called(categoryId)
|
||||||
|
|
||||||
|
var r0 *model.SidebarCategoryWithChannels
|
||||||
|
if rf, ok := ret.Get(0).(func(string) *model.SidebarCategoryWithChannels); ok {
|
||||||
|
r0 = rf(categoryId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.SidebarCategoryWithChannels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
|
||||||
|
r1 = rf(categoryId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSidebarCategoryOrder provides a mock function with given fields: userId, teamId
|
||||||
|
func (_m *ChannelStore) GetSidebarCategoryOrder(userId string, teamId string) ([]string, *model.AppError) {
|
||||||
|
ret := _m.Called(userId, teamId)
|
||||||
|
|
||||||
|
var r0 []string
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string) []string); ok {
|
||||||
|
r0 = rf(userId, teamId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(1).(func(string, string) *model.AppError); ok {
|
||||||
|
r1 = rf(userId, teamId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetTeamChannels provides a mock function with given fields: teamId
|
// GetTeamChannels provides a mock function with given fields: teamId
|
||||||
func (_m *ChannelStore) GetTeamChannels(teamId string) (*model.ChannelList, *model.AppError) {
|
func (_m *ChannelStore) GetTeamChannels(teamId string) (*model.ChannelList, *model.AppError) {
|
||||||
ret := _m.Called(teamId)
|
ret := _m.Called(teamId)
|
||||||
@@ -1264,6 +1410,29 @@ func (_m *ChannelStore) MigrateChannelMembers(fromChannelId string, fromUserId s
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MigrateFavoritesToSidebarChannels provides a mock function with given fields: lastUserId, runningOrder
|
||||||
|
func (_m *ChannelStore) MigrateFavoritesToSidebarChannels(lastUserId string, runningOrder int64) (map[string]interface{}, error) {
|
||||||
|
ret := _m.Called(lastUserId, runningOrder)
|
||||||
|
|
||||||
|
var r0 map[string]interface{}
|
||||||
|
if rf, ok := ret.Get(0).(func(string, int64) map[string]interface{}); ok {
|
||||||
|
r0 = rf(lastUserId, runningOrder)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(map[string]interface{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(string, int64) error); ok {
|
||||||
|
r1 = rf(lastUserId, runningOrder)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// MigratePublicChannels provides a mock function with given fields:
|
// MigratePublicChannels provides a mock function with given fields:
|
||||||
func (_m *ChannelStore) MigratePublicChannels() error {
|
func (_m *ChannelStore) MigratePublicChannels() error {
|
||||||
ret := _m.Called()
|
ret := _m.Called()
|
||||||
@@ -1278,6 +1447,29 @@ func (_m *ChannelStore) MigratePublicChannels() error {
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MigrateSidebarCategories provides a mock function with given fields: fromTeamId, fromUserId
|
||||||
|
func (_m *ChannelStore) MigrateSidebarCategories(fromTeamId string, fromUserId string) (map[string]interface{}, error) {
|
||||||
|
ret := _m.Called(fromTeamId, fromUserId)
|
||||||
|
|
||||||
|
var r0 map[string]interface{}
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string) map[string]interface{}); ok {
|
||||||
|
r0 = rf(fromTeamId, fromUserId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(map[string]interface{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||||
|
r1 = rf(fromTeamId, fromUserId)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// PermanentDelete provides a mock function with given fields: channelId
|
// PermanentDelete provides a mock function with given fields: channelId
|
||||||
func (_m *ChannelStore) PermanentDelete(channelId string) error {
|
func (_m *ChannelStore) PermanentDelete(channelId string) error {
|
||||||
ret := _m.Called(channelId)
|
ret := _m.Called(channelId)
|
||||||
@@ -1822,6 +2014,79 @@ func (_m *ChannelStore) UpdateMultipleMembers(members []*model.ChannelMember) ([
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateSidebarCategories provides a mock function with given fields: userId, teamId, categories
|
||||||
|
func (_m *ChannelStore) UpdateSidebarCategories(userId string, teamId string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
ret := _m.Called(userId, teamId, categories)
|
||||||
|
|
||||||
|
var r0 []*model.SidebarCategoryWithChannels
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels) []*model.SidebarCategoryWithChannels); ok {
|
||||||
|
r0 = rf(userId, teamId, categories)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.SidebarCategoryWithChannels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(1).(func(string, string, []*model.SidebarCategoryWithChannels) *model.AppError); ok {
|
||||||
|
r1 = rf(userId, teamId, categories)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSidebarCategoryOrder provides a mock function with given fields: userId, teamId, categoryOrder
|
||||||
|
func (_m *ChannelStore) UpdateSidebarCategoryOrder(userId string, teamId string, categoryOrder []string) *model.AppError {
|
||||||
|
ret := _m.Called(userId, teamId, categoryOrder)
|
||||||
|
|
||||||
|
var r0 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string, []string) *model.AppError); ok {
|
||||||
|
r0 = rf(userId, teamId, categoryOrder)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSidebarChannelCategoryOnMove provides a mock function with given fields: channel, newTeamId
|
||||||
|
func (_m *ChannelStore) UpdateSidebarChannelCategoryOnMove(channel *model.Channel, newTeamId string) *model.AppError {
|
||||||
|
ret := _m.Called(channel, newTeamId)
|
||||||
|
|
||||||
|
var r0 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Channel, string) *model.AppError); ok {
|
||||||
|
r0 = rf(channel, newTeamId)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSidebarChannelsByPreferences provides a mock function with given fields: preferences
|
||||||
|
func (_m *ChannelStore) UpdateSidebarChannelsByPreferences(preferences *model.Preferences) *model.AppError {
|
||||||
|
ret := _m.Called(preferences)
|
||||||
|
|
||||||
|
var r0 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Preferences) *model.AppError); ok {
|
||||||
|
r0 = rf(preferences)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
// UserBelongsToChannels provides a mock function with given fields: userId, channelIds
|
// UserBelongsToChannels provides a mock function with given fields: userId, channelIds
|
||||||
func (_m *ChannelStore) UserBelongsToChannels(userId string, channelIds []string) (bool, *model.AppError) {
|
func (_m *ChannelStore) UserBelongsToChannels(userId string, channelIds []string) (bool, *model.AppError) {
|
||||||
ret := _m.Called(userId, channelIds)
|
ret := _m.Called(userId, channelIds)
|
||||||
|
|||||||
@@ -247,6 +247,20 @@ func (_m *SqlStore) CreateIndexIfNotExists(indexName string, tableName string, c
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateUniqueCompositeIndexIfNotExists provides a mock function with given fields: indexName, tableName, columnNames
|
||||||
|
func (_m *SqlStore) CreateUniqueCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool {
|
||||||
|
ret := _m.Called(indexName, tableName, columnNames)
|
||||||
|
|
||||||
|
var r0 bool
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string, []string) bool); ok {
|
||||||
|
r0 = rf(indexName, tableName, columnNames)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
// CreateUniqueIndexIfNotExists provides a mock function with given fields: indexName, tableName, columnName
|
// CreateUniqueIndexIfNotExists provides a mock function with given fields: indexName, tableName, columnName
|
||||||
func (_m *SqlStore) CreateUniqueIndexIfNotExists(indexName string, tableName string, columnName string) bool {
|
func (_m *SqlStore) CreateUniqueIndexIfNotExists(indexName string, tableName string, columnName string) bool {
|
||||||
ret := _m.Called(indexName, tableName, columnName)
|
ret := _m.Called(indexName, tableName, columnName)
|
||||||
|
|||||||
@@ -552,6 +552,22 @@ func (s *TimerLayerChannelStore) ClearCaches() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) ClearSidebarOnTeamLeave(userId string, teamId string) *model.AppError {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0 := s.ChannelStore.ClearSidebarOnTeamLeave(userId, teamId)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar0 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.ClearSidebarOnTeamLeave", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, *model.AppError) {
|
func (s *TimerLayerChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, *model.AppError) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -584,6 +600,38 @@ func (s *TimerLayerChannelStore) CreateDirectChannel(userId *model.User, otherUs
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) CreateInitialSidebarCategories(user *model.User, teamId string) error {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0 := s.ChannelStore.CreateInitialSidebarCategories(user, teamId)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar0 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.CreateInitialSidebarCategories", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) CreateSidebarCategory(userId string, teamId string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.CreateSidebarCategory(userId, teamId, newCategory)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar1 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.CreateSidebarCategory", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) Delete(channelId string, time int64) error {
|
func (s *TimerLayerChannelStore) Delete(channelId string, time int64) error {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -600,6 +648,22 @@ func (s *TimerLayerChannelStore) Delete(channelId string, time int64) error {
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) DeleteSidebarCategory(categoryId string) *model.AppError {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0 := s.ChannelStore.DeleteSidebarCategory(categoryId)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar0 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.DeleteSidebarCategory", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) Get(id string, allowFromCache bool) (*model.Channel, error) {
|
func (s *TimerLayerChannelStore) Get(id string, allowFromCache bool) (*model.Channel, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -1224,6 +1288,54 @@ func (s *TimerLayerChannelStore) GetPublicChannelsForTeam(teamId string, offset
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) GetSidebarCategories(userId string, teamId string) (*model.OrderedSidebarCategories, *model.AppError) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.GetSidebarCategories(userId, teamId)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar1 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetSidebarCategories", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.GetSidebarCategory(categoryId)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar1 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetSidebarCategory", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) GetSidebarCategoryOrder(userId string, teamId string) ([]string, *model.AppError) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.GetSidebarCategoryOrder(userId, teamId)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar1 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetSidebarCategoryOrder", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) GetTeamChannels(teamId string) (*model.ChannelList, *model.AppError) {
|
func (s *TimerLayerChannelStore) GetTeamChannels(teamId string) (*model.ChannelList, *model.AppError) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -1409,6 +1521,22 @@ func (s *TimerLayerChannelStore) MigrateChannelMembers(fromChannelId string, fro
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) MigrateFavoritesToSidebarChannels(lastUserId string, runningOrder int64) (map[string]interface{}, error) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.MigrateFavoritesToSidebarChannels(lastUserId, runningOrder)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar1 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.MigrateFavoritesToSidebarChannels", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) MigratePublicChannels() error {
|
func (s *TimerLayerChannelStore) MigratePublicChannels() error {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -1425,6 +1553,22 @@ func (s *TimerLayerChannelStore) MigratePublicChannels() error {
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) MigrateSidebarCategories(fromTeamId string, fromUserId string) (map[string]interface{}, error) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.MigrateSidebarCategories(fromTeamId, fromUserId)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar1 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.MigrateSidebarCategories", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) PermanentDelete(channelId string) error {
|
func (s *TimerLayerChannelStore) PermanentDelete(channelId string) error {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -1841,6 +1985,70 @@ func (s *TimerLayerChannelStore) UpdateMultipleMembers(members []*model.ChannelM
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) UpdateSidebarCategories(userId string, teamId string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0, resultVar1 := s.ChannelStore.UpdateSidebarCategories(userId, teamId, categories)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar1 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.UpdateSidebarCategories", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) UpdateSidebarCategoryOrder(userId string, teamId string, categoryOrder []string) *model.AppError {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0 := s.ChannelStore.UpdateSidebarCategoryOrder(userId, teamId, categoryOrder)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar0 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.UpdateSidebarCategoryOrder", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) UpdateSidebarChannelCategoryOnMove(channel *model.Channel, newTeamId string) *model.AppError {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0 := s.ChannelStore.UpdateSidebarChannelCategoryOnMove(channel, newTeamId)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar0 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.UpdateSidebarChannelCategoryOnMove", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) UpdateSidebarChannelsByPreferences(preferences *model.Preferences) *model.AppError {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0 := s.ChannelStore.UpdateSidebarChannelsByPreferences(preferences)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar0 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.UpdateSidebarChannelsByPreferences", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) UserBelongsToChannels(userId string, channelIds []string) (bool, *model.AppError) {
|
func (s *TimerLayerChannelStore) UserBelongsToChannels(userId string, channelIds []string) (bool, *model.AppError) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
|||||||
@@ -293,6 +293,17 @@ func (c *Context) RequireTeamId() *Context {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Context) RequireCategoryId() *Context {
|
||||||
|
if c.Err != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Params.CategoryId) != 26 {
|
||||||
|
c.SetInvalidUrlParam("category_id")
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) RequireInviteId() *Context {
|
func (c *Context) RequireInviteId() *Context {
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return c
|
return c
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ type Params struct {
|
|||||||
IncludeDeleted bool
|
IncludeDeleted bool
|
||||||
FilterAllowReference bool
|
FilterAllowReference bool
|
||||||
FilterParentTeamPermitted bool
|
FilterParentTeamPermitted bool
|
||||||
|
CategoryId string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParamsFromRequest(r *http.Request) *Params {
|
func ParamsFromRequest(r *http.Request) *Params {
|
||||||
@@ -93,6 +94,10 @@ func ParamsFromRequest(r *http.Request) *Params {
|
|||||||
params.TeamId = val
|
params.TeamId = val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val, ok := props["category_id"]; ok {
|
||||||
|
params.CategoryId = val
|
||||||
|
}
|
||||||
|
|
||||||
if val, ok := props["invite_id"]; ok {
|
if val, ok := props["invite_id"]; ok {
|
||||||
params.InviteId = val
|
params.InviteId = val
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user