Merge branch 'master' into MM-45118_my_top_dms

Этот коммит содержится в:
Mattermod
2022-08-05 09:56:52 +03:00
коммит произвёл GitHub
родитель 45e434cc26 14246abdef
Коммит 4fc8ef0125
87 изменённых файлов: 966 добавлений и 493 удалений

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

@@ -17,7 +17,7 @@ jobs:
setup: setup:
working_directory: ~/mattermost/mattermost-server working_directory: ~/mattermost/mattermost-server
docker: docker:
- image: mattermost/mattermost-build-webapp:20210524_node-16 - image: mattermost/mattermost-build-webapp:20220802_node-16.10.0@sha256:3272aa759f10c2ef1719ed08cc82ddb07224bec5be86f09800c72f5e2a623c3d
resource_class: xlarge resource_class: xlarge
# Use `--retry-all-errors` instead of `until` after curl version >= 7.71.0; `retry` will not work, since it only retries on transient errors, 403 is not one of them. # Use `--retry-all-errors` instead of `until` after curl version >= 7.71.0; `retry` will not work, since it only retries on transient errors, 403 is not one of them.
steps: steps:

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

@@ -117,7 +117,7 @@ func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, ent
if includeCache { if includeCache {
// Adds the cache layer to the test store // Adds the cache layer to the test store
options = append(options, app.StoreOverride(func(s *app.Server) store.Store { options = append(options, app.StoreOverride(func(s *app.Server) store.Store {
lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.GetMetrics(), s.Cluster, s.CacheProvider)
if err2 != nil { if err2 != nil {
panic(err2) panic(err2)
} }
@@ -218,7 +218,7 @@ func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, ent
return th return th
} }
func SetupEnterprise(tb testing.TB) *TestHelper { func SetupEnterprise(tb testing.TB, options ...app.Option) *TestHelper {
if testing.Short() { if testing.Short() {
tb.SkipNow() tb.SkipNow()
} }
@@ -232,7 +232,7 @@ func SetupEnterprise(tb testing.TB) *TestHelper {
dbStore.MarkSystemRanUnitTests() dbStore.MarkSystemRanUnitTests()
mainHelper.PreloadMigrations() mainHelper.PreloadMigrations()
searchEngine := mainHelper.GetSearchEngine() searchEngine := mainHelper.GetSearchEngine()
th := setupTestHelper(dbStore, searchEngine, true, true, nil, nil) th := setupTestHelper(dbStore, searchEngine, true, true, nil, options)
th.InitLogin() th.InitLogin()
return th return th
} }
@@ -322,8 +322,8 @@ func SetupWithStoreMock(tb testing.TB) *TestHelper {
return th return th
} }
func SetupEnterpriseWithStoreMock(tb testing.TB) *TestHelper { func SetupEnterpriseWithStoreMock(tb testing.TB, options ...app.Option) *TestHelper {
th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, true, false, nil, nil) th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, true, false, nil, options)
statusMock := mocks.StatusStore{} statusMock := mocks.StatusStore{}
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil) statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil)
statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil) statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil)

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

@@ -187,7 +187,7 @@ func getBots(c *Context, w http.ResponseWriter, r *http.Request) {
} }
if err := json.NewEncoder(w).Encode(bots); err != nil { if err := json.NewEncoder(w).Encode(bots); err != nil {
mlog.Warn("Error while writing response", mlog.Err(err)) c.Logger.Warn("Error while writing response", mlog.Err(err))
} }
} }
@@ -227,7 +227,7 @@ func updateBotActive(c *Context, w http.ResponseWriter, active bool) {
auditRec.AddEventObjectType("bot") auditRec.AddEventObjectType("bot")
if err := json.NewEncoder(w).Encode(bot); err != nil { if err := json.NewEncoder(w).Encode(bot); err != nil {
mlog.Warn("Error while writing response", mlog.Err(err)) c.Logger.Warn("Error while writing response", mlog.Err(err))
} }
} }

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

@@ -212,14 +212,6 @@ func TestRequestTrialLicense(t *testing.T) {
CheckForbiddenStatus(t, resp) CheckForbiddenStatus(t, resp)
}) })
t.Run("blank site url", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SiteURL = "" })
defer th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SiteURL = "http://localhost:8065/" })
resp, err := th.SystemAdminClient.RequestTrialLicense(1000)
CheckErrorID(t, err, "api.license.request_trial_license.no-site-url.app_error")
CheckBadRequestStatus(t, resp)
})
t.Run("trial license user count less than current users", func(t *testing.T) { t.Run("trial license user count less than current users", func(t *testing.T) {
nUsers := 1 nUsers := 1
license := model.NewTestLicense() license := model.NewTestLicense()

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

@@ -3172,11 +3172,6 @@ func unfollowThreadByUser(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
if !c.App.SessionHasPermissionToChannelByPost(*c.AppContext.Session(), c.Params.ThreadId, model.PermissionReadChannel) {
c.SetPermissionError(model.PermissionReadChannel)
return
}
err := c.App.UpdateThreadFollowForUser(c.Params.UserId, c.Params.TeamId, c.Params.ThreadId, false) err := c.App.UpdateThreadFollowForUser(c.Params.UserId, c.Params.TeamId, c.Params.ThreadId, false)
if err != nil { if err != nil {
c.Err = err c.Err = err

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

@@ -117,7 +117,7 @@ func (a *App) MessageExport() einterfaces.MessageExportInterface {
return a.ch.MessageExport return a.ch.MessageExport
} }
func (a *App) Metrics() einterfaces.MetricsInterface { func (a *App) Metrics() einterfaces.MetricsInterface {
return a.ch.srv.Metrics return a.ch.srv.GetMetrics()
} }
func (a *App) Notification() einterfaces.NotificationInterface { func (a *App) Notification() einterfaces.NotificationInterface {
return a.ch.Notification return a.ch.Notification

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

@@ -37,12 +37,12 @@ import (
// AppIface is extracted from App struct and contains all it's exported methods. It's provided to allow partial interface passing and app layers creation. // AppIface is extracted from App struct and contains all it's exported methods. It's provided to allow partial interface passing and app layers creation.
type AppIface interface { type AppIface interface {
// @openTracingParams args // @openTracingParams args
ExecuteCommand(c *request.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) ExecuteCommand(c request.CTX, args *model.CommandArgs) (*model.CommandResponse, *model.AppError)
// @openTracingParams teamID // @openTracingParams teamID
// previous ListCommands now ListAutocompleteCommands // previous ListCommands now ListAutocompleteCommands
ListAutocompleteCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) ListAutocompleteCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError)
// @openTracingParams teamID, skipSlackParsing // @openTracingParams teamID, skipSlackParsing
CreateCommandPost(c *request.Context, post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError) CreateCommandPost(c request.CTX, post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError)
// AddChannelMember adds a user to a channel. It is a wrapper over AddUserToChannel. // AddChannelMember adds a user to a channel. It is a wrapper over AddUserToChannel.
AddChannelMember(c request.CTX, userID string, channel *model.Channel, opts ChannelMemberOpts) (*model.ChannelMember, *model.AppError) AddChannelMember(c request.CTX, userID string, channel *model.Channel, opts ChannelMemberOpts) (*model.ChannelMember, *model.AppError)
// AddCursorIdsForPostList adds NextPostId and PrevPostId as cursor to the PostList. // AddCursorIdsForPostList adds NextPostId and PrevPostId as cursor to the PostList.
@@ -84,7 +84,7 @@ type AppIface interface {
// ConvertUserToBot converts a user to bot. // ConvertUserToBot converts a user to bot.
ConvertUserToBot(user *model.User) (*model.Bot, *model.AppError) ConvertUserToBot(user *model.User) (*model.Bot, *model.AppError)
// CreateBot creates the given bot and corresponding user. // CreateBot creates the given bot and corresponding user.
CreateBot(c *request.Context, bot *model.Bot) (*model.Bot, *model.AppError) CreateBot(c request.CTX, bot *model.Bot) (*model.Bot, *model.AppError)
// CreateChannelScheme creates a new Scheme of scope channel and assigns it to the channel. // CreateChannelScheme creates a new Scheme of scope channel and assigns it to the channel.
CreateChannelScheme(c request.CTX, channel *model.Channel) (*model.Scheme, *model.AppError) CreateChannelScheme(c request.CTX, channel *model.Channel) (*model.Scheme, *model.AppError)
// CreateDefaultMemberships adds users to teams and channels based on their group memberships and how those groups // CreateDefaultMemberships adds users to teams and channels based on their group memberships and how those groups
@@ -132,7 +132,7 @@ type AppIface interface {
// any ensureBotOptions hence it is not required for now. // any ensureBotOptions hence it is not required for now.
// TODO: Once the focalboard migration completed, we should add this logic to the app and // TODO: Once the focalboard migration completed, we should add this logic to the app and
// let plugin-api use the same code // let plugin-api use the same code
EnsureBot(c *request.Context, productID string, bot *model.Bot) (string, error) EnsureBot(c request.CTX, productID string, bot *model.Bot) (string, error)
// Expand announcements in incoming webhooks from Slack. Those announcements // Expand announcements in incoming webhooks from Slack. Those announcements
// can be found in the text attribute, or in the pretext, text, title and value // can be found in the text attribute, or in the pretext, text, title and value
// attributes of the attachment structure. The Slack attachment structure is // attributes of the attachment structure. The Slack attachment structure is
@@ -250,7 +250,7 @@ type AppIface interface {
MentionsToPublicChannels(c request.CTX, message, teamID string) model.ChannelMentionMap MentionsToPublicChannels(c request.CTX, message, teamID string) model.ChannelMentionMap
// MentionsToTeamMembers returns all the @ mentions found in message that // MentionsToTeamMembers returns all the @ mentions found in message that
// belong to users in the specified team, linking them to their users // belong to users in the specified team, linking them to their users
MentionsToTeamMembers(message, teamID string) model.UserMentionMap MentionsToTeamMembers(c request.CTX, message, teamID string) model.UserMentionMap
// MoveChannel method is prone to data races if someone joins to channel during the move process. However this // MoveChannel method is prone to data races if someone joins to channel during the move process. However this
// function is only exposed to sysadmins and the possibility of this edge case is relatively small. // function is only exposed to sysadmins and the possibility of this edge case is relatively small.
MoveChannel(c request.CTX, team *model.Team, channel *model.Channel, user *model.User) *model.AppError MoveChannel(c request.CTX, team *model.Team, channel *model.Channel, user *model.User) *model.AppError
@@ -328,7 +328,7 @@ type AppIface interface {
SyncPlugins() *model.AppError SyncPlugins() *model.AppError
// SyncRolesAndMembership updates the SchemeAdmin status and membership of all of the members of the given // SyncRolesAndMembership updates the SchemeAdmin status and membership of all of the members of the given
// syncable. // syncable.
SyncRolesAndMembership(c *request.Context, syncableID string, syncableType model.GroupSyncableType, includeRemovedMembers bool) SyncRolesAndMembership(c request.CTX, syncableID string, syncableType model.GroupSyncableType, includeRemovedMembers bool)
// SyncSyncableRoles updates the SchemeAdmin field value of the given syncable's members based on the configuration of // SyncSyncableRoles updates the SchemeAdmin field value of the given syncable's members based on the configuration of
// the member's group memberships and the configuration of those groups to the syncable. This method should only // the member's group memberships and the configuration of those groups to the syncable. This method should only
// be invoked on group-synced (aka group-constrained) syncables. // be invoked on group-synced (aka group-constrained) syncables.
@@ -354,7 +354,7 @@ type AppIface interface {
// This to be used for places we check the users password when they are already logged in // This to be used for places we check the users password when they are already logged in
DoubleCheckPassword(user *model.User, password string) *model.AppError DoubleCheckPassword(user *model.User, password string) *model.AppError
// UpdateBotActive marks a bot as active or inactive, along with its corresponding user. // UpdateBotActive marks a bot as active or inactive, along with its corresponding user.
UpdateBotActive(c *request.Context, botUserId string, active bool) (*model.Bot, *model.AppError) UpdateBotActive(c request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError)
// UpdateBotOwner changes a bot's owner to the given value. // UpdateBotOwner changes a bot's owner to the given value.
UpdateBotOwner(botUserId, newOwnerId string) (*model.Bot, *model.AppError) UpdateBotOwner(botUserId, newOwnerId string) (*model.Bot, *model.AppError)
// UpdateChannel updates a given channel by its Id. It also publishes the CHANNEL_UPDATED event. // UpdateChannel updates a given channel by its Id. It also publishes the CHANNEL_UPDATED event.
@@ -374,7 +374,7 @@ type AppIface interface {
// UpdateWebConnUserActivity sets the LastUserActivityAt of the hub for the given session. // UpdateWebConnUserActivity sets the LastUserActivityAt of the hub for the given session.
UpdateWebConnUserActivity(session model.Session, activityAt int64) UpdateWebConnUserActivity(session model.Session, activityAt int64)
// UploadFile uploads a single file in form of a completely constructed byte array for a channel. // UploadFile uploads a single file in form of a completely constructed byte array for a channel.
UploadFile(c *request.Context, data []byte, channelID string, filename string) (*model.FileInfo, *model.AppError) UploadFile(c request.CTX, data []byte, channelID string, filename string) (*model.FileInfo, *model.AppError)
// UploadFileX uploads a single file as specified in t. It applies the upload // UploadFileX uploads a single file as specified in t. It applies the upload
// constraints, executes plugins and image processing logic as needed. It // constraints, executes plugins and image processing logic as needed. It
// returns a filled-out FileInfo and an optional error. A plugin may reject the // returns a filled-out FileInfo and an optional error. A plugin may reject the
@@ -402,12 +402,12 @@ type AppIface interface {
AddSessionToCache(session *model.Session) AddSessionToCache(session *model.Session)
AddStatusCache(status *model.Status) AddStatusCache(status *model.Status)
AddStatusCacheSkipClusterSend(status *model.Status) AddStatusCacheSkipClusterSend(status *model.Status)
AddTeamMember(c *request.Context, teamID, userID string) (*model.TeamMember, *model.AppError) AddTeamMember(c request.CTX, teamID, userID string) (*model.TeamMember, *model.AppError)
AddTeamMemberByInviteId(c *request.Context, inviteId, userID string) (*model.TeamMember, *model.AppError) AddTeamMemberByInviteId(c *request.Context, inviteId, userID string) (*model.TeamMember, *model.AppError)
AddTeamMemberByToken(c *request.Context, userID, tokenID string) (*model.TeamMember, *model.AppError) AddTeamMemberByToken(c *request.Context, userID, tokenID string) (*model.TeamMember, *model.AppError)
AddTeamMembers(c *request.Context, teamID string, userIDs []string, userRequestorId string, graceful bool) ([]*model.TeamMemberWithError, *model.AppError) AddTeamMembers(c *request.Context, teamID string, userIDs []string, userRequestorId string, graceful bool) ([]*model.TeamMemberWithError, *model.AppError)
AddTeamsToRetentionPolicy(policyID string, teamIDs []string) *model.AppError AddTeamsToRetentionPolicy(policyID string, teamIDs []string) *model.AppError
AddUserToTeam(c *request.Context, teamID string, userID string, userRequestorId string) (*model.Team, *model.TeamMember, *model.AppError) AddUserToTeam(c request.CTX, teamID string, userID string, userRequestorId string) (*model.Team, *model.TeamMember, *model.AppError)
AddUserToTeamByInviteId(c *request.Context, inviteId string, userID string) (*model.Team, *model.TeamMember, *model.AppError) AddUserToTeamByInviteId(c *request.Context, inviteId string, userID string) (*model.Team, *model.TeamMember, *model.AppError)
AddUserToTeamByTeamId(c *request.Context, teamID string, user *model.User) *model.AppError AddUserToTeamByTeamId(c *request.Context, teamID string, user *model.User) *model.AppError
AddUserToTeamByToken(c *request.Context, userID string, tokenID string) (*model.Team, *model.TeamMember, *model.AppError) AddUserToTeamByToken(c *request.Context, userID string, tokenID string) (*model.Team, *model.TeamMember, *model.AppError)
@@ -428,10 +428,10 @@ type AppIface interface {
AutocompleteUsersInChannel(teamID string, channelID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) AutocompleteUsersInChannel(teamID string, channelID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError)
AutocompleteUsersInTeam(teamID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInTeam, *model.AppError) AutocompleteUsersInTeam(teamID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInTeam, *model.AppError)
BroadcastStatus(status *model.Status) BroadcastStatus(status *model.Status)
BuildPostReactions(postID string) (*[]ReactionImportData, *model.AppError) BuildPostReactions(ctx request.CTX, postID string) (*[]ReactionImportData, *model.AppError)
BuildPushNotificationMessage(c request.CTX, contentsConfig string, post *model.Post, user *model.User, channel *model.Channel, channelName string, senderName string, explicitMention bool, channelWideMention bool, replyToThreadType string) (*model.PushNotification, *model.AppError) BuildPushNotificationMessage(c request.CTX, contentsConfig string, post *model.Post, user *model.User, channel *model.Channel, channelName string, senderName string, explicitMention bool, channelWideMention bool, replyToThreadType string) (*model.PushNotification, *model.AppError)
BuildSamlMetadataObject(idpMetadata []byte) (*model.SamlMetadataResponse, *model.AppError) BuildSamlMetadataObject(idpMetadata []byte) (*model.SamlMetadataResponse, *model.AppError)
BulkExport(writer io.Writer, outPath string, opts model.BulkExportOpts) *model.AppError BulkExport(ctx request.CTX, writer io.Writer, outPath string, opts model.BulkExportOpts) *model.AppError
BulkImport(c *request.Context, jsonlReader io.Reader, attachmentsReader *zip.Reader, dryRun bool, workers int) (*model.AppError, int) BulkImport(c *request.Context, jsonlReader io.Reader, attachmentsReader *zip.Reader, dryRun bool, workers int) (*model.AppError, int)
BulkImportWithPath(c *request.Context, jsonlReader io.Reader, attachmentsReader *zip.Reader, dryRun bool, workers int, importPath string) (*model.AppError, int) BulkImportWithPath(c *request.Context, jsonlReader io.Reader, attachmentsReader *zip.Reader, dryRun bool, workers int, importPath string) (*model.AppError, int)
CancelJob(jobId string) *model.AppError CancelJob(jobId string) *model.AppError
@@ -449,13 +449,13 @@ type AppIface interface {
CheckUserPostflightAuthenticationCriteria(user *model.User) *model.AppError CheckUserPostflightAuthenticationCriteria(user *model.User) *model.AppError
CheckUserPreflightAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError CheckUserPreflightAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError
CheckWebConn(userID, connectionID string) *CheckConnResult CheckWebConn(userID, connectionID string) *CheckConnResult
ClearChannelMembersCache(c request.CTX, channelID string) ClearChannelMembersCache(c request.CTX, channelID string) error
ClearLatestVersionCache() ClearLatestVersionCache()
ClearSessionCacheForAllUsers() ClearSessionCacheForAllUsers()
ClearSessionCacheForAllUsersSkipClusterSend() ClearSessionCacheForAllUsersSkipClusterSend()
ClearSessionCacheForUser(userID string) ClearSessionCacheForUser(userID string)
ClearSessionCacheForUserSkipClusterSend(userID string) ClearSessionCacheForUserSkipClusterSend(userID string)
ClearTeamMembersCache(teamID string) ClearTeamMembersCache(teamID string) error
ClientConfig() map[string]string ClientConfig() map[string]string
ClientConfigHash() string ClientConfigHash() string
Cloud() einterfaces.CloudInterface Cloud() einterfaces.CloudInterface
@@ -484,7 +484,7 @@ type AppIface interface {
CreateOutgoingWebhook(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.AppError) CreateOutgoingWebhook(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.AppError)
CreatePasswordRecoveryToken(userID, email string) (*model.Token, *model.AppError) CreatePasswordRecoveryToken(userID, email string) (*model.Token, *model.AppError)
CreatePost(c request.CTX, post *model.Post, channel *model.Channel, triggerWebhooks, setOnline bool) (savedPost *model.Post, err *model.AppError) CreatePost(c request.CTX, post *model.Post, channel *model.Channel, triggerWebhooks, setOnline bool) (savedPost *model.Post, err *model.AppError)
CreatePostAsUser(c *request.Context, post *model.Post, currentSessionId string, setOnline bool) (*model.Post, *model.AppError) CreatePostAsUser(c request.CTX, post *model.Post, currentSessionId string, setOnline bool) (*model.Post, *model.AppError)
CreatePostMissingChannel(c request.CTX, post *model.Post, triggerWebhooks bool) (*model.Post, *model.AppError) CreatePostMissingChannel(c request.CTX, post *model.Post, triggerWebhooks bool) (*model.Post, *model.AppError)
CreateRetentionPolicy(policy *model.RetentionPolicyWithTeamAndChannelIDs) (*model.RetentionPolicyWithTeamAndChannelCounts, *model.AppError) CreateRetentionPolicy(policy *model.RetentionPolicyWithTeamAndChannelIDs) (*model.RetentionPolicyWithTeamAndChannelCounts, *model.AppError)
CreateRole(role *model.Role) (*model.Role, *model.AppError) CreateRole(role *model.Role) (*model.Role, *model.AppError)
@@ -545,7 +545,7 @@ type AppIface interface {
DoPostActionWithCookie(c *request.Context, postID, actionId, userID, selectedOption string, cookie *model.PostActionCookie) (string, *model.AppError) DoPostActionWithCookie(c *request.Context, postID, actionId, userID, selectedOption string, cookie *model.PostActionCookie) (string, *model.AppError)
DoSystemConsoleRolesCreationMigration() DoSystemConsoleRolesCreationMigration()
DoUploadFile(c *request.Context, now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, *model.AppError) DoUploadFile(c *request.Context, now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, *model.AppError)
DoUploadFileExpectModification(c *request.Context, now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, []byte, *model.AppError) DoUploadFileExpectModification(c request.CTX, now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, []byte, *model.AppError)
DownloadFromURL(downloadURL string) ([]byte, error) DownloadFromURL(downloadURL string) ([]byte, error)
EnableUserAccessToken(token *model.UserAccessToken) *model.AppError EnableUserAccessToken(token *model.UserAccessToken) *model.AppError
EnvironmentConfig(filter func(reflect.StructField) bool) map[string]any EnvironmentConfig(filter func(reflect.StructField) bool) map[string]any
@@ -837,8 +837,8 @@ type AppIface interface {
GetWarnMetricsStatus() (map[string]*model.WarnMetricStatus, *model.AppError) GetWarnMetricsStatus() (map[string]*model.WarnMetricStatus, *model.AppError)
HTTPService() httpservice.HTTPService HTTPService() httpservice.HTTPService
Handle404(w http.ResponseWriter, r *http.Request) Handle404(w http.ResponseWriter, r *http.Request)
HandleCommandResponse(c *request.Context, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *model.AppError) HandleCommandResponse(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *model.AppError)
HandleCommandResponsePost(c *request.Context, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.Post, *model.AppError) HandleCommandResponsePost(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.Post, *model.AppError)
HandleCommandWebhook(c *request.Context, hookID string, response *model.CommandResponse) *model.AppError HandleCommandWebhook(c *request.Context, hookID string, response *model.CommandResponse) *model.AppError
HandleImages(previewPathList []string, thumbnailPathList []string, fileData [][]byte) HandleImages(previewPathList []string, thumbnailPathList []string, fileData [][]byte)
HandleIncomingWebhook(c *request.Context, hookID string, req *model.IncomingWebhookRequest) *model.AppError HandleIncomingWebhook(c *request.Context, hookID string, req *model.IncomingWebhookRequest) *model.AppError
@@ -874,7 +874,7 @@ type AppIface interface {
JoinUserToTeam(c request.CTX, team *model.Team, user *model.User, userRequestorId string) (*model.TeamMember, *model.AppError) JoinUserToTeam(c request.CTX, team *model.Team, user *model.User, userRequestorId string) (*model.TeamMember, *model.AppError)
Ldap() einterfaces.LdapInterface Ldap() einterfaces.LdapInterface
LeaveChannel(c request.CTX, channelID string, userID string) *model.AppError LeaveChannel(c request.CTX, channelID string, userID string) *model.AppError
LeaveTeam(c *request.Context, team *model.Team, user *model.User, requestorId string) *model.AppError LeaveTeam(c request.CTX, team *model.Team, user *model.User, requestorId string) *model.AppError
License() *model.License License() *model.License
LimitedClientConfig() map[string]string LimitedClientConfig() map[string]string
ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError)
@@ -955,7 +955,7 @@ type AppIface interface {
RemoveTeamIcon(teamID string) *model.AppError RemoveTeamIcon(teamID string) *model.AppError
RemoveTeamsFromRetentionPolicy(policyID string, teamIDs []string) *model.AppError RemoveTeamsFromRetentionPolicy(policyID string, teamIDs []string) *model.AppError
RemoveUserFromChannel(c request.CTX, userIDToRemove string, removerUserId string, channel *model.Channel) *model.AppError RemoveUserFromChannel(c request.CTX, userIDToRemove string, removerUserId string, channel *model.Channel) *model.AppError
RemoveUserFromTeam(c *request.Context, teamID string, userID string, requestorId string) *model.AppError RemoveUserFromTeam(c request.CTX, teamID string, userID string, requestorId string) *model.AppError
RemoveUsersFromChannelNotMemberOfTeam(c request.CTX, remover *model.User, channel *model.Channel, team *model.Team) *model.AppError RemoveUsersFromChannelNotMemberOfTeam(c request.CTX, remover *model.User, channel *model.Channel, team *model.Team) *model.AppError
RequestLicenseAndAckWarnMetric(c *request.Context, warnMetricId string, isBot bool) *model.AppError RequestLicenseAndAckWarnMetric(c *request.Context, warnMetricId string, isBot bool) *model.AppError
ResetPasswordFromToken(c request.CTX, userSuppliedTokenString, newPassword string) *model.AppError ResetPasswordFromToken(c request.CTX, userSuppliedTokenString, newPassword string) *model.AppError
@@ -1077,7 +1077,7 @@ type AppIface interface {
TotalWebsocketConnections() int TotalWebsocketConnections() int
TriggerWebhook(c request.CTX, payload *model.OutgoingWebhookPayload, hook *model.OutgoingWebhook, post *model.Post, channel *model.Channel) TriggerWebhook(c request.CTX, payload *model.OutgoingWebhookPayload, hook *model.OutgoingWebhook, post *model.Post, channel *model.Channel)
UnregisterPluginCommand(pluginID, teamID, trigger string) UnregisterPluginCommand(pluginID, teamID, trigger string)
UpdateActive(c *request.Context, user *model.User, active bool) (*model.User, *model.AppError) UpdateActive(c request.CTX, user *model.User, active bool) (*model.User, *model.AppError)
UpdateChannelMemberNotifyProps(c request.CTX, data map[string]string, channelID string, userID string) (*model.ChannelMember, *model.AppError) UpdateChannelMemberNotifyProps(c request.CTX, data map[string]string, channelID string, userID string) (*model.ChannelMember, *model.AppError)
UpdateChannelMemberRoles(c request.CTX, channelID string, userID string, newRoles string) (*model.ChannelMember, *model.AppError) UpdateChannelMemberRoles(c request.CTX, channelID string, userID string, newRoles string) (*model.ChannelMember, *model.AppError)
UpdateChannelMemberSchemeRoles(c request.CTX, channelID string, userID string, isSchemeGuest bool, isSchemeUser bool, isSchemeAdmin bool) (*model.ChannelMember, *model.AppError) UpdateChannelMemberSchemeRoles(c request.CTX, channelID string, userID string, isSchemeGuest bool, isSchemeUser bool, isSchemeAdmin bool) (*model.ChannelMember, *model.AppError)
@@ -1122,7 +1122,7 @@ type AppIface interface {
UpdateThreadReadForUserByPost(c request.CTX, currentSessionId, userID, teamID, threadID, postID string) (*model.ThreadResponse, *model.AppError) UpdateThreadReadForUserByPost(c request.CTX, currentSessionId, userID, teamID, threadID, postID string) (*model.ThreadResponse, *model.AppError)
UpdateThreadsReadForUser(userID, teamID string) *model.AppError UpdateThreadsReadForUser(userID, teamID string) *model.AppError
UpdateUser(c request.CTX, user *model.User, sendNotifications bool) (*model.User, *model.AppError) UpdateUser(c request.CTX, user *model.User, sendNotifications bool) (*model.User, *model.AppError)
UpdateUserActive(c *request.Context, userID string, active bool) *model.AppError UpdateUserActive(c request.CTX, userID string, active bool) *model.AppError
UpdateUserAsUser(c request.CTX, user *model.User, asAdmin bool) (*model.User, *model.AppError) UpdateUserAsUser(c request.CTX, user *model.User, asAdmin bool) (*model.User, *model.AppError)
UpdateUserAuth(userID string, userAuth *model.UserAuth) (*model.UserAuth, *model.AppError) UpdateUserAuth(userID string, userAuth *model.UserAuth) (*model.UserAuth, *model.AppError)
UpdateUserRoles(c request.CTX, userID string, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError) UpdateUserRoles(c request.CTX, userID string, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError)

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

@@ -38,7 +38,7 @@ func (w *botServiceWrapper) EnsureBot(c *request.Context, productID string, bot
// any ensureBotOptions hence it is not required for now. // any ensureBotOptions hence it is not required for now.
// TODO: Once the focalboard migration completed, we should add this logic to the app and // TODO: Once the focalboard migration completed, we should add this logic to the app and
// let plugin-api use the same code // let plugin-api use the same code
func (a *App) EnsureBot(c *request.Context, productID string, bot *model.Bot) (string, error) { func (a *App) EnsureBot(c request.CTX, productID string, bot *model.Bot) (string, error) {
if bot == nil { if bot == nil {
return "", errors.New("passed a nil bot") return "", errors.New("passed a nil bot")
} }
@@ -77,7 +77,7 @@ func (a *App) EnsureBot(c *request.Context, productID string, bot *model.Bot) (s
return "", fmt.Errorf("failed to set plugin key: %w", err) return "", fmt.Errorf("failed to set plugin key: %w", err)
} }
} else { } else {
a.Srv().Log.Error("Product attempted to use an account that already exists. Convert user to a bot "+ c.Logger().Error("Product attempted to use an account that already exists. Convert user to a bot "+
"account in the CLI by running 'mattermost user convert <username> --bot'. If the user is an "+ "account in the CLI by running 'mattermost user convert <username> --bot'. If the user is an "+
"existing user account you want to preserve, change its username and restart the Mattermost server, "+ "existing user account you want to preserve, change its username and restart the Mattermost server, "+
"after which the plugin will create a bot account with that name. For more information about bot "+ "after which the plugin will create a bot account with that name. For more information about bot "+
@@ -103,7 +103,7 @@ func (a *App) EnsureBot(c *request.Context, productID string, bot *model.Bot) (s
} }
// CreateBot creates the given bot and corresponding user. // CreateBot creates the given bot and corresponding user.
func (a *App) CreateBot(c *request.Context, bot *model.Bot) (*model.Bot, *model.AppError) { func (a *App) CreateBot(c request.CTX, bot *model.Bot) (*model.Bot, *model.AppError) {
vErr := bot.IsValidCreate() vErr := bot.IsValidCreate()
if vErr != nil { if vErr != nil {
return nil, vErr return nil, vErr
@@ -391,7 +391,7 @@ func (a *App) GetBots(options *model.BotGetOptions) (model.BotList, *model.AppEr
} }
// UpdateBotActive marks a bot as active or inactive, along with its corresponding user. // UpdateBotActive marks a bot as active or inactive, along with its corresponding user.
func (a *App) UpdateBotActive(c *request.Context, botUserId string, active bool) (*model.Bot, *model.AppError) { func (a *App) UpdateBotActive(c request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError) {
user, nErr := a.Srv().Store.User().Get(context.Background(), botUserId) user, nErr := a.Srv().Store.User().Get(context.Background(), botUserId)
if nErr != nil { if nErr != nil {
var nfErr *store.ErrNotFound var nfErr *store.ErrNotFound
@@ -498,7 +498,7 @@ func (a *App) UpdateBotOwner(botUserId, newOwnerId string) (*model.Bot, *model.A
} }
// disableUserBots disables all bots owned by the given user. // disableUserBots disables all bots owned by the given user.
func (a *App) disableUserBots(c *request.Context, userID string) *model.AppError { func (a *App) disableUserBots(c request.CTX, userID string) *model.AppError {
perPage := 20 perPage := 20
for { for {
options := &model.BotGetOptions{ options := &model.BotGetOptions{
@@ -516,7 +516,7 @@ func (a *App) disableUserBots(c *request.Context, userID string) *model.AppError
for _, bot := range userBots { for _, bot := range userBots {
_, err := a.UpdateBotActive(c, bot.UserId, false) _, err := a.UpdateBotActive(c, bot.UserId, false)
if err != nil { if err != nil {
mlog.Warn("Unable to deactivate bot.", mlog.String("bot_user_id", bot.UserId), mlog.Err(err)) c.Logger().Warn("Unable to deactivate bot.", mlog.String("bot_user_id", bot.UserId), mlog.Err(err))
} }
} }
@@ -531,7 +531,7 @@ func (a *App) disableUserBots(c *request.Context, userID string) *model.AppError
return nil return nil
} }
func (a *App) notifySysadminsBotOwnerDeactivated(c *request.Context, userID string) *model.AppError { func (a *App) notifySysadminsBotOwnerDeactivated(c request.CTX, userID string) *model.AppError {
perPage := 25 perPage := 25
botOptions := &model.BotGetOptions{ botOptions := &model.BotGetOptions{
OwnerId: userID, OwnerId: userID,

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

@@ -91,17 +91,10 @@ func (a *App) JoinDefaultChannels(c request.CTX, teamID string, user *model.User
} }
} }
var err *model.AppError
for _, channelName := range a.DefaultChannelNames(c) { for _, channelName := range a.DefaultChannelNames(c) {
channel, channelErr := a.Srv().Store.Channel().GetByName(teamID, channelName, true) channel, channelErr := a.Srv().Store.Channel().GetByName(teamID, channelName, true)
if channelErr != nil { if channelErr != nil {
var nfErr *store.ErrNotFound c.Logger().Warn("No default channel with this name", mlog.String("channelName", channelName), mlog.String("teamID", teamID), mlog.Err(channelErr))
switch {
case errors.As(err, &nfErr):
err = model.NewAppError("JoinDefaultChannels", "app.channel.get_by_name.missing.app_error", nil, nfErr.Error(), http.StatusNotFound)
default:
err = model.NewAppError("JoinDefaultChannels", "app.channel.get_by_name.existing.app_error", nil, channelErr.Error(), http.StatusInternalServerError)
}
continue continue
} }
@@ -661,7 +654,7 @@ func (a *App) UpdateChannel(c request.CTX, channel *model.Channel) (*model.Chann
messageWs := model.NewWebSocketEvent(model.WebsocketEventChannelUpdated, "", channel.Id, "", nil) messageWs := model.NewWebSocketEvent(model.WebsocketEventChannelUpdated, "", channel.Id, "", nil)
channelJSON, jsonErr := json.Marshal(channel) channelJSON, jsonErr := json.Marshal(channel)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode channel to JSON", mlog.Err(jsonErr)) return nil, model.NewAppError("UpdateChannel", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
messageWs.Add("channel", string(channelJSON)) messageWs.Add("channel", string(channelJSON))
a.Publish(messageWs) a.Publish(messageWs)
@@ -1019,7 +1012,9 @@ func (a *App) PatchChannelModerationsForChannel(c request.CTX, channel *model.Ch
if err != nil { if err != nil {
return nil, err return nil, err
} }
a.sendUpdatedRoleEvent(adminRole) if appErr := a.sendUpdatedRoleEvent(adminRole); appErr != nil {
return nil, appErr
}
message := model.NewWebSocketEvent(model.WebsocketEventChannelSchemeUpdated, "", channel.Id, "", nil) message := model.NewWebSocketEvent(model.WebsocketEventChannelSchemeUpdated, "", channel.Id, "", nil)
a.Publish(message) a.Publish(message)
@@ -1285,7 +1280,7 @@ func (a *App) UpdateChannelMemberNotifyProps(c request.CTX, data map[string]stri
evt := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", member.UserId, nil) evt := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", member.UserId, nil)
memberJSON, jsonErr := json.Marshal(member) memberJSON, jsonErr := json.Marshal(member)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode channel member to JSON", mlog.Err(jsonErr)) return nil, model.NewAppError("UpdateChannelMemberNotifyProps", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
evt.Add("channelMember", string(memberJSON)) evt.Add("channelMember", string(memberJSON))
a.Publish(evt) a.Publish(evt)
@@ -1314,7 +1309,7 @@ func (a *App) updateChannelMember(c request.CTX, member *model.ChannelMember) (*
evt := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", member.UserId, nil) evt := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", member.UserId, nil)
memberJSON, jsonErr := json.Marshal(member) memberJSON, jsonErr := json.Marshal(member)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode channel member to JSON", mlog.Err(jsonErr)) return nil, model.NewAppError("updateChannelMember", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
evt.Add("channelMember", string(memberJSON)) evt.Add("channelMember", string(memberJSON))
a.Publish(evt) a.Publish(evt)
@@ -1587,7 +1582,7 @@ func (a *App) AddChannelMember(c request.CTX, userID string, channel *model.Chan
if opts.UserRequestorID == "" || userID == opts.UserRequestorID { if opts.UserRequestorID == "" || userID == opts.UserRequestorID {
if err := a.postJoinChannelMessage(c, user, channel); err != nil { if err := a.postJoinChannelMessage(c, user, channel); err != nil {
mlog.Error("Failed to post join channel message", mlog.Err(err)) return nil, err
} }
} else { } else {
a.Srv().Go(func() { a.Srv().Go(func() {
@@ -2513,11 +2508,9 @@ func (a *App) RemoveUserFromChannel(c request.CTX, userIDToRemove string, remove
return err return err
} }
} else { } else {
a.Srv().Go(func() { if err := a.postRemoveFromChannelMessage(c, removerUserId, user, channel); err != nil {
if err := a.postRemoveFromChannelMessage(c, removerUserId, user, channel); err != nil { c.Logger().Error("Failed to post user removal message", mlog.Err(err))
mlog.Error("Failed to post user removal message", mlog.Err(err)) }
}
})
} }
return nil return nil
@@ -2701,7 +2694,7 @@ func (a *App) markChannelAsUnreadFromPostCRTUnsupported(c request.CTX, postID st
if a.IsCRTEnabledForUser(c, userID) { if a.IsCRTEnabledForUser(c, userID) {
payload, jsonErr := json.Marshal(thread) payload, jsonErr := json.Marshal(thread)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode thread to JSON") return nil, model.NewAppError("MarkChannelAsUnreadFromPost", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message := model.NewWebSocketEvent(model.WebsocketEventThreadUpdated, channel.TeamId, "", userID, nil) message := model.NewWebSocketEvent(model.WebsocketEventThreadUpdated, channel.TeamId, "", userID, nil)
message.Add("thread", string(payload)) message.Add("thread", string(payload))
@@ -3268,7 +3261,7 @@ func (a *App) setChannelsMuted(c request.CTX, channelIDs []string, userID string
memberJSON, jsonErr := json.Marshal(member) memberJSON, jsonErr := json.Marshal(member)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode channel member to JSON", mlog.Err(jsonErr)) return nil, model.NewAppError("setChannelsMuted", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
evt.Add("channelMember", string(memberJSON)) evt.Add("channelMember", string(memberJSON))
@@ -3369,21 +3362,22 @@ func (a *App) forEachChannelMember(c request.CTX, channelID string, f func(model
return nil return nil
} }
func (a *App) ClearChannelMembersCache(c request.CTX, channelID string) { func (a *App) ClearChannelMembersCache(c request.CTX, channelID string) error {
clearSessionCache := func(channelMember model.ChannelMember) error { clearSessionCache := func(channelMember model.ChannelMember) error {
a.ClearSessionCacheForUser(channelMember.UserId) a.ClearSessionCacheForUser(channelMember.UserId)
message := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", channelMember.UserId, nil) message := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", channelMember.UserId, nil)
memberJSON, jsonErr := json.Marshal(channelMember) memberJSON, jsonErr := json.Marshal(channelMember)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode channel member to JSON", mlog.Err(jsonErr)) return jsonErr
} }
message.Add("channelMember", string(memberJSON)) message.Add("channelMember", string(memberJSON))
a.Publish(message) a.Publish(message)
return nil return nil
} }
if err := a.forEachChannelMember(c, channelID, clearSessionCache); err != nil { if err := a.forEachChannelMember(c, channelID, clearSessionCache); err != nil {
c.Logger().Warn("error clearing cache for channel members", mlog.String("channel_id", channelID)) return fmt.Errorf("error clearing cache for channel members: channel_id: %s, error: %v", channelID, err)
} }
return nil
} }
func (a *App) GetMemberCountsByGroup(ctx context.Context, channelID string, includeTimezones bool) ([]*model.ChannelMemberCountByGroup, *model.AppError) { func (a *App) GetMemberCountsByGroup(ctx context.Context, channelID string, includeTimezones bool) ([]*model.ChannelMemberCountByGroup, *model.AppError) {

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

@@ -151,7 +151,7 @@ func (a *App) UpdateSidebarCategories(c request.CTX, userID, teamID string, cate
updatedCategoriesJSON, jsonErr := json.Marshal(updatedCategories) updatedCategoriesJSON, jsonErr := json.Marshal(updatedCategories)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode original categories to JSON", mlog.Err(jsonErr)) return nil, model.NewAppError("UpdateSidebarCategories", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message.Add("updatedCategories", string(updatedCategoriesJSON)) message.Add("updatedCategories", string(updatedCategoriesJSON))

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

@@ -347,6 +347,33 @@ func TestJoinDefaultChannelsExperimentalDefaultChannels(t *testing.T) {
} }
} }
func TestJoinDefaultChannelsExperimentalDefaultChannelsMissing(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
basicChannel2 := th.CreateChannel(th.Context, th.BasicTeam)
defer th.App.PermanentDeleteChannel(th.Context, basicChannel2)
defaultChannelList := []string{th.BasicChannel.Name, basicChannel2.Name, "thischanneldoesnotexist", basicChannel2.Name}
th.App.Config().TeamSettings.ExperimentalDefaultChannels = defaultChannelList
user := th.CreateUser()
require.Nil(t, th.App.JoinDefaultChannels(th.Context, th.BasicTeam.Id, user, false, ""))
for _, channelName := range defaultChannelList {
if channelName == "thischanneldoesnotexist" {
continue // skip the non-existent channel
}
channel, err := th.App.GetChannelByName(th.Context, channelName, th.BasicTeam.Id, false)
require.Nil(t, err, "Expected nil, didn't receive nil")
member, err := th.App.GetChannelMember(th.Context, channel.Id, user.Id)
require.NotNil(t, member, "Expected member object, got nil")
require.Nil(t, err, "Expected nil object, didn't receive nil")
}
}
func TestCreateChannelPublicCreatesChannelMemberHistoryRecord(t *testing.T) { func TestCreateChannelPublicCreatesChannelMemberHistoryRecord(t *testing.T) {
th := Setup(t).InitBasic() th := Setup(t).InitBasic()
defer th.TearDown() defer th.TearDown()
@@ -2065,7 +2092,7 @@ func TestClearChannelMembersCache(t *testing.T) {
mockStore.On("Channel").Return(&mockChannelStore) mockStore.On("Channel").Return(&mockChannelStore)
mockStore.On("GetDBSchemaVersion").Return(1, nil) mockStore.On("GetDBSchemaVersion").Return(1, nil)
th.App.ClearChannelMembersCache(th.Context, "channelID") require.NoError(t, th.App.ClearChannelMembersCache(th.Context, "channelID"))
} }
func TestGetMemberCountsByGroup(t *testing.T) { func TestGetMemberCountsByGroup(t *testing.T) {

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

@@ -33,7 +33,7 @@ var atMentionRegexp = regexp.MustCompile(`\B@[[:alnum:]][[:alnum:]\.\-_:]*`)
type CommandProvider interface { type CommandProvider interface {
GetTrigger() string GetTrigger() string
GetCommand(a *App, T i18n.TranslateFunc) *model.Command GetCommand(a *App, T i18n.TranslateFunc) *model.Command
DoCommand(a *App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse DoCommand(a *App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse
} }
var commandProviders = make(map[string]CommandProvider) var commandProviders = make(map[string]CommandProvider)
@@ -52,7 +52,7 @@ func GetCommandProvider(name string) CommandProvider {
} }
// @openTracingParams teamID, skipSlackParsing // @openTracingParams teamID, skipSlackParsing
func (a *App) CreateCommandPost(c *request.Context, post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError) { func (a *App) CreateCommandPost(c request.CTX, post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError) {
if skipSlackParsing { if skipSlackParsing {
post.Message = response.Text post.Message = response.Text
} else { } else {
@@ -180,7 +180,7 @@ func (a *App) ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Com
} }
// @openTracingParams args // @openTracingParams args
func (a *App) ExecuteCommand(c *request.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) { func (a *App) ExecuteCommand(c request.CTX, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
trigger := "" trigger := ""
message := "" message := ""
index := strings.IndexFunc(args.Command, unicode.IsSpace) index := strings.IndexFunc(args.Command, unicode.IsSpace)
@@ -198,7 +198,7 @@ func (a *App) ExecuteCommand(c *request.Context, args *model.CommandArgs) (*mode
clientTriggerId, triggerId, appErr := model.GenerateTriggerId(args.UserId, a.AsymmetricSigningKey()) clientTriggerId, triggerId, appErr := model.GenerateTriggerId(args.UserId, a.AsymmetricSigningKey())
if appErr != nil { if appErr != nil {
mlog.Warn("error occurred in generating trigger Id for a user ", mlog.Err(appErr)) c.Logger().Warn("error occurred in generating trigger Id for a user ", mlog.Err(appErr))
} }
args.TriggerId = triggerId args.TriggerId = triggerId
@@ -235,7 +235,7 @@ func (a *App) ExecuteCommand(c *request.Context, args *model.CommandArgs) (*mode
// MentionsToTeamMembers returns all the @ mentions found in message that // MentionsToTeamMembers returns all the @ mentions found in message that
// belong to users in the specified team, linking them to their users // belong to users in the specified team, linking them to their users
func (a *App) MentionsToTeamMembers(message, teamID string) model.UserMentionMap { func (a *App) MentionsToTeamMembers(c request.CTX, message, teamID string) model.UserMentionMap {
type mentionMapItem struct { type mentionMapItem struct {
Name string Name string
Id string Id string
@@ -253,7 +253,7 @@ func (a *App) MentionsToTeamMembers(message, teamID string) model.UserMentionMap
var nfErr *store.ErrNotFound var nfErr *store.ErrNotFound
if nErr != nil && !errors.As(nErr, &nfErr) { if nErr != nil && !errors.As(nErr, &nfErr) {
mlog.Warn("Failed to retrieve user @"+mention, mlog.Err(nErr)) c.Logger().Warn("Failed to retrieve user @"+mention, mlog.Err(nErr))
return return
} }
@@ -347,7 +347,7 @@ func (a *App) MentionsToPublicChannels(c request.CTX, message, teamID string) mo
// tryExecuteBuiltInCommand attempts to run a built in command based on the given arguments. If no such command can be // tryExecuteBuiltInCommand attempts to run a built in command based on the given arguments. If no such command can be
// found, returns nil for all arguments. // found, returns nil for all arguments.
func (a *App) tryExecuteBuiltInCommand(c *request.Context, args *model.CommandArgs, trigger string, message string) (*model.Command, *model.CommandResponse) { func (a *App) tryExecuteBuiltInCommand(c request.CTX, args *model.CommandArgs, trigger string, message string) (*model.Command, *model.CommandResponse) {
provider := GetCommandProvider(trigger) provider := GetCommandProvider(trigger)
if provider == nil { if provider == nil {
return nil, nil return nil, nil
@@ -443,7 +443,7 @@ func (a *App) tryExecuteCustomCommand(c request.CTX, args *model.CommandArgs, tr
return nil, nil, nil return nil, nil, nil
} }
mlog.Debug("Executing command", mlog.String("command", trigger), mlog.String("user_id", args.UserId)) c.Logger().Debug("Executing command", mlog.String("command", trigger), mlog.String("user_id", args.UserId))
p := url.Values{} p := url.Values{}
p.Set("token", cmd.Token) p.Set("token", cmd.Token)
@@ -462,7 +462,7 @@ func (a *App) tryExecuteCustomCommand(c request.CTX, args *model.CommandArgs, tr
p.Set("trigger_id", args.TriggerId) p.Set("trigger_id", args.TriggerId)
userMentionMap := a.MentionsToTeamMembers(message, team.Id) userMentionMap := a.MentionsToTeamMembers(c, message, team.Id)
for key, values := range userMentionMap.ToURLValues() { for key, values := range userMentionMap.ToURLValues() {
p[key] = values p[key] = values
} }
@@ -536,7 +536,7 @@ func (a *App) DoCommandRequest(cmd *model.Command, p url.Values) (*model.Command
return cmd, response, nil return cmd, response, nil
} }
func (a *App) HandleCommandResponse(c *request.Context, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *model.AppError) { func (a *App) HandleCommandResponse(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *model.AppError) {
trigger := "" trigger := ""
if args.Command != "" { if args.Command != "" {
parts := strings.Split(args.Command, " ") parts := strings.Split(args.Command, " ")
@@ -570,7 +570,7 @@ func (a *App) HandleCommandResponse(c *request.Context, command *model.Command,
return response, nil return response, nil
} }
func (a *App) HandleCommandResponsePost(c *request.Context, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.Post, *model.AppError) { func (a *App) HandleCommandResponsePost(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.Post, *model.AppError) {
post := &model.Post{} post := &model.Post{}
post.ChannelId = args.ChannelId post.ChannelId = args.ChannelId
post.RootId = args.RootId post.RootId = args.RootId

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

@@ -659,7 +659,7 @@ func (p *testCommandProvider) GetCommand(a *App, T i18n.TranslateFunc) *model.Co
} }
} }
func (p *testCommandProvider) DoCommand(a *App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (p *testCommandProvider) DoCommand(a *App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
return &model.CommandResponse{ return &model.CommandResponse{
Text: "I do nothing!", Text: "I do nothing!",
ResponseType: model.CommandResponseTypeEphemeral, ResponseType: model.CommandResponseTypeEphemeral,

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

@@ -79,12 +79,12 @@ func (w *configWrapper) SaveConfig(newCfg *model.Config, sendConfigChangeCluster
} }
if w.srv.startMetrics && *w.Config().MetricsSettings.Enable { if w.srv.startMetrics && *w.Config().MetricsSettings.Enable {
if w.srv.Metrics != nil { if w.srv.GetMetrics() != nil {
w.srv.Metrics.Register() w.srv.GetMetrics().Register()
} }
w.srv.SetupMetricsServer() w.srv.platform.RestartMetrics() // TODO: remove when this moved to the platform service
} else { } else {
w.srv.StopMetricsServer() w.srv.platform.ShutdownMetrics() // TODO: remove when this moved to the platform service
} }
if w.srv.Cluster != nil { if w.srv.Cluster != nil {

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

@@ -82,7 +82,7 @@ func (a *App) CreateEmoji(sessionUserId string, emoji *model.Emoji, multiPartIma
message := model.NewWebSocketEvent(model.WebsocketEventEmojiAdded, "", "", "", nil) message := model.NewWebSocketEvent(model.WebsocketEventEmojiAdded, "", "", "", nil)
emojiJSON, jsonErr := json.Marshal(emoji) emojiJSON, jsonErr := json.Marshal(emoji)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode emoji to JSON", mlog.Err(jsonErr)) return nil, model.NewAppError("CreateEmoji", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message.Add("emoji", string(emojiJSON)) message.Add("emoji", string(emojiJSON))
a.Publish(message) a.Publish(message)

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

@@ -112,10 +112,6 @@ func RegisterLicenseInterface(f func(*Server) einterfaces.LicenseInterface) {
} }
func (s *Server) initEnterprise() { func (s *Server) initEnterprise() {
if metricsInterface != nil {
s.Metrics = metricsInterface(s)
}
if clusterInterface != nil && s.Cluster == nil { if clusterInterface != nil && s.Cluster == nil {
s.Cluster = clusterInterface(s) s.Cluster = clusterInterface(s)
} }

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

@@ -15,6 +15,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/mattermost/mattermost-server/v6/store" "github.com/mattermost/mattermost-server/v6/store"
@@ -61,7 +62,7 @@ var exportablePreferences = map[ComparablePreference]string{{
}: "EmailInterval", }: "EmailInterval",
} }
func (a *App) BulkExport(writer io.Writer, outPath string, opts model.BulkExportOpts) *model.AppError { func (a *App) BulkExport(ctx request.CTX, writer io.Writer, outPath string, opts model.BulkExportOpts) *model.AppError {
var zipWr *zip.Writer var zipWr *zip.Writer
if opts.CreateArchive { if opts.CreateArchive {
var err error var err error
@@ -74,52 +75,52 @@ func (a *App) BulkExport(writer io.Writer, outPath string, opts model.BulkExport
} }
} }
mlog.Info("Bulk export: exporting version") ctx.Logger().Info("Bulk export: exporting version")
if err := a.exportVersion(writer); err != nil { if err := a.exportVersion(writer); err != nil {
return err return err
} }
mlog.Info("Bulk export: exporting teams") ctx.Logger().Info("Bulk export: exporting teams")
teamNames, err := a.exportAllTeams(writer) teamNames, err := a.exportAllTeams(writer)
if err != nil { if err != nil {
return err return err
} }
mlog.Info("Bulk export: exporting channels") ctx.Logger().Info("Bulk export: exporting channels")
if err = a.exportAllChannels(writer, teamNames); err != nil { if err = a.exportAllChannels(writer, teamNames); err != nil {
return err return err
} }
mlog.Info("Bulk export: exporting users") ctx.Logger().Info("Bulk export: exporting users")
if err = a.exportAllUsers(writer); err != nil { if err = a.exportAllUsers(writer); err != nil {
return err return err
} }
mlog.Info("Bulk export: exporting posts") ctx.Logger().Info("Bulk export: exporting posts")
attachments, err := a.exportAllPosts(writer, opts.IncludeAttachments) attachments, err := a.exportAllPosts(ctx, writer, opts.IncludeAttachments)
if err != nil { if err != nil {
return err return err
} }
mlog.Info("Bulk export: exporting emoji") ctx.Logger().Info("Bulk export: exporting emoji")
emojiPaths, err := a.exportCustomEmoji(writer, outPath, "exported_emoji", !opts.CreateArchive) emojiPaths, err := a.exportCustomEmoji(writer, outPath, "exported_emoji", !opts.CreateArchive)
if err != nil { if err != nil {
return err return err
} }
mlog.Info("Bulk export: exporting direct channels") ctx.Logger().Info("Bulk export: exporting direct channels")
if err = a.exportAllDirectChannels(writer); err != nil { if err = a.exportAllDirectChannels(writer); err != nil {
return err return err
} }
mlog.Info("Bulk export: exporting direct posts") ctx.Logger().Info("Bulk export: exporting direct posts")
directAttachments, err := a.exportAllDirectPosts(writer, opts.IncludeAttachments) directAttachments, err := a.exportAllDirectPosts(ctx, writer, opts.IncludeAttachments)
if err != nil { if err != nil {
return err return err
} }
if opts.IncludeAttachments { if opts.IncludeAttachments {
mlog.Info("Bulk export: exporting file attachments") ctx.Logger().Info("Bulk export: exporting file attachments")
for _, attachment := range attachments { for _, attachment := range attachments {
if err := a.exportFile(outPath, *attachment.Path, zipWr); err != nil { if err := a.exportFile(outPath, *attachment.Path, zipWr); err != nil {
return err return err
@@ -383,7 +384,7 @@ func (a *App) buildUserNotifyProps(notifyProps model.StringMap) *UserNotifyProps
} }
} }
func (a *App) exportAllPosts(writer io.Writer, withAttachments bool) ([]AttachmentImportData, *model.AppError) { func (a *App) exportAllPosts(ctx request.CTX, writer io.Writer, withAttachments bool) ([]AttachmentImportData, *model.AppError) {
var attachments []AttachmentImportData var attachments []AttachmentImportData
afterId := strings.Repeat("0", 26) afterId := strings.Repeat("0", 26)
@@ -407,7 +408,7 @@ func (a *App) exportAllPosts(writer io.Writer, withAttachments bool) ([]Attachme
postLine := ImportLineForPost(post) postLine := ImportLineForPost(post)
replies, replyAttachments, err := a.buildPostReplies(post.Id, withAttachments) replies, replyAttachments, err := a.buildPostReplies(ctx, post.Id, withAttachments)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -419,7 +420,7 @@ func (a *App) exportAllPosts(writer io.Writer, withAttachments bool) ([]Attachme
postLine.Post.Replies = &replies postLine.Post.Replies = &replies
postLine.Post.Reactions = &[]ReactionImportData{} postLine.Post.Reactions = &[]ReactionImportData{}
if post.HasReactions { if post.HasReactions {
postLine.Post.Reactions, err = a.BuildPostReactions(post.Id) postLine.Post.Reactions, err = a.BuildPostReactions(ctx, post.Id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -444,7 +445,7 @@ func (a *App) exportAllPosts(writer io.Writer, withAttachments bool) ([]Attachme
} }
} }
func (a *App) buildPostReplies(postID string, withAttachments bool) ([]ReplyImportData, []AttachmentImportData, *model.AppError) { func (a *App) buildPostReplies(ctx request.CTX, postID string, withAttachments bool) ([]ReplyImportData, []AttachmentImportData, *model.AppError) {
var replies []ReplyImportData var replies []ReplyImportData
var attachments []AttachmentImportData var attachments []AttachmentImportData
@@ -457,7 +458,7 @@ func (a *App) buildPostReplies(postID string, withAttachments bool) ([]ReplyImpo
replyImportObject := ImportReplyFromPost(reply) replyImportObject := ImportReplyFromPost(reply)
if reply.HasReactions { if reply.HasReactions {
var appErr *model.AppError var appErr *model.AppError
replyImportObject.Reactions, appErr = a.BuildPostReactions(reply.Id) replyImportObject.Reactions, appErr = a.BuildPostReactions(ctx, reply.Id)
if appErr != nil { if appErr != nil {
return nil, nil, appErr return nil, nil, appErr
} }
@@ -479,7 +480,7 @@ func (a *App) buildPostReplies(postID string, withAttachments bool) ([]ReplyImpo
return replies, attachments, nil return replies, attachments, nil
} }
func (a *App) BuildPostReactions(postID string) (*[]ReactionImportData, *model.AppError) { func (a *App) BuildPostReactions(ctx request.CTX, postID string) (*[]ReactionImportData, *model.AppError) {
var reactionsOfPost []ReactionImportData var reactionsOfPost []ReactionImportData
reactions, nErr := a.Srv().Store.Reaction().GetForPost(postID, true) reactions, nErr := a.Srv().Store.Reaction().GetForPost(postID, true)
@@ -492,7 +493,7 @@ func (a *App) BuildPostReactions(postID string) (*[]ReactionImportData, *model.A
if err != nil { if err != nil {
var nfErr *store.ErrNotFound var nfErr *store.ErrNotFound
if errors.As(err, &nfErr) { // this is a valid case, the user that reacted might've been deleted by now if errors.As(err, &nfErr) { // this is a valid case, the user that reacted might've been deleted by now
mlog.Info("Skipping reactions by user since the entity doesn't exist anymore", mlog.String("user_id", reaction.UserId)) ctx.Logger().Info("Skipping reactions by user since the entity doesn't exist anymore", mlog.String("user_id", reaction.UserId))
continue continue
} }
return nil, model.NewAppError("BuildPostReactions", "app.user.get.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("BuildPostReactions", "app.user.get.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -634,7 +635,7 @@ func (a *App) exportAllDirectChannels(writer io.Writer) *model.AppError {
return nil return nil
} }
func (a *App) exportAllDirectPosts(writer io.Writer, withAttachments bool) ([]AttachmentImportData, *model.AppError) { func (a *App) exportAllDirectPosts(ctx request.CTX, writer io.Writer, withAttachments bool) ([]AttachmentImportData, *model.AppError) {
var attachments []AttachmentImportData var attachments []AttachmentImportData
afterId := strings.Repeat("0", 26) afterId := strings.Repeat("0", 26)
for { for {
@@ -670,7 +671,7 @@ func (a *App) exportAllDirectPosts(writer io.Writer, withAttachments bool) ([]At
} }
// Do the Replies. // Do the Replies.
replies, replyAttachments, err := a.buildPostReplies(post.Id, withAttachments) replies, replyAttachments, err := a.buildPostReplies(ctx, post.Id, withAttachments)
if err != nil { if err != nil {
return nil, err return nil, err
} }

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

@@ -42,7 +42,7 @@ func TestReactionsOfPost(t *testing.T) {
th.App.SaveReactionForPost(th.Context, &reactionObject) th.App.SaveReactionForPost(th.Context, &reactionObject)
th.App.SaveReactionForPost(th.Context, &reactionObjectDeleted) th.App.SaveReactionForPost(th.Context, &reactionObjectDeleted)
reactionsOfPost, err := th.App.BuildPostReactions(post.Id) reactionsOfPost, err := th.App.BuildPostReactions(th.Context, post.Id)
require.Nil(t, err) require.Nil(t, err)
assert.Equal(t, reactionObject.EmojiName, *(*reactionsOfPost)[0].EmojiName) assert.Equal(t, reactionObject.EmojiName, *(*reactionsOfPost)[0].EmojiName)
@@ -179,7 +179,7 @@ func TestExportAllUsers(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
var b bytes.Buffer var b bytes.Buffer
err = th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) err = th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, err) require.Nil(t, err)
th2 := Setup(t) th2 := Setup(t)
@@ -227,7 +227,7 @@ func TestExportDMChannel(t *testing.T) {
th1.CreateDmChannel(th1.BasicUser2) th1.CreateDmChannel(th1.BasicUser2)
var b bytes.Buffer var b bytes.Buffer
err := th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) err := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, err) require.Nil(t, err)
channels, nErr := th1.App.Srv().Store.Channel().GetAllDirectChannelsForExportAfter(1000, "00000000") channels, nErr := th1.App.Srv().Store.Channel().GetAllDirectChannelsForExportAfter(1000, "00000000")
@@ -268,7 +268,7 @@ func TestExportDMChannel(t *testing.T) {
th1.App.PermanentDeleteUser(th1.Context, th1.BasicUser) th1.App.PermanentDeleteUser(th1.Context, th1.BasicUser)
var b bytes.Buffer var b bytes.Buffer
err := th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) err := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, err) require.Nil(t, err)
th2 := Setup(t).InitBasic() th2 := Setup(t).InitBasic()
@@ -292,7 +292,7 @@ func TestExportDMChannelToSelf(t *testing.T) {
th1.CreateDmChannel(th1.BasicUser) th1.CreateDmChannel(th1.BasicUser)
var b bytes.Buffer var b bytes.Buffer
err := th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) err := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, err) require.Nil(t, err)
channels, nErr := th1.App.Srv().Store.Channel().GetAllDirectChannelsForExportAfter(1000, "00000000") channels, nErr := th1.App.Srv().Store.Channel().GetAllDirectChannelsForExportAfter(1000, "00000000")
@@ -330,7 +330,7 @@ func TestExportGMChannel(t *testing.T) {
th1.CreateGroupChannel(th1.Context, user1, user2) th1.CreateGroupChannel(th1.Context, user1, user2)
var b bytes.Buffer var b bytes.Buffer
err := th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) err := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, err) require.Nil(t, err)
channels, nErr := th1.App.Srv().Store.Channel().GetAllDirectChannelsForExportAfter(1000, "00000000") channels, nErr := th1.App.Srv().Store.Channel().GetAllDirectChannelsForExportAfter(1000, "00000000")
@@ -362,7 +362,7 @@ func TestExportGMandDMChannels(t *testing.T) {
th1.CreateGroupChannel(th1.Context, user1, user2) th1.CreateGroupChannel(th1.Context, user1, user2)
var b bytes.Buffer var b bytes.Buffer
err := th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) err := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, err) require.Nil(t, err)
channels, nErr := th1.App.Srv().Store.Channel().GetAllDirectChannelsForExportAfter(1000, "00000000") channels, nErr := th1.App.Srv().Store.Channel().GetAllDirectChannelsForExportAfter(1000, "00000000")
@@ -445,7 +445,7 @@ func TestExportDMandGMPost(t *testing.T) {
assert.Equal(t, 4, len(posts)) assert.Equal(t, 4, len(posts))
var b bytes.Buffer var b bytes.Buffer
appErr := th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) appErr := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, appErr) require.Nil(t, appErr)
th1.TearDown() th1.TearDown()
@@ -520,7 +520,7 @@ func TestExportPostWithProps(t *testing.T) {
require.NotEmpty(t, posts[1].Props) require.NotEmpty(t, posts[1].Props)
var b bytes.Buffer var b bytes.Buffer
appErr := th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) appErr := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, appErr) require.Nil(t, appErr)
th1.TearDown() th1.TearDown()
@@ -558,7 +558,7 @@ func TestExportDMPostWithSelf(t *testing.T) {
th1.CreatePost(dmChannel) th1.CreatePost(dmChannel)
var b bytes.Buffer var b bytes.Buffer
err := th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) err := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, err) require.Nil(t, err)
posts, nErr := th1.App.Srv().Store.Post().GetDirectPostParentsForExportAfter(1000, "0000000") posts, nErr := th1.App.Srv().Store.Post().GetDirectPostParentsForExportAfter(1000, "0000000")
@@ -626,7 +626,7 @@ func TestBulkExport(t *testing.T) {
IncludeAttachments: true, IncludeAttachments: true,
CreateArchive: true, CreateArchive: true,
} }
appErr = th.App.BulkExport(exportFile, dir, opts) appErr = th.App.BulkExport(th.Context, exportFile, dir, opts)
require.Nil(t, appErr) require.Nil(t, appErr)
th.TearDown() th.TearDown()
@@ -663,7 +663,7 @@ func TestBuildPostReplies(t *testing.T) {
} }
t.Run("basic post", func(t *testing.T) { t.Run("basic post", func(t *testing.T) {
data, attachments, err := th.App.buildPostReplies(th.BasicPost.Id, true) data, attachments, err := th.App.buildPostReplies(th.Context, th.BasicPost.Id, true)
require.Nil(t, err) require.Nil(t, err)
require.Empty(t, data) require.Empty(t, data)
require.Empty(t, attachments) require.Empty(t, attachments)
@@ -671,7 +671,7 @@ func TestBuildPostReplies(t *testing.T) {
t.Run("root post with attachments and no replies", func(t *testing.T) { t.Run("root post with attachments and no replies", func(t *testing.T) {
post := createPostWithAttachments(th, 5, "") post := createPostWithAttachments(th, 5, "")
data, attachments, err := th.App.buildPostReplies(post.Id, true) data, attachments, err := th.App.buildPostReplies(th.Context, post.Id, true)
require.Nil(t, err) require.Nil(t, err)
require.Empty(t, data) require.Empty(t, data)
require.Empty(t, attachments) require.Empty(t, attachments)
@@ -680,7 +680,7 @@ func TestBuildPostReplies(t *testing.T) {
t.Run("root post with attachments and a reply", func(t *testing.T) { t.Run("root post with attachments and a reply", func(t *testing.T) {
post := createPostWithAttachments(th, 5, "") post := createPostWithAttachments(th, 5, "")
createPostWithAttachments(th, 0, post.Id) createPostWithAttachments(th, 0, post.Id)
data, attachments, err := th.App.buildPostReplies(post.Id, true) data, attachments, err := th.App.buildPostReplies(th.Context, post.Id, true)
require.Nil(t, err) require.Nil(t, err)
require.Len(t, data, 1) require.Len(t, data, 1)
require.Empty(t, attachments) require.Empty(t, attachments)
@@ -690,7 +690,7 @@ func TestBuildPostReplies(t *testing.T) {
post := createPostWithAttachments(th, 5, "") post := createPostWithAttachments(th, 5, "")
reply1 := createPostWithAttachments(th, 2, post.Id) reply1 := createPostWithAttachments(th, 2, post.Id)
reply2 := createPostWithAttachments(th, 3, post.Id) reply2 := createPostWithAttachments(th, 3, post.Id)
data, attachments, err := th.App.buildPostReplies(post.Id, true) data, attachments, err := th.App.buildPostReplies(th.Context, post.Id, true)
require.Nil(t, err) require.Nil(t, err)
require.Len(t, data, 2) require.Len(t, data, 2)
require.Len(t, attachments, 5) require.Len(t, attachments, 5)
@@ -717,7 +717,7 @@ func TestExportDeletedTeams(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
var b bytes.Buffer var b bytes.Buffer
err = th1.App.BulkExport(&b, "somePath", model.BulkExportOpts{}) err = th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
require.Nil(t, err) require.Nil(t, err)
th2 := Setup(t) th2 := Setup(t)

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

@@ -453,7 +453,7 @@ func GeneratePublicLinkHash(fileID, salt string) string {
} }
// UploadFile uploads a single file in form of a completely constructed byte array for a channel. // UploadFile uploads a single file in form of a completely constructed byte array for a channel.
func (a *App) UploadFile(c *request.Context, data []byte, channelID string, filename string) (*model.FileInfo, *model.AppError) { func (a *App) UploadFile(c request.CTX, data []byte, channelID string, filename string) (*model.FileInfo, *model.AppError) {
_, err := a.GetChannel(c, channelID) _, err := a.GetChannel(c, channelID)
if err != nil && channelID != "" { if err != nil && channelID != "" {
return nil, model.NewAppError("UploadFile", "api.file.upload_file.incorrect_channelId.app_error", return nil, model.NewAppError("UploadFile", "api.file.upload_file.incorrect_channelId.app_error",
@@ -853,7 +853,7 @@ func (t UploadFileTask) newAppError(id string, httpStatus int, extra ...any) *mo
return model.NewAppError("uploadFileTask", id, params, "", httpStatus) return model.NewAppError("uploadFileTask", id, params, "", httpStatus)
} }
func (a *App) DoUploadFileExpectModification(c *request.Context, now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, []byte, *model.AppError) { func (a *App) DoUploadFileExpectModification(c request.CTX, now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, []byte, *model.AppError) {
filename := filepath.Base(rawFilename) filename := filepath.Base(rawFilename)
teamID := filepath.Base(rawTeamId) teamID := filepath.Base(rawTeamId)
channelID := filepath.Base(rawChannelId) channelID := filepath.Base(rawChannelId)

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

@@ -9,7 +9,6 @@ import (
"net/http" "net/http"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/mattermost/mattermost-server/v6/store" "github.com/mattermost/mattermost-server/v6/store"
) )
@@ -139,7 +138,7 @@ func (a *App) CreateGroupWithUserIds(group *model.GroupWithUserIds) (*model.Grou
case errors.As(err, &invErr): case errors.As(err, &invErr):
return nil, model.NewAppError("CreateGroupWithUserIds", "app.group.id.app_error", nil, invErr.Error(), http.StatusBadRequest) return nil, model.NewAppError("CreateGroupWithUserIds", "app.group.id.app_error", nil, invErr.Error(), http.StatusBadRequest)
case errors.As(err, &dupKey): case errors.As(err, &dupKey):
return nil, model.NewAppError("CreateGroup", "app.custom_group.unique_name", nil, dupKey.Error(), http.StatusBadRequest) return nil, model.NewAppError("CreateGroupWithUserIds", "app.custom_group.unique_name", nil, dupKey.Error(), http.StatusBadRequest)
default: default:
return nil, model.NewAppError("CreateGroupWithUserIds", "app.insert_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("CreateGroupWithUserIds", "app.insert_error", nil, err.Error(), http.StatusInternalServerError)
} }
@@ -153,7 +152,7 @@ func (a *App) CreateGroupWithUserIds(group *model.GroupWithUserIds) (*model.Grou
group.MemberCount = model.NewInt(int(count)) group.MemberCount = model.NewInt(int(count))
groupJSON, jsonErr := json.Marshal(newGroup) groupJSON, jsonErr := json.Marshal(newGroup)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode group to JSON", mlog.Err(jsonErr)) return nil, model.NewAppError("CreateGroupWithUserIds", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
messageWs.Add("group", string(groupJSON)) messageWs.Add("group", string(groupJSON))
a.Publish(messageWs) a.Publish(messageWs)
@@ -172,13 +171,13 @@ func (a *App) UpdateGroup(group *model.Group) (*model.Group, *model.AppError) {
if err == nil { if err == nil {
count, countErr := a.Srv().Store.Group().GetMemberCount(updatedGroup.Id) count, countErr := a.Srv().Store.Group().GetMemberCount(updatedGroup.Id)
if countErr != nil { if countErr != nil {
return nil, model.NewAppError("CreateGroupWithUserIds", "app.group.id.app_error", nil, countErr.Error(), http.StatusBadRequest) return nil, model.NewAppError("UpdateGroup", "app.group.id.app_error", nil, countErr.Error(), http.StatusBadRequest)
} }
updatedGroup.MemberCount = model.NewInt(int(count)) updatedGroup.MemberCount = model.NewInt(int(count))
messageWs := model.NewWebSocketEvent(model.WebsocketEventReceivedGroup, "", "", "", nil) messageWs := model.NewWebSocketEvent(model.WebsocketEventReceivedGroup, "", "", "", nil)
groupJSON, jsonErr := json.Marshal(updatedGroup) groupJSON, jsonErr := json.Marshal(updatedGroup)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode group to JSON", mlog.Err(jsonErr)) return nil, model.NewAppError("UpdateGroup", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
messageWs.Add("group", string(groupJSON)) messageWs.Add("group", string(groupJSON))
a.Publish(messageWs) a.Publish(messageWs)
@@ -272,7 +271,9 @@ func (a *App) UpsertGroupMember(groupID string, userID string) (*model.GroupMemb
} }
} }
a.publishGroupMemberEvent(model.WebsocketEventGroupMemberAdd, groupMember) if appErr := a.publishGroupMemberEvent(model.WebsocketEventGroupMemberAdd, groupMember); appErr != nil {
return nil, appErr
}
return groupMember, nil return groupMember, nil
} }
@@ -289,7 +290,9 @@ func (a *App) DeleteGroupMember(groupID string, userID string) (*model.GroupMemb
} }
} }
a.publishGroupMemberEvent(model.WebsocketEventGroupMemberDelete, groupMember) if appErr := a.publishGroupMemberEvent(model.WebsocketEventGroupMemberDelete, groupMember); appErr != nil {
return nil, appErr
}
return groupMember, nil return groupMember, nil
} }
@@ -743,7 +746,9 @@ func (a *App) UpsertGroupMembers(groupID string, userIDs []string) ([]*model.Gro
} }
for _, groupMember := range members { for _, groupMember := range members {
a.publishGroupMemberEvent(model.WebsocketEventGroupMemberAdd, groupMember) if appErr := a.publishGroupMemberEvent(model.WebsocketEventGroupMemberAdd, groupMember); appErr != nil {
return nil, appErr
}
} }
return members, nil return members, nil
@@ -765,18 +770,21 @@ func (a *App) DeleteGroupMembers(groupID string, userIDs []string) ([]*model.Gro
} }
for _, groupMember := range members { for _, groupMember := range members {
a.publishGroupMemberEvent(model.WebsocketEventGroupMemberDelete, groupMember) if appErr := a.publishGroupMemberEvent(model.WebsocketEventGroupMemberDelete, groupMember); appErr != nil {
return nil, appErr
}
} }
return members, nil return members, nil
} }
func (a *App) publishGroupMemberEvent(eventName string, groupMember *model.GroupMember) { func (a *App) publishGroupMemberEvent(eventName string, groupMember *model.GroupMember) *model.AppError {
messageWs := model.NewWebSocketEvent(eventName, "", "", groupMember.UserId, nil) messageWs := model.NewWebSocketEvent(eventName, "", "", groupMember.UserId, nil)
groupMemberJSON, jsonErr := json.Marshal(groupMember) groupMemberJSON, jsonErr := json.Marshal(groupMember)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("failed to encode group member to JSON", mlog.Err(jsonErr)) return model.NewAppError("publishGroupMemberEvent", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
messageWs.Add("group_member", string(groupMemberJSON)) messageWs.Add("group_member", string(groupMemberJSON))
a.Publish(messageWs) a.Publish(messageWs)
return nil
} }

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

@@ -70,7 +70,7 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
if includeCacheLayer { if includeCacheLayer {
// Adds the cache layer to the test store // Adds the cache layer to the test store
options = append(options, StoreOverride(func(s *Server) store.Store { options = append(options, StoreOverride(func(s *Server) store.Store {
lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.GetMetrics(), s.Cluster, s.CacheProvider)
if err2 != nil { if err2 != nil {
panic(err2) panic(err2)
} }

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

@@ -521,7 +521,7 @@ func (a *App) importUser(c request.CTX, data *UserImportData, dryRun bool) *mode
pref := model.Preference{UserId: savedUser.Id, Category: model.PreferenceCategoryTutorialSteps, Name: savedUser.Id, Value: "0"} pref := model.Preference{UserId: savedUser.Id, Category: model.PreferenceCategoryTutorialSteps, Name: savedUser.Id, Value: "0"}
if err := a.Srv().Store.Preference().Save(model.Preferences{pref}); err != nil { if err := a.Srv().Store.Preference().Save(model.Preferences{pref}); err != nil {
mlog.Warn("Encountered error saving tutorial preference", mlog.Err(err)) c.Logger().Warn("Encountered error saving tutorial preference", mlog.Err(err))
} }
} else { } else {
@@ -584,14 +584,14 @@ func (a *App) importUser(c request.CTX, data *UserImportData, dryRun bool) *mode
} }
if err != nil { if err != nil {
mlog.Warn("Unable to open the profile image.", mlog.Err(err)) c.Logger().Warn("Unable to open the profile image.", mlog.Err(err))
} else { } else {
defer file.Close() defer file.Close()
if limitErr := checkImageLimits(file, *a.Config().FileSettings.MaxImageResolution); limitErr != nil { if limitErr := checkImageLimits(file, *a.Config().FileSettings.MaxImageResolution); limitErr != nil {
return model.NewAppError("SetProfileImage", "api.user.upload_profile_user.check_image_limits.app_error", nil, "", http.StatusBadRequest) return model.NewAppError("SetProfileImage", "api.user.upload_profile_user.check_image_limits.app_error", nil, "", http.StatusBadRequest)
} }
if err := a.SetProfileImageFromFile(c, savedUser.Id, file); err != nil { if err := a.SetProfileImageFromFile(c, savedUser.Id, file); err != nil {
mlog.Warn("Unable to set the profile image from a file.", mlog.Err(err)) c.Logger().Warn("Unable to set the profile image from a file.", mlog.Err(err))
} }
} }
} }
@@ -1137,7 +1137,7 @@ func (a *App) importReplies(c *request.Context, data []ReplyImportData, post *mo
reply.Message = *replyData.Message reply.Message = *replyData.Message
reply.CreateAt = *replyData.CreateAt reply.CreateAt = *replyData.CreateAt
if reply.CreateAt < post.CreateAt { if reply.CreateAt < post.CreateAt {
mlog.Warn("Reply CreateAt is before parent post CreateAt, setting it to parent post CreateAt", mlog.Int64("reply_create_at", reply.CreateAt), mlog.Int64("parent_create_at", post.CreateAt)) c.Logger().Warn("Reply CreateAt is before parent post CreateAt, setting it to parent post CreateAt", mlog.Int64("reply_create_at", reply.CreateAt), mlog.Int64("parent_create_at", post.CreateAt))
reply.CreateAt = post.CreateAt reply.CreateAt = post.CreateAt
} }
if replyData.Type != nil { if replyData.Type != nil {

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

@@ -71,10 +71,6 @@ func (w *licenseWrapper) RequestTrialLicense(requesterID string, users int, term
} }
} }
if *w.srv.Config().ServiceSettings.SiteURL == "" {
return model.NewAppError("RequestTrialLicense", "api.license.request_trial_license.no-site-url.app_error", nil, "", http.StatusBadRequest)
}
trialLicenseRequest := &model.TrialLicenseRequest{ trialLicenseRequest := &model.TrialLicenseRequest{
ServerID: w.srv.TelemetryId(), ServerID: w.srv.TelemetryId(),
Name: requester.GetDisplayName(model.ShowFullName), Name: requester.GetDisplayName(model.ShowFullName),

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

@@ -383,7 +383,7 @@ func (a *OpenTracingAppLayer) AddStatusCacheSkipClusterSend(status *model.Status
a.app.AddStatusCacheSkipClusterSend(status) a.app.AddStatusCacheSkipClusterSend(status)
} }
func (a *OpenTracingAppLayer) AddTeamMember(c *request.Context, teamID string, userID string) (*model.TeamMember, *model.AppError) { func (a *OpenTracingAppLayer) AddTeamMember(c request.CTX, teamID string, userID string) (*model.TeamMember, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddTeamMember") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddTeamMember")
@@ -515,7 +515,7 @@ func (a *OpenTracingAppLayer) AddUserToChannel(c request.CTX, user *model.User,
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) AddUserToTeam(c *request.Context, teamID string, userID string, userRequestorId string) (*model.Team, *model.TeamMember, *model.AppError) { func (a *OpenTracingAppLayer) AddUserToTeam(c request.CTX, teamID string, userID string, userRequestorId string) (*model.Team, *model.TeamMember, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddUserToTeam") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddUserToTeam")
@@ -951,7 +951,7 @@ func (a *OpenTracingAppLayer) BroadcastStatus(status *model.Status) {
a.app.BroadcastStatus(status) a.app.BroadcastStatus(status)
} }
func (a *OpenTracingAppLayer) BuildPostReactions(postID string) (*[]app.ReactionImportData, *model.AppError) { func (a *OpenTracingAppLayer) BuildPostReactions(ctx request.CTX, postID string) (*[]app.ReactionImportData, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.BuildPostReactions") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.BuildPostReactions")
@@ -963,7 +963,7 @@ func (a *OpenTracingAppLayer) BuildPostReactions(postID string) (*[]app.Reaction
}() }()
defer span.Finish() defer span.Finish()
resultVar0, resultVar1 := a.app.BuildPostReactions(postID) resultVar0, resultVar1 := a.app.BuildPostReactions(ctx, postID)
if resultVar1 != nil { if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1)) span.LogFields(spanlog.Error(resultVar1))
@@ -1017,7 +1017,7 @@ func (a *OpenTracingAppLayer) BuildSamlMetadataObject(idpMetadata []byte) (*mode
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) BulkExport(writer io.Writer, outPath string, opts model.BulkExportOpts) *model.AppError { func (a *OpenTracingAppLayer) BulkExport(ctx request.CTX, writer io.Writer, outPath string, opts model.BulkExportOpts) *model.AppError {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.BulkExport") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.BulkExport")
@@ -1029,7 +1029,7 @@ func (a *OpenTracingAppLayer) BulkExport(writer io.Writer, outPath string, opts
}() }()
defer span.Finish() defer span.Finish()
resultVar0 := a.app.BulkExport(writer, outPath, opts) resultVar0 := a.app.BulkExport(ctx, writer, outPath, opts)
if resultVar0 != nil { if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0)) span.LogFields(spanlog.Error(resultVar0))
@@ -1469,7 +1469,7 @@ func (a *OpenTracingAppLayer) CheckWebConn(userID string, connectionID string) *
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) ClearChannelMembersCache(c request.CTX, channelID string) { func (a *OpenTracingAppLayer) ClearChannelMembersCache(c request.CTX, channelID string) error {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ClearChannelMembersCache") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ClearChannelMembersCache")
@@ -1481,7 +1481,14 @@ func (a *OpenTracingAppLayer) ClearChannelMembersCache(c request.CTX, channelID
}() }()
defer span.Finish() defer span.Finish()
a.app.ClearChannelMembersCache(c, channelID) resultVar0 := a.app.ClearChannelMembersCache(c, channelID)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
} }
func (a *OpenTracingAppLayer) ClearLatestVersionCache() { func (a *OpenTracingAppLayer) ClearLatestVersionCache() {
@@ -1559,7 +1566,7 @@ func (a *OpenTracingAppLayer) ClearSessionCacheForUserSkipClusterSend(userID str
a.app.ClearSessionCacheForUserSkipClusterSend(userID) a.app.ClearSessionCacheForUserSkipClusterSend(userID)
} }
func (a *OpenTracingAppLayer) ClearTeamMembersCache(teamID string) { func (a *OpenTracingAppLayer) ClearTeamMembersCache(teamID string) error {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ClearTeamMembersCache") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ClearTeamMembersCache")
@@ -1571,7 +1578,14 @@ func (a *OpenTracingAppLayer) ClearTeamMembersCache(teamID string) {
}() }()
defer span.Finish() defer span.Finish()
a.app.ClearTeamMembersCache(teamID) resultVar0 := a.app.ClearTeamMembersCache(teamID)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
} }
func (a *OpenTracingAppLayer) ClientConfig() map[string]string { func (a *OpenTracingAppLayer) ClientConfig() map[string]string {
@@ -1857,7 +1871,7 @@ func (a *OpenTracingAppLayer) CopyFileInfos(userID string, fileIDs []string) ([]
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) CreateBot(c *request.Context, bot *model.Bot) (*model.Bot, *model.AppError) { func (a *OpenTracingAppLayer) CreateBot(c request.CTX, bot *model.Bot) (*model.Bot, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateBot") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateBot")
@@ -1967,7 +1981,7 @@ func (a *OpenTracingAppLayer) CreateCommand(cmd *model.Command) (*model.Command,
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) CreateCommandPost(c *request.Context, post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError) { func (a *OpenTracingAppLayer) CreateCommandPost(c request.CTX, post *model.Post, teamID string, response *model.CommandResponse, skipSlackParsing bool) (*model.Post, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateCommandPost") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateCommandPost")
@@ -2323,7 +2337,7 @@ func (a *OpenTracingAppLayer) CreatePost(c request.CTX, post *model.Post, channe
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) CreatePostAsUser(c *request.Context, post *model.Post, currentSessionId string, setOnline bool) (*model.Post, *model.AppError) { func (a *OpenTracingAppLayer) CreatePostAsUser(c request.CTX, post *model.Post, currentSessionId string, setOnline bool) (*model.Post, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreatePostAsUser") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreatePostAsUser")
@@ -3838,7 +3852,7 @@ func (a *OpenTracingAppLayer) DoUploadFile(c *request.Context, now time.Time, ra
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) DoUploadFileExpectModification(c *request.Context, now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, []byte, *model.AppError) { func (a *OpenTracingAppLayer) DoUploadFileExpectModification(c request.CTX, now time.Time, rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, []byte, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.DoUploadFileExpectModification") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.DoUploadFileExpectModification")
@@ -3948,7 +3962,7 @@ func (a *OpenTracingAppLayer) EnableUserAccessToken(token *model.UserAccessToken
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) EnsureBot(c *request.Context, productID string, bot *model.Bot) (string, error) { func (a *OpenTracingAppLayer) EnsureBot(c request.CTX, productID string, bot *model.Bot) (string, error) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.EnsureBot") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.EnsureBot")
@@ -3987,7 +4001,7 @@ func (a *OpenTracingAppLayer) EnvironmentConfig(filter func(reflect.StructField)
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) ExecuteCommand(c *request.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) { func (a *OpenTracingAppLayer) ExecuteCommand(c request.CTX, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ExecuteCommand") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ExecuteCommand")
@@ -10997,7 +11011,7 @@ func (a *OpenTracingAppLayer) Handle404(w http.ResponseWriter, r *http.Request)
a.app.Handle404(w, r) a.app.Handle404(w, r)
} }
func (a *OpenTracingAppLayer) HandleCommandResponse(c *request.Context, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *model.AppError) { func (a *OpenTracingAppLayer) HandleCommandResponse(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.HandleCommandResponse") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.HandleCommandResponse")
@@ -11019,7 +11033,7 @@ func (a *OpenTracingAppLayer) HandleCommandResponse(c *request.Context, command
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) HandleCommandResponsePost(c *request.Context, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.Post, *model.AppError) { func (a *OpenTracingAppLayer) HandleCommandResponsePost(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.Post, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.HandleCommandResponsePost") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.HandleCommandResponsePost")
@@ -11753,7 +11767,7 @@ func (a *OpenTracingAppLayer) LeaveChannel(c request.CTX, channelID string, user
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) LeaveTeam(c *request.Context, team *model.Team, user *model.User, requestorId string) *model.AppError { func (a *OpenTracingAppLayer) LeaveTeam(c request.CTX, team *model.Team, user *model.User, requestorId string) *model.AppError {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.LeaveTeam") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.LeaveTeam")
@@ -12173,7 +12187,7 @@ func (a *OpenTracingAppLayer) MentionsToPublicChannels(c request.CTX, message st
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) MentionsToTeamMembers(message string, teamID string) model.UserMentionMap { func (a *OpenTracingAppLayer) MentionsToTeamMembers(c request.CTX, message string, teamID string) model.UserMentionMap {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.MentionsToTeamMembers") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.MentionsToTeamMembers")
@@ -12185,7 +12199,7 @@ func (a *OpenTracingAppLayer) MentionsToTeamMembers(message string, teamID strin
}() }()
defer span.Finish() defer span.Finish()
resultVar0 := a.app.MentionsToTeamMembers(message, teamID) resultVar0 := a.app.MentionsToTeamMembers(c, message, teamID)
return resultVar0 return resultVar0
} }
@@ -13708,7 +13722,7 @@ func (a *OpenTracingAppLayer) RemoveUserFromChannel(c request.CTX, userIDToRemov
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) RemoveUserFromTeam(c *request.Context, teamID string, userID string, requestorId string) *model.AppError { func (a *OpenTracingAppLayer) RemoveUserFromTeam(c request.CTX, teamID string, userID string, requestorId string) *model.AppError {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveUserFromTeam") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveUserFromTeam")
@@ -16175,7 +16189,7 @@ func (a *OpenTracingAppLayer) SyncPlugins() *model.AppError {
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) SyncRolesAndMembership(c *request.Context, syncableID string, syncableType model.GroupSyncableType, includeRemovedMembers bool) { func (a *OpenTracingAppLayer) SyncRolesAndMembership(c request.CTX, syncableID string, syncableType model.GroupSyncableType, includeRemovedMembers bool) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SyncRolesAndMembership") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SyncRolesAndMembership")
@@ -16496,7 +16510,7 @@ func (a *OpenTracingAppLayer) UnregisterPluginCommand(pluginID string, teamID st
a.app.UnregisterPluginCommand(pluginID, teamID, trigger) a.app.UnregisterPluginCommand(pluginID, teamID, trigger)
} }
func (a *OpenTracingAppLayer) UpdateActive(c *request.Context, user *model.User, active bool) (*model.User, *model.AppError) { func (a *OpenTracingAppLayer) UpdateActive(c request.CTX, user *model.User, active bool) (*model.User, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateActive") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateActive")
@@ -16518,7 +16532,7 @@ func (a *OpenTracingAppLayer) UpdateActive(c *request.Context, user *model.User,
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) UpdateBotActive(c *request.Context, botUserId string, active bool) (*model.Bot, *model.AppError) { func (a *OpenTracingAppLayer) UpdateBotActive(c request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateBotActive") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateBotActive")
@@ -17585,7 +17599,7 @@ func (a *OpenTracingAppLayer) UpdateUser(c request.CTX, user *model.User, sendNo
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) UpdateUserActive(c *request.Context, userID string, active bool) *model.AppError { func (a *OpenTracingAppLayer) UpdateUserActive(c request.CTX, userID string, active bool) *model.AppError {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateUserActive") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateUserActive")
@@ -17791,7 +17805,7 @@ func (a *OpenTracingAppLayer) UploadEmojiImage(id string, imageData *multipart.F
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) UploadFile(c *request.Context, data []byte, channelID string, filename string) (*model.FileInfo, *model.AppError) { func (a *OpenTracingAppLayer) UploadFile(c request.CTX, data []byte, channelID string, filename string) (*model.FileInfo, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UploadFile") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UploadFile")

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

@@ -3,14 +3,34 @@
package platform package platform
import (
"errors"
"github.com/mattermost/mattermost-server/v6/config"
"github.com/mattermost/mattermost-server/v6/einterfaces"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
// ServiceConfig is used to initialize the PlatformService. // ServiceConfig is used to initialize the PlatformService.
// The mandatory fields will be checked during the initialization of the service. // The mandatory fields will be checked during the initialization of the service.
type ServiceConfig struct { type ServiceConfig struct {
// Mandatory fields // Mandatory fields
ConfigStore *config.Store
Logger *mlog.Logger
StartMetrics bool // TODO: find an elegant way to start/stop metrics server by default
// Optional fields // Optional fields
Metrics einterfaces.MetricsInterface
Cluster einterfaces.ClusterInterface
} }
func (c *ServiceConfig) validate() error { func (c *ServiceConfig) validate() error {
// Mandatory fields need to be checked here // Mandatory fields need to be checked here
if c.ConfigStore == nil {
return errors.New("ConfigStore is required")
}
if c.Logger == nil {
return errors.New("Logger is required")
}
return nil return nil
} }

184
app/platform/metrics.go Обычный файл
Просмотреть файл

@@ -0,0 +1,184 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package platform
import (
"context"
"fmt"
"net"
"net/http"
"net/http/pprof"
"runtime"
"sync"
"text/template"
"time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/mattermost/mattermost-server/v6/einterfaces"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/pkg/errors"
)
const TimeToWaitForConnectionsToCloseOnServerShutdown = time.Second
type platformMetrics struct {
server *http.Server
router *mux.Router
lock sync.Mutex
logger *mlog.Logger
metricsImpl einterfaces.MetricsInterface
cfgFn func() *model.Config
}
// resetMetrics resets the metrics server. Clears the metrics if the metrics are disabled by the config.
func (ps *PlatformService) resetMetrics(metricsImpl einterfaces.MetricsInterface, cfgFn func() *model.Config) error {
if !*cfgFn().MetricsSettings.Enable {
if ps.metrics != nil {
return ps.metrics.stopMetricsServer()
}
return nil
}
if ps.metrics != nil {
if err := ps.metrics.stopMetricsServer(); err != nil {
return err
}
}
ps.metrics = &platformMetrics{
cfgFn: cfgFn,
metricsImpl: metricsImpl,
logger: ps.logger,
}
if err := ps.metrics.initMetricsRouter(); err != nil {
return err
}
if metricsImpl != nil {
metricsImpl.Register()
}
return ps.metrics.startMetricsServer()
}
func (pm *platformMetrics) stopMetricsServer() error {
pm.lock.Lock()
defer pm.lock.Unlock()
if pm.server != nil {
ctx, cancel := context.WithTimeout(context.Background(), TimeToWaitForConnectionsToCloseOnServerShutdown)
defer cancel()
if err := pm.server.Shutdown(ctx); err != nil {
return fmt.Errorf("could not shutdown metrics server: %v", err)
}
pm.logger.Info("Metrics and profiling server is stopped")
}
return nil
}
func (pm *platformMetrics) startMetricsServer() error {
var notify chan struct{}
pm.lock.Lock()
defer func() {
if notify != nil {
<-notify
}
pm.lock.Unlock()
}()
l, err := net.Listen("tcp", *pm.cfgFn().MetricsSettings.ListenAddress)
if err != nil {
return err
}
notify = make(chan struct{})
pm.server = &http.Server{
Handler: handlers.RecoveryHandler(handlers.PrintRecoveryStack(true))(pm.router),
ReadTimeout: time.Duration(*pm.cfgFn().ServiceSettings.ReadTimeout) * time.Second,
WriteTimeout: time.Duration(*pm.cfgFn().ServiceSettings.WriteTimeout) * time.Second,
}
go func() {
close(notify)
if err := pm.server.Serve(l); err != nil && err != http.ErrServerClosed {
pm.logger.Critical(err.Error())
}
}()
pm.logger.Info("Metrics and profiling server is started", mlog.String("address", l.Addr().String()))
return nil
}
func (pm *platformMetrics) initMetricsRouter() error {
pm.router = mux.NewRouter()
runtime.SetBlockProfileRate(*pm.cfgFn().MetricsSettings.BlockProfileRate)
metricsPage := `
<html>
<body>{{if .}}
<div><a href="/metrics">Metrics</a></div>{{end}}
<div><a href="/debug/pprof/">Profiling Root</a></div>
<div><a href="/debug/pprof/cmdline">Profiling Command Line</a></div>
<div><a href="/debug/pprof/symbol">Profiling Symbols</a></div>
<div><a href="/debug/pprof/goroutine">Profiling Goroutines</a></div>
<div><a href="/debug/pprof/heap">Profiling Heap</a></div>
<div><a href="/debug/pprof/threadcreate">Profiling Threads</a></div>
<div><a href="/debug/pprof/block">Profiling Blocking</a></div>
<div><a href="/debug/pprof/trace">Profiling Execution Trace</a></div>
<div><a href="/debug/pprof/profile">Profiling CPU</a></div>
</body>
</html>
`
metricsPageTmpl, err := template.New("page").Parse(metricsPage)
if err != nil {
return errors.Wrap(err, "failed to create template")
}
rootHandler := func(w http.ResponseWriter, r *http.Request) {
metricsPageTmpl.Execute(w, pm.metricsImpl != nil)
}
pm.router.HandleFunc("/", rootHandler)
pm.router.StrictSlash(true)
pm.router.Handle("/debug", http.RedirectHandler("/", http.StatusMovedPermanently))
pm.router.HandleFunc("/debug/pprof/", pprof.Index)
pm.router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
pm.router.HandleFunc("/debug/pprof/profile", pprof.Profile)
pm.router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
pm.router.HandleFunc("/debug/pprof/trace", pprof.Trace)
// Manually add support for paths linked to by index page at /debug/pprof/
pm.router.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
pm.router.Handle("/debug/pprof/heap", pprof.Handler("heap"))
pm.router.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
pm.router.Handle("/debug/pprof/block", pprof.Handler("block"))
return nil
}
func (ps *PlatformService) HandleMetrics(route string, h http.Handler) {
if ps.metrics != nil {
ps.metrics.router.Handle(route, h)
}
}
func (ps *PlatformService) RestartMetrics() error {
return ps.resetMetrics(ps.serviceConfig.Metrics, ps.serviceConfig.ConfigStore.Get)
}
func (ps *PlatformService) Metrics() einterfaces.MetricsInterface {
if ps.metrics == nil {
return nil
}
return ps.metrics.metricsImpl
}

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

@@ -3,17 +3,49 @@
package platform package platform
import (
"github.com/mattermost/mattermost-server/v6/config"
"github.com/mattermost/mattermost-server/v6/einterfaces"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
// PlatformService is the service for the platform related tasks. It is // PlatformService is the service for the platform related tasks. It is
// responsible for non-entity related functionalities that are required // responsible for non-entity related functionalities that are required
// by a product such as database access, configuration access, licensing etc. // by a product such as database access, configuration access, licensing etc.
type PlatformService struct { type PlatformService struct {
serviceConfig ServiceConfig
configStore *config.Store
logger *mlog.Logger
metrics *platformMetrics
cluster einterfaces.ClusterInterface
} }
// New creates a new PlatformService. // New creates a new PlatformService.
func New(c ServiceConfig) (*PlatformService, error) { func New(sc ServiceConfig) (*PlatformService, error) {
if err := c.validate(); err != nil { if err := sc.validate(); err != nil {
return nil, err return nil, err
} }
return &PlatformService{}, nil ps := &PlatformService{
serviceConfig: sc,
configStore: sc.ConfigStore,
logger: sc.Logger,
cluster: sc.Cluster,
}
if err := ps.resetMetrics(sc.Metrics, ps.configStore.Get); err != nil {
return nil, err
}
return ps, nil
}
func (ps *PlatformService) ShutdownMetrics() error {
if ps.metrics != nil {
return ps.metrics.stopMetricsServer()
}
return nil
} }

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

@@ -226,7 +226,7 @@ func (ch *Channels) initPlugins(c *request.Context, pluginDir, webappPluginDir s
return New(ServerConnector(ch)).NewPluginAPI(c, manifest) return New(ServerConnector(ch)).NewPluginAPI(c, manifest)
} }
env, err := plugin.NewEnvironment(newAPIFunc, NewDriverImpl(ch.srv), pluginDir, webappPluginDir, ch.srv.Log, ch.srv.Metrics) env, err := plugin.NewEnvironment(newAPIFunc, NewDriverImpl(ch.srv), pluginDir, webappPluginDir, ch.srv.Log, ch.srv.GetMetrics())
if err != nil { if err != nil {
mlog.Error("Failed to start up plugins", mlog.Err(err)) mlog.Error("Failed to start up plugins", mlog.Err(err))
return return

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

@@ -1821,7 +1821,7 @@ func (*MockSlashCommandProvider) GetCommand(a *App, T i18n.TranslateFunc) *model
} }
} }
func (mscp *MockSlashCommandProvider) DoCommand(a *App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (mscp *MockSlashCommandProvider) DoCommand(a *App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
mscp.Args = args mscp.Args = args
mscp.Message = message mscp.Message = message
return &model.CommandResponse{ return &model.CommandResponse{

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

@@ -117,7 +117,7 @@ func (a *App) PluginCommandsForTeam(teamID string) []*model.Command {
// tryExecutePluginCommand attempts to run a command provided by a plugin based on the given arguments. If no such // tryExecutePluginCommand attempts to run a command provided by a plugin based on the given arguments. If no such
// command can be found, returns nil for all arguments. // command can be found, returns nil for all arguments.
func (a *App) tryExecutePluginCommand(c *request.Context, args *model.CommandArgs) (*model.Command, *model.CommandResponse, *model.AppError) { func (a *App) tryExecutePluginCommand(c request.CTX, args *model.CommandArgs) (*model.Command, *model.CommandResponse, *model.AppError) {
parts := strings.Split(args.Command, " ") parts := strings.Split(args.Command, " ")
trigger := parts[0][1:] trigger := parts[0][1:]
trigger = strings.ToLower(trigger) trigger = strings.ToLower(trigger)
@@ -150,7 +150,7 @@ func (a *App) tryExecutePluginCommand(c *request.Context, args *model.CommandArg
return matched.Command, nil, model.NewAppError("ExecutePluginCommand", "model.plugin_command.error.app_error", nil, "err="+err.Error(), http.StatusInternalServerError) return matched.Command, nil, model.NewAppError("ExecutePluginCommand", "model.plugin_command.error.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
} }
for username, userID := range a.MentionsToTeamMembers(args.Command, args.TeamId) { for username, userID := range a.MentionsToTeamMembers(c, args.Command, args.TeamId) {
args.AddUserMention(username, userID) args.AddUserMention(username, userID)
} }

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

@@ -46,7 +46,7 @@ func (s *postServiceWrapper) CreatePost(ctx *request.Context, post *model.Post)
return s.app.CreatePostMissingChannel(ctx, post, true) return s.app.CreatePostMissingChannel(ctx, post, true)
} }
func (a *App) CreatePostAsUser(c *request.Context, post *model.Post, currentSessionId string, setOnline bool) (*model.Post, *model.AppError) { func (a *App) CreatePostAsUser(c request.CTX, post *model.Post, currentSessionId string, setOnline bool) (*model.Post, *model.AppError) {
// Check that channel has not been deleted // Check that channel has not been deleted
channel, errCh := a.Srv().Store.Channel().Get(post.ChannelId, true) channel, errCh := a.Srv().Store.Channel().Get(post.ChannelId, true)
if errCh != nil { if errCh != nil {
@@ -83,7 +83,7 @@ func (a *App) CreatePostAsUser(c *request.Context, post *model.Post, currentSess
isCRTReply := post.RootId != "" && a.IsCRTEnabledForUser(c, post.UserId) isCRTReply := post.RootId != "" && a.IsCRTEnabledForUser(c, post.UserId)
if !fromWebhook && !fromBot && !isCRTReply { if !fromWebhook && !fromBot && !isCRTReply {
if _, err := a.MarkChannelsAsViewed(c, []string{post.ChannelId}, post.UserId, currentSessionId, true); err != nil { if _, err := a.MarkChannelsAsViewed(c, []string{post.ChannelId}, post.UserId, currentSessionId, true); err != nil {
mlog.Warn( c.Logger().Warn(
"Encountered error updating last viewed", "Encountered error updating last viewed",
mlog.String("channel_id", post.ChannelId), mlog.String("channel_id", post.ChannelId),
mlog.String("user_id", post.UserId), mlog.String("user_id", post.UserId),
@@ -1251,7 +1251,7 @@ func (a *App) DeletePost(c request.CTX, postID, deleteByID string) (*model.Post,
postJSON, jsonErr := json.Marshal(post) postJSON, jsonErr := json.Marshal(post)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode post to JSON") return nil, model.NewAppError("DeletePost", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
userMessage := model.NewWebSocketEvent(model.WebsocketEventPostDeleted, "", post.ChannelId, "", nil) userMessage := model.NewWebSocketEvent(model.WebsocketEventPostDeleted, "", post.ChannelId, "", nil)

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

@@ -9,7 +9,6 @@ import (
"net/http" "net/http"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
) )
func (a *App) GetPreferencesForUser(userID string) (model.Preferences, *model.AppError) { func (a *App) GetPreferencesForUser(userID string) (model.Preferences, *model.AppError) {
@@ -69,7 +68,7 @@ func (a *App) UpdatePreferences(userID string, preferences model.Preferences) *m
message = model.NewWebSocketEvent(model.WebsocketEventPreferencesChanged, "", "", userID, nil) message = model.NewWebSocketEvent(model.WebsocketEventPreferencesChanged, "", "", userID, nil)
prefsJSON, jsonErr := json.Marshal(preferences) prefsJSON, jsonErr := json.Marshal(preferences)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode to JSON", mlog.Err(jsonErr)) return model.NewAppError("UpdatePreferences", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message.Add("preferences", string(prefsJSON)) message.Add("preferences", string(prefsJSON))
a.Publish(message) a.Publish(message)
@@ -103,7 +102,7 @@ func (a *App) DeletePreferences(userID string, preferences model.Preferences) *m
message = model.NewWebSocketEvent(model.WebsocketEventPreferencesDeleted, "", "", userID, nil) message = model.NewWebSocketEvent(model.WebsocketEventPreferencesDeleted, "", "", userID, nil)
prefsJSON, jsonErr := json.Marshal(preferences) prefsJSON, jsonErr := json.Marshal(preferences)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode to JSON", mlog.Err(jsonErr)) return model.NewAppError("DeletePreferences", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message.Add("preferences", string(prefsJSON)) message.Add("preferences", string(prefsJSON))
a.Publish(message) a.Publish(message)

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

@@ -12,7 +12,6 @@ import (
"strings" "strings"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/mattermost/mattermost-server/v6/store" "github.com/mattermost/mattermost-server/v6/store"
"github.com/mattermost/mattermost-server/v6/utils" "github.com/mattermost/mattermost-server/v6/utils"
) )
@@ -138,7 +137,9 @@ func (a *App) PatchRole(role *model.Role, patch *model.RolePatch) (*model.Role,
return nil, err return nil, err
} }
a.sendUpdatedRoleEvent(role) if appErr := a.sendUpdatedRoleEvent(role); appErr != nil {
return nil, appErr
}
return role, err return role, err
} }
@@ -225,7 +226,10 @@ func (a *App) UpdateRole(role *model.Role) (*model.Role, *model.AppError) {
for _, ir := range impactedRoles { for _, ir := range impactedRoles {
if ir.Name != role.Name { if ir.Name != role.Name {
a.sendUpdatedRoleEvent(ir) appErr = a.sendUpdatedRoleEvent(ir)
if appErr != nil {
return nil, appErr
}
} }
} }
@@ -254,17 +258,15 @@ func (a *App) CheckRolesExist(roleNames []string) *model.AppError {
return nil return nil
} }
func (a *App) sendUpdatedRoleEvent(role *model.Role) { func (a *App) sendUpdatedRoleEvent(role *model.Role) *model.AppError {
message := model.NewWebSocketEvent(model.WebsocketEventRoleUpdated, "", "", "", nil) message := model.NewWebSocketEvent(model.WebsocketEventRoleUpdated, "", "", "", nil)
roleJSON, jsonErr := json.Marshal(role) roleJSON, jsonErr := json.Marshal(role)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode role to JSON", mlog.Err(jsonErr)) return model.NewAppError("sendUpdatedRoleEvent", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message.Add("role", string(roleJSON)) message.Add("role", string(roleJSON))
a.Publish(message)
a.Srv().Go(func() { return nil
a.Publish(message)
})
} }
func RemoveRoles(rolesToRemove []string, roles string) string { func RemoveRoles(rolesToRemove []string, roles string) string {

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

@@ -9,10 +9,8 @@ import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"hash/maphash" "hash/maphash"
"html/template"
"net" "net"
"net/http" "net/http"
"net/http/pprof"
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
@@ -27,7 +25,6 @@ import (
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
sentryhttp "github.com/getsentry/sentry-go/http" sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/rs/cors" "github.com/rs/cors"
@@ -35,6 +32,7 @@ import (
"github.com/mattermost/mattermost-server/v6/app/email" "github.com/mattermost/mattermost-server/v6/app/email"
"github.com/mattermost/mattermost-server/v6/app/featureflag" "github.com/mattermost/mattermost-server/v6/app/featureflag"
"github.com/mattermost/mattermost-server/v6/app/platform"
"github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/app/teams" "github.com/mattermost/mattermost-server/v6/app/teams"
"github.com/mattermost/mattermost-server/v6/app/users" "github.com/mattermost/mattermost-server/v6/app/users"
@@ -131,10 +129,6 @@ type Server struct {
localModeServer *http.Server localModeServer *http.Server
metricsServer *http.Server
metricsRouter *mux.Router
metricsLock sync.Mutex
didFinishListen chan struct{} didFinishListen chan struct{}
goroutineCount int32 goroutineCount int32
@@ -177,6 +171,7 @@ type Server struct {
configStore *configWrapper configStore *configWrapper
filestore filestore.FileBackend filestore filestore.FileBackend
platform *platform.PlatformService
telemetryService *telemetry.TelemetryService telemetryService *telemetry.TelemetryService
userService *users.UserService userService *users.UserService
teamService *teams.TeamService teamService *teams.TeamService
@@ -200,7 +195,6 @@ type Server struct {
Cluster einterfaces.ClusterInterface Cluster einterfaces.ClusterInterface
Cloud einterfaces.CloudInterface Cloud einterfaces.CloudInterface
Metrics einterfaces.MetricsInterface
LicenseManager einterfaces.LicenseInterface LicenseManager einterfaces.LicenseInterface
CacheProvider cache.Provider CacheProvider cache.Provider
@@ -286,6 +280,22 @@ func NewServer(options ...Option) (*Server, error) {
// Depends on step 3 (s.SearchEngine must be non-nil) // Depends on step 3 (s.SearchEngine must be non-nil)
s.initEnterprise() s.initEnterprise()
platformCfg := platform.ServiceConfig{
ConfigStore: s.configStore.Store,
Logger: s.Log,
StartMetrics: s.startMetrics,
Cluster: s.Cluster,
}
if metricsInterface != nil {
platformCfg.Metrics = metricsInterface(s)
}
ps, sErr := platform.New(platformCfg)
if sErr != nil {
return nil, errors.Wrap(sErr, "failed to initialize platform")
}
s.platform = ps
// Step 5: Cache provider. // Step 5: Cache provider.
// At the moment we only have this implementation // At the moment we only have this implementation
// in the future the cache provider will be built based on the loaded config // in the future the cache provider will be built based on the loaded config
@@ -298,11 +308,11 @@ func NewServer(options ...Option) (*Server, error) {
// Depends on Step 1 (config), 4 (metrics, cluster) and 5 (cacheProvider). // Depends on Step 1 (config), 4 (metrics, cluster) and 5 (cacheProvider).
if s.newStore == nil { if s.newStore == nil {
s.newStore = func() (store.Store, error) { s.newStore = func() (store.Store, error) {
s.sqlStore = sqlstore.New(s.Config().SqlSettings, s.Metrics) s.sqlStore = sqlstore.New(s.Config().SqlSettings, s.GetMetrics())
lcl, err2 := localcachelayer.NewLocalCacheLayer( lcl, err2 := localcachelayer.NewLocalCacheLayer(
retrylayer.New(s.sqlStore), retrylayer.New(s.sqlStore),
s.Metrics, s.GetMetrics(),
s.Cluster, s.Cluster,
s.CacheProvider, s.CacheProvider,
) )
@@ -327,7 +337,7 @@ func NewServer(options ...Option) (*Server, error) {
return timerlayer.New( return timerlayer.New(
searchStore, searchStore,
s.Metrics, s.GetMetrics(),
), nil ), nil
} }
} }
@@ -343,7 +353,7 @@ func NewServer(options ...Option) (*Server, error) {
SessionStore: s.Store.Session(), SessionStore: s.Store.Session(),
OAuthStore: s.Store.OAuth(), OAuthStore: s.Store.OAuth(),
ConfigFn: s.Config, ConfigFn: s.Config,
Metrics: s.Metrics, Metrics: s.GetMetrics(),
Cluster: s.Cluster, Cluster: s.Cluster,
LicenseFn: s.License, LicenseFn: s.License,
}) })
@@ -620,7 +630,9 @@ func NewServer(options ...Option) (*Server, error) {
} }
if s.startMetrics { if s.startMetrics {
s.SetupMetricsServer() if err := s.platform.RestartMetrics(); err != nil {
return nil, errors.Wrap(err, "failed to start metrics")
}
} }
s.AddLicenseListener(func(oldLicense, newLicense *model.License) { s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
@@ -632,7 +644,9 @@ func NewServer(options ...Option) (*Server, error) {
return return
} }
s.SetupMetricsServer() if err := s.platform.RestartMetrics(); err != nil {
s.Log.Error("Failed to reset metrics server", mlog.Err(err))
}
}) })
s.SearchEngine.UpdateConfig(s.Config()) s.SearchEngine.UpdateConfig(s.Config())
@@ -701,24 +715,6 @@ func NewServer(options ...Option) (*Server, error) {
return s, nil return s, nil
} }
func (s *Server) SetupMetricsServer() {
if !*s.Config().MetricsSettings.Enable {
return
}
s.StopMetricsServer()
if err := s.InitMetricsRouter(); err != nil {
mlog.Error("Error initiating metrics router.", mlog.Err(err))
}
if s.Metrics != nil {
s.Metrics.Register()
}
s.startMetricsServer()
}
func maxInt(a, b int) int { func maxInt(a, b int) int {
if a > b { if a > b {
return a return a
@@ -951,11 +947,11 @@ func (s *Server) startInterClusterServices(license *model.License) error {
} }
func (s *Server) enableLoggingMetrics() { func (s *Server) enableLoggingMetrics() {
if s.Metrics == nil { if s.GetMetrics() == nil {
return return
} }
s.Log.SetMetricsCollector(s.Metrics.GetLoggerMetricsCollector(), mlog.DefaultMetricsUpdateFreqMillis) s.Log.SetMetricsCollector(s.GetMetrics().GetLoggerMetricsCollector(), mlog.DefaultMetricsUpdateFreqMillis)
// logging config needs to be reloaded when metrics collector is added or changed. // logging config needs to be reloaded when metrics collector is added or changed.
if err := s.initLogging(); err != nil { if err := s.initLogging(); err != nil {
@@ -991,7 +987,7 @@ func (s *Server) StopHTTPServer() {
} }
func (s *Server) Shutdown() { func (s *Server) Shutdown() {
mlog.Info("Stopping Server...") s.Log.Info("Stopping Server...")
defer sentry.Flush(2 * time.Second) defer sentry.Flush(2 * time.Second)
@@ -1002,24 +998,24 @@ func (s *Server) Shutdown() {
if s.tracer != nil { if s.tracer != nil {
if err := s.tracer.Close(); err != nil { if err := s.tracer.Close(); err != nil {
mlog.Warn("Unable to cleanly shutdown opentracing client", mlog.Err(err)) s.Log.Warn("Unable to cleanly shutdown opentracing client", mlog.Err(err))
} }
} }
err := s.telemetryService.Shutdown() err := s.telemetryService.Shutdown()
if err != nil { if err != nil {
mlog.Warn("Unable to cleanly shutdown telemetry client", mlog.Err(err)) s.Log.Warn("Unable to cleanly shutdown telemetry client", mlog.Err(err))
} }
s.serviceMux.RLock() s.serviceMux.RLock()
if s.sharedChannelService != nil { if s.sharedChannelService != nil {
if err = s.sharedChannelService.Shutdown(); err != nil { if err = s.sharedChannelService.Shutdown(); err != nil {
mlog.Error("Error shutting down shared channel services", mlog.Err(err)) s.Log.Error("Error shutting down shared channel services", mlog.Err(err))
} }
} }
if s.remoteClusterService != nil { if s.remoteClusterService != nil {
if err = s.remoteClusterService.Shutdown(); err != nil { if err = s.remoteClusterService.Shutdown(); err != nil {
mlog.Error("Error shutting down intercluster services", mlog.Err(err)) s.Log.Error("Error shutting down intercluster services", mlog.Err(err))
} }
} }
s.serviceMux.RUnlock() s.serviceMux.RUnlock()
@@ -1046,7 +1042,9 @@ func (s *Server) Shutdown() {
s.Cluster.StopInterNodeCommunication() s.Cluster.StopInterNodeCommunication()
} }
s.StopMetricsServer() if err = s.platform.ShutdownMetrics(); err != nil {
s.Log.Warn("Failed to stop metrics server", mlog.Err(err))
}
// This must be done after the cluster is stopped. // This must be done after the cluster is stopped.
if s.Jobs != nil { if s.Jobs != nil {
@@ -1054,10 +1052,10 @@ func (s *Server) Shutdown() {
// before stopping them as both calls essentially become no-ops // before stopping them as both calls essentially become no-ops
// if nothing is running. // if nothing is running.
if err = s.Jobs.StopWorkers(); err != nil && !errors.Is(err, jobs.ErrWorkersNotRunning) { if err = s.Jobs.StopWorkers(); err != nil && !errors.Is(err, jobs.ErrWorkersNotRunning) {
mlog.Warn("Failed to stop job server workers", mlog.Err(err)) s.Log.Warn("Failed to stop job server workers", mlog.Err(err))
} }
if err = s.Jobs.StopSchedulers(); err != nil && !errors.Is(err, jobs.ErrSchedulersNotRunning) { if err = s.Jobs.StopSchedulers(); err != nil && !errors.Is(err, jobs.ErrSchedulersNotRunning) {
mlog.Warn("Failed to stop job server schedulers", mlog.Err(err)) s.Log.Warn("Failed to stop job server schedulers", mlog.Err(err))
} }
} }
@@ -1066,7 +1064,7 @@ func (s *Server) Shutdown() {
// on parent services. // on parent services.
for name, product := range s.products { for name, product := range s.products {
if err2 := product.Stop(); err2 != nil { if err2 := product.Stop(); err2 != nil {
mlog.Warn("Unable to cleanly stop product", mlog.String("name", name), mlog.Err(err2)) s.Log.Warn("Unable to cleanly stop product", mlog.String("name", name), mlog.Err(err2))
} }
} }
@@ -1076,11 +1074,11 @@ func (s *Server) Shutdown() {
if s.CacheProvider != nil { if s.CacheProvider != nil {
if err = s.CacheProvider.Close(); err != nil { if err = s.CacheProvider.Close(); err != nil {
mlog.Warn("Unable to cleanly shutdown cache", mlog.Err(err)) s.Log.Warn("Unable to cleanly shutdown cache", mlog.Err(err))
} }
} }
mlog.Info("Server stopped") s.Log.Info("Server stopped")
// shutdown main and notification loggers which will flush any remaining log records. // shutdown main and notification loggers which will flush any remaining log records.
timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), time.Second*15) timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), time.Second*15)
@@ -1630,104 +1628,8 @@ func doConfigCleanup(s *Server) {
} }
} }
func (s *Server) StopMetricsServer() {
s.metricsLock.Lock()
defer s.metricsLock.Unlock()
if s.metricsServer != nil {
ctx, cancel := context.WithTimeout(context.Background(), TimeToWaitForConnectionsToCloseOnServerShutdown)
defer cancel()
s.metricsServer.Shutdown(ctx)
s.Log.Info("Metrics and profiling server is stopping")
}
}
func (s *Server) HandleMetrics(route string, h http.Handler) { func (s *Server) HandleMetrics(route string, h http.Handler) {
if s.metricsRouter != nil { s.platform.HandleMetrics(route, h)
s.metricsRouter.Handle(route, h)
}
}
func (s *Server) InitMetricsRouter() error {
s.metricsRouter = mux.NewRouter()
runtime.SetBlockProfileRate(*s.Config().MetricsSettings.BlockProfileRate)
metricsPage := `
<html>
<body>{{if .}}
<div><a href="/metrics">Metrics</a></div>{{end}}
<div><a href="/debug/pprof/">Profiling Root</a></div>
<div><a href="/debug/pprof/cmdline">Profiling Command Line</a></div>
<div><a href="/debug/pprof/symbol">Profiling Symbols</a></div>
<div><a href="/debug/pprof/goroutine">Profiling Goroutines</a></div>
<div><a href="/debug/pprof/heap">Profiling Heap</a></div>
<div><a href="/debug/pprof/threadcreate">Profiling Threads</a></div>
<div><a href="/debug/pprof/block">Profiling Blocking</a></div>
<div><a href="/debug/pprof/trace">Profiling Execution Trace</a></div>
<div><a href="/debug/pprof/profile">Profiling CPU</a></div>
</body>
</html>
`
metricsPageTmpl, err := template.New("page").Parse(metricsPage)
if err != nil {
return errors.Wrap(err, "failed to create template")
}
rootHandler := func(w http.ResponseWriter, r *http.Request) {
metricsPageTmpl.Execute(w, s.Metrics != nil)
}
s.metricsRouter.HandleFunc("/", rootHandler)
s.metricsRouter.StrictSlash(true)
s.metricsRouter.Handle("/debug", http.RedirectHandler("/", http.StatusMovedPermanently))
s.metricsRouter.HandleFunc("/debug/pprof/", pprof.Index)
s.metricsRouter.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
s.metricsRouter.HandleFunc("/debug/pprof/profile", pprof.Profile)
s.metricsRouter.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
s.metricsRouter.HandleFunc("/debug/pprof/trace", pprof.Trace)
// Manually add support for paths linked to by index page at /debug/pprof/
s.metricsRouter.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
s.metricsRouter.Handle("/debug/pprof/heap", pprof.Handler("heap"))
s.metricsRouter.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
s.metricsRouter.Handle("/debug/pprof/block", pprof.Handler("block"))
return nil
}
func (s *Server) startMetricsServer() {
var notify chan struct{}
s.metricsLock.Lock()
defer func() {
if notify != nil {
<-notify
}
s.metricsLock.Unlock()
}()
l, err := net.Listen("tcp", *s.Config().MetricsSettings.ListenAddress)
if err != nil {
mlog.Error(err.Error())
return
}
notify = make(chan struct{})
s.metricsServer = &http.Server{
Handler: handlers.RecoveryHandler(handlers.PrintRecoveryStack(true))(s.metricsRouter),
ReadTimeout: time.Duration(*s.Config().ServiceSettings.ReadTimeout) * time.Second,
WriteTimeout: time.Duration(*s.Config().ServiceSettings.WriteTimeout) * time.Second,
}
go func() {
close(notify)
if err := s.metricsServer.Serve(l); err != nil && err != http.ErrServerClosed {
mlog.Critical(err.Error())
}
}()
s.Log.Info("Metrics and profiling server is started", mlog.String("address", l.Addr().String()))
} }
func (s *Server) sendLicenseUpForRenewalEmail(users map[string]*model.User, license *model.License) *model.AppError { func (s *Server) sendLicenseUpForRenewalEmail(users map[string]*model.User, license *model.License) *model.AppError {
@@ -1956,7 +1858,7 @@ func (ch *Channels) ClientConfigHash() string {
} }
func (s *Server) initJobs() { func (s *Server) initJobs() {
s.Jobs = jobs.NewJobServer(s, s.Store, s.Metrics) s.Jobs = jobs.NewJobServer(s, s.Store, s.GetMetrics())
if jobsDataRetentionJobInterface != nil { if jobsDataRetentionJobInterface != nil {
builder := jobsDataRetentionJobInterface(s) builder := jobsDataRetentionJobInterface(s)
@@ -2039,7 +1941,7 @@ func (s *Server) initJobs() {
s.Jobs.RegisterJobType( s.Jobs.RegisterJobType(
model.JobTypeActiveUsers, model.JobTypeActiveUsers,
active_users.MakeWorker(s.Jobs, s.Store, func() einterfaces.MetricsInterface { return s.Metrics }), active_users.MakeWorker(s.Jobs, s.Store, func() einterfaces.MetricsInterface { return s.GetMetrics() }),
active_users.MakeScheduler(s.Jobs), active_users.MakeScheduler(s.Jobs),
) )
@@ -2106,7 +2008,10 @@ func (s *Server) GetSharedChannelSyncService() SharedChannelServiceIFace {
// GetMetrics returns the server's Metrics interface. Exposing via a method // GetMetrics returns the server's Metrics interface. Exposing via a method
// allows interfaces to be created with subsets of server APIs. // allows interfaces to be created with subsets of server APIs.
func (s *Server) GetMetrics() einterfaces.MetricsInterface { func (s *Server) GetMetrics() einterfaces.MetricsInterface {
return s.Metrics if s.platform == nil {
return nil
}
return s.platform.Metrics()
} }
// SetRemoteClusterService sets the `RemoteClusterService` to be used by the server. // SetRemoteClusterService sets the `RemoteClusterService` to be used by the server.

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

@@ -36,7 +36,7 @@ func NewAutoChannelCreator(a *app.App, team *model.Team, userID string) *AutoCha
} }
} }
func (cfg *AutoChannelCreator) createRandomChannel(c *request.Context) (*model.Channel, error) { func (cfg *AutoChannelCreator) createRandomChannel(c request.CTX) (*model.Channel, error) {
var displayName string var displayName string
if cfg.Fuzzy { if cfg.Fuzzy {
displayName = utils.FuzzName() displayName = utils.FuzzName()
@@ -60,7 +60,7 @@ func (cfg *AutoChannelCreator) createRandomChannel(c *request.Context) (*model.C
return channel, nil return channel, nil
} }
func (cfg *AutoChannelCreator) CreateTestChannels(c *request.Context, num utils.Range) ([]*model.Channel, error) { func (cfg *AutoChannelCreator) CreateTestChannels(c request.CTX, num utils.Range) ([]*model.Channel, error) {
numChannels := utils.RandIntFromRange(num) numChannels := utils.RandIntFromRange(num)
channels := make([]*model.Channel, numChannels) channels := make([]*model.Channel, numChannels)
@@ -75,7 +75,7 @@ func (cfg *AutoChannelCreator) CreateTestChannels(c *request.Context, num utils.
return channels, nil return channels, nil
} }
func (cfg *AutoChannelCreator) CreateTestDMs(c *request.Context, num utils.Range) ([]*model.Channel, error) { func (cfg *AutoChannelCreator) CreateTestDMs(c request.CTX, num utils.Range) ([]*model.Channel, error) {
numDMs := utils.RandIntFromRange(num) numDMs := utils.RandIntFromRange(num)
dms := make([]*model.Channel, numDMs) dms := make([]*model.Channel, numDMs)

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

@@ -18,7 +18,7 @@ type TestEnvironment struct {
Environments []TeamEnvironment Environments []TeamEnvironment
} }
func CreateTestEnvironmentWithTeams(a *app.App, c *request.Context, client *model.Client4, rangeTeams utils.Range, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TestEnvironment, error) { func CreateTestEnvironmentWithTeams(a *app.App, c request.CTX, client *model.Client4, rangeTeams utils.Range, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TestEnvironment, error) {
rand.Seed(time.Now().UTC().UnixNano()) rand.Seed(time.Now().UTC().UnixNano())
teamCreator := NewAutoTeamCreator(client) teamCreator := NewAutoTeamCreator(client)
@@ -48,7 +48,7 @@ func CreateTestEnvironmentWithTeams(a *app.App, c *request.Context, client *mode
return environment, nil return environment, nil
} }
func CreateTestEnvironmentInTeam(a *app.App, c *request.Context, client *model.Client4, team *model.Team, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TeamEnvironment, error) { func CreateTestEnvironmentInTeam(a *app.App, c request.CTX, client *model.Client4, team *model.Team, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TeamEnvironment, error) {
rand.Seed(time.Now().UTC().UnixNano()) rand.Seed(time.Now().UTC().UnixNano())
// We need to create at least one user // We need to create at least one user

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

@@ -45,7 +45,7 @@ func NewAutoPostCreator(a *app.App, channelid, userid string) *AutoPostCreator {
} }
} }
func (cfg *AutoPostCreator) UploadTestFile(c *request.Context) ([]string, error) { func (cfg *AutoPostCreator) UploadTestFile(c request.CTX) ([]string, error) {
filename := cfg.ImageFilenames[utils.RandIntFromRange(utils.Range{Begin: 0, End: len(cfg.ImageFilenames) - 1})] filename := cfg.ImageFilenames[utils.RandIntFromRange(utils.Range{Begin: 0, End: len(cfg.ImageFilenames) - 1})]
path, _ := fileutils.FindDir("tests") path, _ := fileutils.FindDir("tests")
@@ -69,11 +69,11 @@ func (cfg *AutoPostCreator) UploadTestFile(c *request.Context) ([]string, error)
return []string{fileResp.Id}, nil return []string{fileResp.Id}, nil
} }
func (cfg *AutoPostCreator) CreateRandomPost(c *request.Context) (*model.Post, error) { func (cfg *AutoPostCreator) CreateRandomPost(c request.CTX) (*model.Post, error) {
return cfg.CreateRandomPostNested(c, "") return cfg.CreateRandomPostNested(c, "")
} }
func (cfg *AutoPostCreator) CreateRandomPostNested(c *request.Context, rootId string) (*model.Post, error) { func (cfg *AutoPostCreator) CreateRandomPostNested(c request.CTX, rootId string) (*model.Post, error) {
var fileIDs []string var fileIDs []string
if cfg.HasImage { if cfg.HasImage {
var err error var err error

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

@@ -78,7 +78,7 @@ func CreateBasicUser(a *app.App, client *model.Client4) error {
return nil return nil
} }
func (cfg *AutoUserCreator) createRandomUser(c *request.Context) (*model.User, error) { func (cfg *AutoUserCreator) createRandomUser(c request.CTX) (*model.User, error) {
var userEmail string var userEmail string
var userName string var userName string
if cfg.Fuzzy { if cfg.Fuzzy {
@@ -113,7 +113,7 @@ func (cfg *AutoUserCreator) createRandomUser(c *request.Context) (*model.User, e
return ruser, nil return ruser, nil
} }
func (cfg *AutoUserCreator) CreateTestUsers(c *request.Context, num utils.Range) ([]*model.User, error) { func (cfg *AutoUserCreator) CreateTestUsers(c request.CTX, num utils.Range) ([]*model.User, error) {
numUsers := utils.RandIntFromRange(num) numUsers := utils.RandIntFromRange(num)
users := make([]*model.User, numUsers) users := make([]*model.User, numUsers)

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

@@ -34,7 +34,7 @@ func (*AwayProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command
} }
} }
func (*AwayProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*AwayProvider) DoCommand(a *app.App, _ request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
a.SetStatusAwayIfNeeded(args.UserId, true) a.SetStatusAwayIfNeeded(args.UserId, true)
return &model.CommandResponse{ResponseType: model.CommandResponseTypeEphemeral, Text: args.T("api.command_away.success")} return &model.CommandResponse{ResponseType: model.CommandResponseTypeEphemeral, Text: args.T("api.command_away.success")}

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

@@ -35,7 +35,7 @@ func (*HeaderProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comma
} }
} }
func (*HeaderProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*HeaderProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
channel, err := a.GetChannel(c, args.ChannelId) channel, err := a.GetChannel(c, args.ChannelId)
if err != nil { if err != nil {
return &model.CommandResponse{ return &model.CommandResponse{

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

@@ -35,7 +35,7 @@ func (*PurposeProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comm
} }
} }
func (*PurposeProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*PurposeProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
channel, err := a.GetChannel(c, args.ChannelId) channel, err := a.GetChannel(c, args.ChannelId)
if err != nil { if err != nil {
return &model.CommandResponse{ return &model.CommandResponse{

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

@@ -38,7 +38,7 @@ func (*RenameProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comma
} }
} }
func (*RenameProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*RenameProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
channel, err := a.GetChannel(c, args.ChannelId) channel, err := a.GetChannel(c, args.ChannelId)
if err != nil { if err != nil {
return &model.CommandResponse{ return &model.CommandResponse{

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

@@ -37,7 +37,7 @@ func (*CodeProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command
} }
} }
func (*CodeProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*CodeProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
if message == "" { if message == "" {
return &model.CommandResponse{Text: args.T("api.command_code.message.app_error"), ResponseType: model.CommandResponseTypeEphemeral} return &model.CommandResponse{Text: args.T("api.command_code.message.app_error"), ResponseType: model.CommandResponseTypeEphemeral}
} }

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

@@ -41,7 +41,7 @@ func (*CustomStatusProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model
} }
} }
func (*CustomStatusProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*CustomStatusProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
if !*a.Config().TeamSettings.EnableCustomUserStatuses { if !*a.Config().TeamSettings.EnableCustomUserStatuses {
return nil return nil
} }

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

@@ -34,7 +34,7 @@ func (*DndProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command
} }
} }
func (*DndProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*DndProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
a.SetStatusDoNotDisturb(args.UserId) a.SetStatusDoNotDisturb(args.UserId)
return &model.CommandResponse{ResponseType: model.CommandResponseTypeEphemeral, Text: args.T("api.command_dnd.success")} return &model.CommandResponse{ResponseType: model.CommandResponseTypeEphemeral, Text: args.T("api.command_dnd.success")}

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

@@ -42,7 +42,7 @@ func (*EchoProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command
} }
} }
func (*EchoProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*EchoProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
if message == "" { if message == "" {
return &model.CommandResponse{Text: args.T("api.command_echo.message.app_error"), ResponseType: model.CommandResponseTypeEphemeral} return &model.CommandResponse{Text: args.T("api.command_echo.message.app_error"), ResponseType: model.CommandResponseTypeEphemeral}
} }

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

@@ -11,7 +11,6 @@ import (
"github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/i18n" "github.com/mattermost/mattermost-server/v6/shared/i18n"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
) )
type ExpandProvider struct { type ExpandProvider struct {
@@ -56,11 +55,11 @@ func (*CollapseProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Com
} }
} }
func (*ExpandProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*ExpandProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
return setCollapsePreference(a, args, false) return setCollapsePreference(a, args, false)
} }
func (*CollapseProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*CollapseProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
return setCollapsePreference(a, args, true) return setCollapsePreference(a, args, true)
} }
@@ -73,14 +72,14 @@ func setCollapsePreference(a *app.App, args *model.CommandArgs, isCollapse bool)
} }
if err := a.Srv().Store.Preference().Save(model.Preferences{pref}); err != nil { if err := a.Srv().Store.Preference().Save(model.Preferences{pref}); err != nil {
return &model.CommandResponse{Text: args.T("api.command_expand_collapse.fail.app_error"), ResponseType: model.CommandResponseTypeEphemeral} return &model.CommandResponse{Text: args.T("api.command_expand_collapse.fail.app_error") + err.Error(), ResponseType: model.CommandResponseTypeEphemeral}
} }
socketMessage := model.NewWebSocketEvent(model.WebsocketEventPreferenceChanged, "", "", args.UserId, nil) socketMessage := model.NewWebSocketEvent(model.WebsocketEventPreferenceChanged, "", "", args.UserId, nil)
prefJSON, jsonErr := json.Marshal(pref) prefJSON, jsonErr := json.Marshal(pref)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode to JSON", mlog.Err(jsonErr)) return &model.CommandResponse{Text: args.T("api.marshal_error") + jsonErr.Error(), ResponseType: model.CommandResponseTypeEphemeral}
} }
socketMessage.Add("preference", string(prefJSON)) socketMessage.Add("preference", string(prefJSON))
a.Publish(socketMessage) a.Publish(socketMessage)

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

@@ -39,7 +39,7 @@ func (*groupmsgProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Com
} }
} }
func (*groupmsgProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*groupmsgProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
targetUsers := map[string]*model.User{} targetUsers := map[string]*model.User{}
targetUsersSlice := []string{args.UserId} targetUsersSlice := []string{args.UserId}
invalidUsernames := []string{} invalidUsernames := []string{}

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

@@ -34,7 +34,7 @@ func (h *HelpProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comma
} }
} }
func (h *HelpProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (h *HelpProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
helpLink := *a.Config().SupportSettings.HelpLink helpLink := *a.Config().SupportSettings.HelpLink
if helpLink == "" { if helpLink == "" {

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

@@ -38,7 +38,7 @@ func (*InviteProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comma
} }
} }
func (*InviteProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*InviteProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
if message == "" { if message == "" {
return &model.CommandResponse{ return &model.CommandResponse{
Text: args.T("api.command_invite.missing_message.app_error"), Text: args.T("api.command_invite.missing_message.app_error"),

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

@@ -42,7 +42,7 @@ func (*InvitePeopleProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model
} }
} }
func (*InvitePeopleProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*InvitePeopleProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
if !a.HasPermissionToTeam(args.UserId, args.TeamId, model.PermissionInviteUser) { if !a.HasPermissionToTeam(args.UserId, args.TeamId, model.PermissionInviteUser) {
return &model.CommandResponse{Text: args.T("api.command_invite_people.permission.app_error"), ResponseType: model.CommandResponseTypeEphemeral} return &model.CommandResponse{Text: args.T("api.command_invite_people.permission.app_error"), ResponseType: model.CommandResponseTypeEphemeral}
} }

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

@@ -37,7 +37,7 @@ func (*JoinProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command
} }
} }
func (*JoinProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*JoinProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
channelName := strings.ToLower(message) channelName := strings.ToLower(message)
if strings.HasPrefix(message, "~") { if strings.HasPrefix(message, "~") {

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

@@ -34,7 +34,7 @@ func (*LeaveProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comman
} }
} }
func (*LeaveProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*LeaveProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
var channel *model.Channel var channel *model.Channel
var noChannelErr *model.AppError var noChannelErr *model.AppError
if channel, noChannelErr = a.GetChannel(c, args.ChannelId); noChannelErr != nil { if channel, noChannelErr = a.GetChannel(c, args.ChannelId); noChannelErr != nil {

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

@@ -115,16 +115,16 @@ func (*LoadTestProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Com
} }
} }
func (lt *LoadTestProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (lt *LoadTestProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
commandResponse, err := lt.doCommand(a, c, args, message) commandResponse, err := lt.doCommand(a, c, args, message)
if err != nil { if err != nil {
mlog.Error("failed command /"+CmdTest, mlog.Err(err)) c.Logger().Error("failed command /"+CmdTest, mlog.Err(err))
} }
return commandResponse return commandResponse
} }
func (lt *LoadTestProvider) doCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (lt *LoadTestProvider) doCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
//This command is only available when EnableTesting is true //This command is only available when EnableTesting is true
if !*a.Config().ServiceSettings.EnableTesting { if !*a.Config().ServiceSettings.EnableTesting {
return &model.CommandResponse{}, nil return &model.CommandResponse{}, nil
@@ -181,7 +181,7 @@ func (*LoadTestProvider) HelpCommand(args *model.CommandArgs, message string) *m
return &model.CommandResponse{Text: usage, ResponseType: model.CommandResponseTypeEphemeral} return &model.CommandResponse{Text: usage, ResponseType: model.CommandResponseTypeEphemeral}
} }
func (*LoadTestProvider) SetupCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) SetupCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
tokens := strings.Fields(strings.TrimPrefix(message, "setup")) tokens := strings.Fields(strings.TrimPrefix(message, "setup"))
doTeams := contains(tokens, "teams") doTeams := contains(tokens, "teams")
doFuzz := contains(tokens, "fuzz") doFuzz := contains(tokens, "fuzz")
@@ -242,10 +242,10 @@ func (*LoadTestProvider) SetupCommand(a *app.App, c *request.Context, args *mode
return &model.CommandResponse{Text: "Failed to create testing environment", ResponseType: model.CommandResponseTypeEphemeral}, err return &model.CommandResponse{Text: "Failed to create testing environment", ResponseType: model.CommandResponseTypeEphemeral}, err
} }
mlog.Info("Testing environment created") c.Logger().Info("Testing environment created")
for i := 0; i < len(environment.Teams); i++ { for i := 0; i < len(environment.Teams); i++ {
mlog.Info("Team Created: " + environment.Teams[i].Name) c.Logger().Info("Team Created: " + environment.Teams[i].Name)
mlog.Info("\t User to login: " + environment.Environments[i].Users[0].Email + ", " + UserPassword) c.Logger().Info("\t User to login: " + environment.Environments[i].Users[0].Email + ", " + UserPassword)
} }
} else { } else {
team, err := a.Srv().Store.Team().Get(args.TeamId) team, err := a.Srv().Store.Team().Get(args.TeamId)
@@ -267,7 +267,7 @@ func (*LoadTestProvider) SetupCommand(a *app.App, c *request.Context, args *mode
return &model.CommandResponse{Text: "Created environment", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Created environment", ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) ActivateUserCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) ActivateUserCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
user_id := strings.TrimSpace(strings.TrimPrefix(message, "activate_user")) user_id := strings.TrimSpace(strings.TrimPrefix(message, "activate_user"))
if err := a.UpdateUserActive(c, user_id, true); err != nil { if err := a.UpdateUserActive(c, user_id, true); err != nil {
return &model.CommandResponse{Text: "Failed to activate user", ResponseType: model.CommandResponseTypeEphemeral}, err return &model.CommandResponse{Text: "Failed to activate user", ResponseType: model.CommandResponseTypeEphemeral}, err
@@ -276,7 +276,7 @@ func (*LoadTestProvider) ActivateUserCommand(a *app.App, c *request.Context, arg
return &model.CommandResponse{Text: "Activated user", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Activated user", ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) DeActivateUserCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) DeActivateUserCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
user_id := strings.TrimSpace(strings.TrimPrefix(message, "deactivate_user")) user_id := strings.TrimSpace(strings.TrimPrefix(message, "deactivate_user"))
if err := a.UpdateUserActive(c, user_id, false); err != nil { if err := a.UpdateUserActive(c, user_id, false); err != nil {
return &model.CommandResponse{Text: "Failed to deactivate user", ResponseType: model.CommandResponseTypeEphemeral}, err return &model.CommandResponse{Text: "Failed to deactivate user", ResponseType: model.CommandResponseTypeEphemeral}, err
@@ -285,7 +285,7 @@ func (*LoadTestProvider) DeActivateUserCommand(a *app.App, c *request.Context, a
return &model.CommandResponse{Text: "DeActivated user", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "DeActivated user", ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) UsersCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) UsersCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
cmd := strings.TrimSpace(strings.TrimPrefix(message, "users")) cmd := strings.TrimSpace(strings.TrimPrefix(message, "users"))
doFuzz := false doFuzz := false
@@ -314,7 +314,7 @@ func (*LoadTestProvider) UsersCommand(a *app.App, c *request.Context, args *mode
return &model.CommandResponse{Text: "Added users", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Added users", ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) ChannelsCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) ChannelsCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
cmd := strings.TrimSpace(strings.TrimPrefix(message, "channels")) cmd := strings.TrimSpace(strings.TrimPrefix(message, "channels"))
doFuzz := false doFuzz := false
@@ -342,7 +342,7 @@ func (*LoadTestProvider) ChannelsCommand(a *app.App, c *request.Context, args *m
return &model.CommandResponse{Text: "Added channels", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Added channels", ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) DMsCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) DMsCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
cmd := strings.TrimSpace(strings.TrimPrefix(message, "dms")) cmd := strings.TrimSpace(strings.TrimPrefix(message, "dms"))
channelsr, ok := parseRange(cmd, "") channelsr, ok := parseRange(cmd, "")
@@ -358,7 +358,7 @@ func (*LoadTestProvider) DMsCommand(a *app.App, c *request.Context, args *model.
return &model.CommandResponse{Text: "Added DMs", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Added DMs", ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) ThreadedPostCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) ThreadedPostCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
var usernames []string var usernames []string
options := &model.UserGetOptions{InTeamId: args.TeamId, Page: 0, PerPage: 1000} options := &model.UserGetOptions{InTeamId: args.TeamId, Page: 0, PerPage: 1000}
if profileUsers, err := a.Srv().Store.User().GetProfiles(options); err == nil { if profileUsers, err := a.Srv().Store.User().GetProfiles(options); err == nil {
@@ -384,7 +384,7 @@ func (*LoadTestProvider) ThreadedPostCommand(a *app.App, c *request.Context, arg
return &model.CommandResponse{Text: "Added threaded post", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Added threaded post", ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) PostsCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) PostsCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
cmd := strings.TrimSpace(strings.TrimPrefix(message, "posts")) cmd := strings.TrimSpace(strings.TrimPrefix(message, "posts"))
doFuzz := false doFuzz := false
@@ -486,7 +486,7 @@ func (*LoadTestProvider) PostCommand(a *app.App, c request.CTX, args *model.Comm
return &model.CommandResponse{Text: "Added a post to " + channel.DisplayName, ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Added a post to " + channel.DisplayName, ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) URLCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) URLCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
url := strings.TrimSpace(strings.TrimPrefix(message, "url")) url := strings.TrimSpace(strings.TrimPrefix(message, "url"))
if url == "" { if url == "" {
return &model.CommandResponse{Text: "Command must contain a url", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Command must contain a url", ResponseType: model.CommandResponseTypeEphemeral}, nil
@@ -540,7 +540,7 @@ func (*LoadTestProvider) URLCommand(a *app.App, c *request.Context, args *model.
return &model.CommandResponse{Text: "Loaded data", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Loaded data", ResponseType: model.CommandResponseTypeEphemeral}, nil
} }
func (*LoadTestProvider) JsonCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) (*model.CommandResponse, error) { func (*LoadTestProvider) JsonCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) (*model.CommandResponse, error) {
url := strings.TrimSpace(strings.TrimPrefix(message, "json")) url := strings.TrimSpace(strings.TrimPrefix(message, "json"))
if url == "" { if url == "" {
return &model.CommandResponse{Text: "Command must contain a url", ResponseType: model.CommandResponseTypeEphemeral}, nil return &model.CommandResponse{Text: "Command must contain a url", ResponseType: model.CommandResponseTypeEphemeral}, nil

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

@@ -35,7 +35,7 @@ func (*LogoutProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comma
} }
} }
func (*LogoutProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*LogoutProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
// Actual logout is handled client side. // Actual logout is handled client side.
return &model.CommandResponse{GotoLocation: "/login"} return &model.CommandResponse{GotoLocation: "/login"}
} }

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

@@ -35,7 +35,7 @@ func (*MeProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command {
} }
} }
func (*MeProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*MeProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
return &model.CommandResponse{ return &model.CommandResponse{
ResponseType: model.CommandResponseTypeInChannel, ResponseType: model.CommandResponseTypeInChannel,
Type: model.PostTypeMe, Type: model.PostTypeMe,

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

@@ -40,7 +40,7 @@ func (*msgProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command
} }
} }
func (*msgProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*msgProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
splitMessage := strings.SplitN(message, " ", 2) splitMessage := strings.SplitN(message, " ", 2)
parsedMessage := "" parsedMessage := ""

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

@@ -37,7 +37,7 @@ func (*MuteProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command
} }
} }
func (*MuteProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*MuteProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
var channel *model.Channel var channel *model.Channel
var noChannelErr *model.AppError var noChannelErr *model.AppError

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

@@ -34,7 +34,7 @@ func (*OfflineProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comm
} }
} }
func (*OfflineProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*OfflineProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
a.SetStatusOffline(args.UserId, true) a.SetStatusOffline(args.UserId, true)
return &model.CommandResponse{ResponseType: model.CommandResponseTypeEphemeral, Text: args.T("api.command_offline.success")} return &model.CommandResponse{ResponseType: model.CommandResponseTypeEphemeral, Text: args.T("api.command_offline.success")}

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

@@ -34,7 +34,7 @@ func (*OnlineProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comma
} }
} }
func (*OnlineProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*OnlineProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
a.SetStatusOnline(args.UserId, true) a.SetStatusOnline(args.UserId, true)
return &model.CommandResponse{ResponseType: model.CommandResponseTypeEphemeral, Text: args.T("api.command_online.success")} return &model.CommandResponse{ResponseType: model.CommandResponseTypeEphemeral, Text: args.T("api.command_online.success")}

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

@@ -69,7 +69,7 @@ func (rp *RemoteProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Co
} }
} }
func (rp *RemoteProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (rp *RemoteProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
if !a.HasPermissionTo(args.UserId, model.PermissionManageSecureConnections) { if !a.HasPermissionTo(args.UserId, model.PermissionManageSecureConnections) {
return responsef(args.T("api.command_remote.permission_required", map[string]any{"Permission": "manage_secure_connections"})) return responsef(args.T("api.command_remote.permission_required", map[string]any{"Permission": "manage_secure_connections"}))
} }

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

@@ -57,15 +57,15 @@ func (*KickProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command
} }
} }
func (*RemoveProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*RemoveProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
return doCommand(a, c, args, message) return doCommand(a, c, args, message)
} }
func (*KickProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*KickProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
return doCommand(a, c, args, message) return doCommand(a, c, args, message)
} }
func doCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func doCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
channel, err := a.GetChannel(c, args.ChannelId) channel, err := a.GetChannel(c, args.ChannelId)
if err != nil { if err != nil {
return &model.CommandResponse{ return &model.CommandResponse{

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

@@ -35,7 +35,7 @@ func (search *SearchProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *mode
} }
} }
func (search *SearchProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (search *SearchProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
// This command is handled client-side and shouldn't hit the server. // This command is handled client-side and shouldn't hit the server.
return &model.CommandResponse{ return &model.CommandResponse{
Text: args.T("api.command_search.unsupported.app_error"), Text: args.T("api.command_search.unsupported.app_error"),

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

@@ -35,7 +35,7 @@ func (settings *SettingsProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *
} }
} }
func (settings *SettingsProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (settings *SettingsProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
// This command is handled client-side and shouldn't hit the server. // This command is handled client-side and shouldn't hit the server.
return &model.CommandResponse{ return &model.CommandResponse{
Text: args.T("api.command_settings.unsupported.app_error"), Text: args.T("api.command_settings.unsupported.app_error"),

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

@@ -120,7 +120,7 @@ func (sp *ShareProvider) getAutoCompleteUnInviteRemote(a *app.App, _ *model.Comm
} }
} }
func (sp *ShareProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (sp *ShareProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
if !a.HasPermissionTo(args.UserId, model.PermissionManageSharedChannels) { if !a.HasPermissionTo(args.UserId, model.PermissionManageSharedChannels) {
return responsef(args.T("api.command_share.permission_required", map[string]any{"Permission": "manage_shared_channels"})) return responsef(args.T("api.command_share.permission_required", map[string]any{"Permission": "manage_shared_channels"}))
} }

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

@@ -35,7 +35,7 @@ func (*ShortcutsProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Co
} }
} }
func (*ShortcutsProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*ShortcutsProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
// This command is handled client-side and shouldn't hit the server. // This command is handled client-side and shouldn't hit the server.
return &model.CommandResponse{ return &model.CommandResponse{
Text: args.T("api.command_shortcuts.unsupported.app_error"), Text: args.T("api.command_shortcuts.unsupported.app_error"),

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

@@ -35,7 +35,7 @@ func (*ShrugProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Comman
} }
} }
func (*ShrugProvider) DoCommand(a *app.App, c *request.Context, args *model.CommandArgs, message string) *model.CommandResponse { func (*ShrugProvider) DoCommand(a *app.App, c request.CTX, args *model.CommandArgs, message string) *model.CommandResponse {
rmsg := `¯\\\_(ツ)\_/¯` rmsg := `¯\\\_(ツ)\_/¯`
if message != "" { if message != "" {
rmsg = message + " " + rmsg rmsg = message + " " + rmsg

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

@@ -525,7 +525,7 @@ func TestMentionsToTeamMembers(t *testing.T) {
} }
for _, data := range fixture { for _, data := range fixture {
actualMap := th.App.MentionsToTeamMembers(data.message, data.inTeam) actualMap := th.App.MentionsToTeamMembers(th.Context, data.message, data.inTeam)
require.Equal(t, actualMap, data.expectedMap) require.Equal(t, actualMap, data.expectedMap)
} }
} }

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

@@ -65,7 +65,7 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
options = append(options, app.ConfigStore(memoryStore)) options = append(options, app.ConfigStore(memoryStore))
if includeCacheLayer { if includeCacheLayer {
options = append(options, app.StoreOverride(func(s *app.Server) store.Store { options = append(options, app.StoreOverride(func(s *app.Server) store.Store {
lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.GetMetrics(), s.Cluster, s.CacheProvider)
if err2 != nil { if err2 != nil {
panic(err2) panic(err2)
} }

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

@@ -18,7 +18,7 @@ import (
// only that channel's members are created. If channelID is nil all channel memberships are created. // only that channel's members are created. If channelID is nil all channel memberships are created.
// If includeRemovedMembers is true, then channel members who left or were removed from the channel will // If includeRemovedMembers is true, then channel members who left or were removed from the channel will
// be re-added; otherwise, they will not be re-added. // be re-added; otherwise, they will not be re-added.
func (a *App) createDefaultChannelMemberships(c *request.Context, since int64, channelID *string, includeRemovedMembers bool) error { func (a *App) createDefaultChannelMemberships(c request.CTX, since int64, channelID *string, includeRemovedMembers bool) error {
channelMembers, appErr := a.ChannelMembersToAdd(since, channelID, includeRemovedMembers) channelMembers, appErr := a.ChannelMembersToAdd(since, channelID, includeRemovedMembers)
if appErr != nil { if appErr != nil {
return appErr return appErr
@@ -40,7 +40,7 @@ func (a *App) createDefaultChannelMemberships(c *request.Context, since int64, c
_, err = a.AddTeamMember(c, channel.TeamId, userChannel.UserID) _, err = a.AddTeamMember(c, channel.TeamId, userChannel.UserID)
if err != nil { if err != nil {
if err.Id == "api.team.join_user_to_team.allowed_domains.app_error" { if err.Id == "api.team.join_user_to_team.allowed_domains.app_error" {
a.Log().Info("User not added to channel - the domain associated with the user is not in the list of allowed team domains", c.Logger().Info("User not added to channel - the domain associated with the user is not in the list of allowed team domains",
mlog.String("user_id", userChannel.UserID), mlog.String("user_id", userChannel.UserID),
mlog.String("channel_id", userChannel.ChannelID), mlog.String("channel_id", userChannel.ChannelID),
mlog.String("team_id", channel.TeamId), mlog.String("team_id", channel.TeamId),
@@ -49,7 +49,7 @@ func (a *App) createDefaultChannelMemberships(c *request.Context, since int64, c
} }
return err return err
} }
a.Log().Info("added teammember", c.Logger().Info("added teammember",
mlog.String("user_id", userChannel.UserID), mlog.String("user_id", userChannel.UserID),
mlog.String("team_id", channel.TeamId), mlog.String("team_id", channel.TeamId),
) )
@@ -60,7 +60,7 @@ func (a *App) createDefaultChannelMemberships(c *request.Context, since int64, c
}) })
if err != nil { if err != nil {
if err.Id == "api.channel.add_user.to.channel.failed.deleted.app_error" { if err.Id == "api.channel.add_user.to.channel.failed.deleted.app_error" {
a.Log().Info("Not adding user to channel because they have already left the team", c.Logger().Info("Not adding user to channel because they have already left the team",
mlog.String("user_id", userChannel.UserID), mlog.String("user_id", userChannel.UserID),
mlog.String("channel_id", userChannel.ChannelID), mlog.String("channel_id", userChannel.ChannelID),
) )
@@ -69,7 +69,7 @@ func (a *App) createDefaultChannelMemberships(c *request.Context, since int64, c
} }
} }
a.Log().Info("added channelmember", c.Logger().Info("added channelmember",
mlog.String("user_id", userChannel.UserID), mlog.String("user_id", userChannel.UserID),
mlog.String("channel_id", userChannel.ChannelID), mlog.String("channel_id", userChannel.ChannelID),
) )
@@ -83,7 +83,7 @@ func (a *App) createDefaultChannelMemberships(c *request.Context, since int64, c
// only that team's members are created. If teamID is nil all team memberships are created. // only that team's members are created. If teamID is nil all team memberships are created.
// If includeRemovedMembers is true, then team members who left or were removed from the team will // If includeRemovedMembers is true, then team members who left or were removed from the team will
// be re-added; otherwise, they will not be re-added. // be re-added; otherwise, they will not be re-added.
func (a *App) createDefaultTeamMemberships(c *request.Context, since int64, teamID *string, includeRemovedMembers bool) error { func (a *App) createDefaultTeamMemberships(c request.CTX, since int64, teamID *string, includeRemovedMembers bool) error {
teamMembers, appErr := a.TeamMembersToAdd(since, teamID, includeRemovedMembers) teamMembers, appErr := a.TeamMembersToAdd(since, teamID, includeRemovedMembers)
if appErr != nil { if appErr != nil {
return appErr return appErr
@@ -93,7 +93,7 @@ func (a *App) createDefaultTeamMemberships(c *request.Context, since int64, team
_, err := a.AddTeamMember(c, userTeam.TeamID, userTeam.UserID) _, err := a.AddTeamMember(c, userTeam.TeamID, userTeam.UserID)
if err != nil { if err != nil {
if err.Id == "api.team.join_user_to_team.allowed_domains.app_error" { if err.Id == "api.team.join_user_to_team.allowed_domains.app_error" {
a.Log().Info("User not added to team - the domain associated with the user is not in the list of allowed team domains", c.Logger().Info("User not added to team - the domain associated with the user is not in the list of allowed team domains",
mlog.String("user_id", userTeam.UserID), mlog.String("user_id", userTeam.UserID),
mlog.String("team_id", userTeam.TeamID), mlog.String("team_id", userTeam.TeamID),
) )
@@ -102,7 +102,7 @@ func (a *App) createDefaultTeamMemberships(c *request.Context, since int64, team
return err return err
} }
a.Log().Info("added teammember", c.Logger().Info("added teammember",
mlog.String("user_id", userTeam.UserID), mlog.String("user_id", userTeam.UserID),
mlog.String("team_id", userTeam.TeamID), mlog.String("team_id", userTeam.TeamID),
) )
@@ -148,7 +148,7 @@ func (a *App) DeleteGroupConstrainedMemberships(c *request.Context) error {
// deleteGroupConstrainedTeamMemberships deletes team memberships of users who aren't members of the allowed // deleteGroupConstrainedTeamMemberships deletes team memberships of users who aren't members of the allowed
// groups of the given group-constrained team. If a teamID is given then the procedure is scoped to the given team, // groups of the given group-constrained team. If a teamID is given then the procedure is scoped to the given team,
// if teamID is nil then the procedure affects all teams. // if teamID is nil then the procedure affects all teams.
func (a *App) deleteGroupConstrainedTeamMemberships(c *request.Context, teamID *string) error { func (a *App) deleteGroupConstrainedTeamMemberships(c request.CTX, teamID *string) error {
teamMembers, appErr := a.TeamMembersToRemove(teamID) teamMembers, appErr := a.TeamMembersToRemove(teamID)
if appErr != nil { if appErr != nil {
return appErr return appErr
@@ -160,7 +160,7 @@ func (a *App) deleteGroupConstrainedTeamMemberships(c *request.Context, teamID *
return err return err
} }
a.Log().Info("removed teammember", c.Logger().Info("removed teammember",
mlog.String("user_id", userTeam.UserId), mlog.String("user_id", userTeam.UserId),
mlog.String("team_id", userTeam.TeamId), mlog.String("team_id", userTeam.TeamId),
) )
@@ -172,7 +172,7 @@ func (a *App) deleteGroupConstrainedTeamMemberships(c *request.Context, teamID *
// deleteGroupConstrainedChannelMemberships deletes channel memberships of users who aren't members of the allowed // deleteGroupConstrainedChannelMemberships deletes channel memberships of users who aren't members of the allowed
// groups of the given group-constrained channel. If a channelID is given then the procedure is scoped to the given team, // groups of the given group-constrained channel. If a channelID is given then the procedure is scoped to the given team,
// if channelID is nil then the procedure affects all teams. // if channelID is nil then the procedure affects all teams.
func (a *App) deleteGroupConstrainedChannelMemberships(c *request.Context, channelID *string) error { func (a *App) deleteGroupConstrainedChannelMemberships(c request.CTX, channelID *string) error {
channelMembers, appErr := a.ChannelMembersToRemove(channelID) channelMembers, appErr := a.ChannelMembersToRemove(channelID)
if appErr != nil { if appErr != nil {
return appErr return appErr
@@ -233,7 +233,7 @@ func (a *App) SyncSyncableRoles(syncableID string, syncableType model.GroupSynca
// SyncRolesAndMembership updates the SchemeAdmin status and membership of all of the members of the given // SyncRolesAndMembership updates the SchemeAdmin status and membership of all of the members of the given
// syncable. // syncable.
func (a *App) SyncRolesAndMembership(c *request.Context, syncableID string, syncableType model.GroupSyncableType, includeRemovedMembers bool) { func (a *App) SyncRolesAndMembership(c request.CTX, syncableID string, syncableType model.GroupSyncableType, includeRemovedMembers bool) {
a.SyncSyncableRoles(syncableID, syncableType) a.SyncSyncableRoles(syncableID, syncableType)
lastJob, _ := a.Srv().Store.Job().GetNewestJobByStatusAndType(model.JobStatusSuccess, model.JobTypeLdapSync) lastJob, _ := a.Srv().Store.Job().GetNewestJobByStatusAndType(model.JobStatusSuccess, model.JobTypeLdapSync)
@@ -246,10 +246,14 @@ func (a *App) SyncRolesAndMembership(c *request.Context, syncableID string, sync
case model.GroupSyncableTypeTeam: case model.GroupSyncableTypeTeam:
a.createDefaultTeamMemberships(c, since, &syncableID, includeRemovedMembers) a.createDefaultTeamMemberships(c, since, &syncableID, includeRemovedMembers)
a.deleteGroupConstrainedTeamMemberships(c, &syncableID) a.deleteGroupConstrainedTeamMemberships(c, &syncableID)
a.ClearTeamMembersCache(syncableID) if err := a.ClearTeamMembersCache(syncableID); err != nil {
c.Logger().Warn("Error clearing team members cache", mlog.Err(err))
}
case model.GroupSyncableTypeChannel: case model.GroupSyncableTypeChannel:
a.createDefaultChannelMemberships(c, since, &syncableID, includeRemovedMembers) a.createDefaultChannelMemberships(c, since, &syncableID, includeRemovedMembers)
a.deleteGroupConstrainedChannelMemberships(c, &syncableID) a.deleteGroupConstrainedChannelMemberships(c, &syncableID)
a.ClearChannelMembersCache(c, syncableID) if err := a.ClearChannelMembersCache(c, syncableID); err != nil {
c.Logger().Warn("Error clearing channel members cache", mlog.Err(err))
}
} }
} }

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

@@ -231,7 +231,9 @@ func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) {
} }
} }
a.sendTeamEvent(oldTeam, model.WebsocketEventUpdateTeam) if appErr := a.sendTeamEvent(oldTeam, model.WebsocketEventUpdateTeam); appErr != nil {
return nil, appErr
}
return oldTeam, nil return oldTeam, nil
} }
@@ -301,9 +303,14 @@ func (a *App) UpdateTeamScheme(team *model.Team) (*model.Team, *model.AppError)
} }
} }
a.ClearTeamMembersCache(team.Id) nErr = a.ClearTeamMembersCache(team.Id)
if nErr != nil {
return nil, model.NewAppError("UpdateTeamScheme", "app.team.clear_cache.app_error", nil, "", http.StatusInternalServerError).Wrap(nErr)
}
a.sendTeamEvent(oldTeam, model.WebsocketEventUpdateTeamScheme) if appErr := a.sendTeamEvent(oldTeam, model.WebsocketEventUpdateTeamScheme); appErr != nil {
return nil, appErr
}
return oldTeam, nil return oldTeam, nil
} }
@@ -336,7 +343,9 @@ func (a *App) UpdateTeamPrivacy(teamID string, teamType string, allowOpenInvite
} }
} }
a.sendTeamEvent(oldTeam, model.WebsocketEventUpdateTeam) if appErr := a.sendTeamEvent(oldTeam, model.WebsocketEventUpdateTeam); appErr != nil {
return appErr
}
return nil return nil
} }
@@ -362,7 +371,9 @@ func (a *App) PatchTeam(teamID string, patch *model.TeamPatch) (*model.Team, *mo
} }
} }
a.sendTeamEvent(team, model.WebsocketEventUpdateTeam) if appErr := a.sendTeamEvent(team, model.WebsocketEventUpdateTeam); appErr != nil {
return nil, appErr
}
return team, nil return team, nil
} }
@@ -389,12 +400,14 @@ func (a *App) RegenerateTeamInviteId(teamID string) (*model.Team, *model.AppErro
} }
} }
a.sendTeamEvent(updatedTeam, model.WebsocketEventUpdateTeam) if appErr := a.sendTeamEvent(updatedTeam, model.WebsocketEventUpdateTeam); appErr != nil {
return nil, appErr
}
return updatedTeam, nil return updatedTeam, nil
} }
func (a *App) sendTeamEvent(team *model.Team, event string) { func (a *App) sendTeamEvent(team *model.Team, event string) *model.AppError {
sanitizedTeam := &model.Team{} sanitizedTeam := &model.Team{}
*sanitizedTeam = *team *sanitizedTeam = *team
sanitizedTeam.Sanitize() sanitizedTeam.Sanitize()
@@ -407,10 +420,11 @@ func (a *App) sendTeamEvent(team *model.Team, event string) {
message := model.NewWebSocketEvent(event, teamID, "", "", nil) message := model.NewWebSocketEvent(event, teamID, "", "", nil)
teamJSON, jsonErr := json.Marshal(team) teamJSON, jsonErr := json.Marshal(team)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode team to JSON", mlog.Err(jsonErr)) return model.NewAppError("sendTeamEvent", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message.Add("team", string(teamJSON)) message.Add("team", string(teamJSON))
a.Publish(message) a.Publish(message)
return nil
} }
func (a *App) GetSchemeRolesForTeam(teamID string) (string, string, string, *model.AppError) { func (a *App) GetSchemeRolesForTeam(teamID string) (string, string, string, *model.AppError) {
@@ -507,7 +521,9 @@ func (a *App) UpdateTeamMemberRoles(teamID string, userID string, newRoles strin
a.ClearSessionCacheForUser(userID) a.ClearSessionCacheForUser(userID)
a.sendUpdatedMemberRoleEvent(userID, member) if appErr := a.sendUpdatedMemberRoleEvent(userID, member); appErr != nil {
return nil, appErr
}
return member, nil return member, nil
} }
@@ -544,22 +560,25 @@ func (a *App) UpdateTeamMemberSchemeRoles(teamID string, userID string, isScheme
a.ClearSessionCacheForUser(userID) a.ClearSessionCacheForUser(userID)
a.sendUpdatedMemberRoleEvent(userID, member) if appErr := a.sendUpdatedMemberRoleEvent(userID, member); appErr != nil {
return nil, appErr
}
return member, nil return member, nil
} }
func (a *App) sendUpdatedMemberRoleEvent(userID string, member *model.TeamMember) { func (a *App) sendUpdatedMemberRoleEvent(userID string, member *model.TeamMember) *model.AppError {
message := model.NewWebSocketEvent(model.WebsocketEventMemberroleUpdated, "", "", userID, nil) message := model.NewWebSocketEvent(model.WebsocketEventMemberroleUpdated, "", "", userID, nil)
tmJSON, jsonErr := json.Marshal(member) tmJSON, jsonErr := json.Marshal(member)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode team member to JSON", mlog.Err(jsonErr)) return model.NewAppError("sendUpdatedMemberRoleEvent", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message.Add("member", string(tmJSON)) message.Add("member", string(tmJSON))
a.Publish(message) a.Publish(message)
return nil
} }
func (a *App) AddUserToTeam(c *request.Context, teamID string, userID string, userRequestorId string) (*model.Team, *model.TeamMember, *model.AppError) { func (a *App) AddUserToTeam(c request.CTX, teamID string, userID string, userRequestorId string) (*model.Team, *model.TeamMember, *model.AppError) {
tchan := make(chan store.StoreResult, 1) tchan := make(chan store.StoreResult, 1)
go func() { go func() {
team, err := a.Srv().Store.Team().Get(teamID) team, err := a.Srv().Store.Team().Get(teamID)
@@ -1059,7 +1078,7 @@ func (a *App) GetCommonTeamIDsForTwoUsers(userID, otherUserID string) ([]string,
return teamIDs, nil return teamIDs, nil
} }
func (a *App) AddTeamMember(c *request.Context, teamID, userID string) (*model.TeamMember, *model.AppError) { func (a *App) AddTeamMember(c request.CTX, teamID, userID string) (*model.TeamMember, *model.AppError) {
_, teamMember, err := a.AddUserToTeam(c, teamID, userID, "") _, teamMember, err := a.AddUserToTeam(c, teamID, userID, "")
if err != nil { if err != nil {
return nil, err return nil, err
@@ -1152,7 +1171,7 @@ func (a *App) GetTeamUnread(teamID, userID string) (*model.TeamUnread, *model.Ap
return teamUnread, nil return teamUnread, nil
} }
func (a *App) RemoveUserFromTeam(c *request.Context, teamID string, userID string, requestorId string) *model.AppError { func (a *App) RemoveUserFromTeam(c request.CTX, teamID string, userID string, requestorId string) *model.AppError {
tchan := make(chan store.StoreResult, 1) tchan := make(chan store.StoreResult, 1)
go func() { go func() {
team, err := a.Srv().Store.Team().Get(teamID) team, err := a.Srv().Store.Team().Get(teamID)
@@ -1245,7 +1264,7 @@ func (a *App) postProcessTeamMemberLeave(c request.CTX, teamMember *model.TeamMe
return nil return nil
} }
func (a *App) LeaveTeam(c *request.Context, team *model.Team, user *model.User, requestorId string) *model.AppError { func (a *App) LeaveTeam(c request.CTX, team *model.Team, user *model.User, requestorId string) *model.AppError {
teamMember, err := a.GetTeamMember(team.Id, user.Id) teamMember, err := a.GetTeamMember(team.Id, user.Id)
if err != nil { if err != nil {
return model.NewAppError("LeaveTeam", "api.team.remove_user_from_team.missing.app_error", nil, err.Error(), http.StatusBadRequest) return model.NewAppError("LeaveTeam", "api.team.remove_user_from_team.missing.app_error", nil, err.Error(), http.StatusBadRequest)
@@ -1288,11 +1307,11 @@ func (a *App) LeaveTeam(c *request.Context, team *model.Team, user *model.User,
if requestorId == user.Id { if requestorId == user.Id {
if err = a.postLeaveTeamMessage(c, user, channel); err != nil { if err = a.postLeaveTeamMessage(c, user, channel); err != nil {
mlog.Warn("Failed to post join/leave message", mlog.Err(err)) c.Logger().Warn("Failed to post join/leave message", mlog.Err(err))
} }
} else { } else {
if err = a.postRemoveFromTeamMessage(c, user, channel); err != nil { if err = a.postRemoveFromTeamMessage(c, user, channel); err != nil {
mlog.Warn("Failed to post join/leave message", mlog.Err(err)) c.Logger().Warn("Failed to post join/leave message", mlog.Err(err))
} }
} }
} }
@@ -1308,7 +1327,7 @@ func (a *App) LeaveTeam(c *request.Context, team *model.Team, user *model.User,
return nil return nil
} }
func (a *App) postLeaveTeamMessage(c *request.Context, user *model.User, channel *model.Channel) *model.AppError { func (a *App) postLeaveTeamMessage(c request.CTX, user *model.User, channel *model.Channel) *model.AppError {
post := &model.Post{ post := &model.Post{
ChannelId: channel.Id, ChannelId: channel.Id,
Message: fmt.Sprintf(i18n.T("api.team.leave.left"), user.Username), Message: fmt.Sprintf(i18n.T("api.team.leave.left"), user.Username),
@@ -1326,7 +1345,7 @@ func (a *App) postLeaveTeamMessage(c *request.Context, user *model.User, channel
return nil return nil
} }
func (a *App) postRemoveFromTeamMessage(c *request.Context, user *model.User, channel *model.Channel) *model.AppError { func (a *App) postRemoveFromTeamMessage(c request.CTX, user *model.User, channel *model.Channel) *model.AppError {
post := &model.Post{ post := &model.Post{
ChannelId: channel.Id, ChannelId: channel.Id,
Message: fmt.Sprintf(i18n.T("api.team.remove_user_from_team.removed"), user.Username), Message: fmt.Sprintf(i18n.T("api.team.remove_user_from_team.removed"), user.Username),
@@ -1797,7 +1816,9 @@ func (a *App) PermanentDeleteTeam(c request.CTX, team *model.Team) *model.AppErr
return model.NewAppError("PermanentDeleteTeam", "app.team.permanent_delete.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("PermanentDeleteTeam", "app.team.permanent_delete.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
a.sendTeamEvent(team, model.WebsocketEventDeleteTeam) if appErr := a.sendTeamEvent(team, model.WebsocketEventDeleteTeam); appErr != nil {
return appErr
}
return nil return nil
} }
@@ -1823,7 +1844,9 @@ func (a *App) SoftDeleteTeam(teamID string) *model.AppError {
} }
} }
a.sendTeamEvent(team, model.WebsocketEventDeleteTeam) if appErr := a.sendTeamEvent(team, model.WebsocketEventDeleteTeam); appErr != nil {
return appErr
}
return nil return nil
} }
@@ -1849,7 +1872,10 @@ func (a *App) RestoreTeam(teamID string) *model.AppError {
} }
} }
a.sendTeamEvent(team, model.WebsocketEventRestoreTeam) if appErr := a.sendTeamEvent(team, model.WebsocketEventRestoreTeam); appErr != nil {
return appErr
}
return nil return nil
} }
@@ -2022,7 +2048,9 @@ func (a *App) SetTeamIconFromFile(team *model.Team, file io.Reader) *model.AppEr
// manually set time to avoid possible cluster inconsistencies // manually set time to avoid possible cluster inconsistencies
team.LastTeamIconUpdate = curTime team.LastTeamIconUpdate = curTime
a.sendTeamEvent(team, model.WebsocketEventUpdateTeam) if appErr := a.sendTeamEvent(team, model.WebsocketEventUpdateTeam); appErr != nil {
return appErr
}
return nil return nil
} }
@@ -2039,7 +2067,9 @@ func (a *App) RemoveTeamIcon(teamID string) *model.AppError {
team.LastTeamIconUpdate = 0 team.LastTeamIconUpdate = 0
a.sendTeamEvent(team, model.WebsocketEventUpdateTeam) if appErr := a.sendTeamEvent(team, model.WebsocketEventUpdateTeam); appErr != nil {
return appErr
}
return nil return nil
} }
@@ -2072,15 +2102,14 @@ func (a *App) InvalidateAllResendInviteEmailJobs() *model.AppError {
return nil return nil
} }
func (a *App) ClearTeamMembersCache(teamID string) { func (a *App) ClearTeamMembersCache(teamID string) error {
perPage := 100 perPage := 100
page := 0 page := 0
for { for {
teamMembers, err := a.Srv().Store.Team().GetMembers(teamID, page*perPage, perPage, nil) teamMembers, err := a.Srv().Store.Team().GetMembers(teamID, page*perPage, perPage, nil)
if err != nil { if err != nil {
a.Log().Warn("error clearing cache for team members", mlog.String("team_id", teamID), mlog.String("err", err.Error())) return fmt.Errorf("failed to get team members: %v", err)
break
} }
for _, teamMember := range teamMembers { for _, teamMember := range teamMembers {
@@ -2089,7 +2118,7 @@ func (a *App) ClearTeamMembersCache(teamID string) {
message := model.NewWebSocketEvent(model.WebsocketEventMemberroleUpdated, "", "", teamMember.UserId, nil) message := model.NewWebSocketEvent(model.WebsocketEventMemberroleUpdated, "", "", teamMember.UserId, nil)
tmJSON, jsonErr := json.Marshal(teamMember) tmJSON, jsonErr := json.Marshal(teamMember)
if jsonErr != nil { if jsonErr != nil {
mlog.Warn("Failed to encode team member to JSON", mlog.Err(jsonErr)) return jsonErr
} }
message.Add("member", string(tmJSON)) message.Add("member", string(tmJSON))
a.Publish(message) a.Publish(message)
@@ -2102,4 +2131,5 @@ func (a *App) ClearTeamMembersCache(teamID string) {
page++ page++
} }
return nil
} }

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

@@ -1433,7 +1433,7 @@ func TestClearTeamMembersCache(t *testing.T) {
mockStore.On("Team").Return(&mockTeamStore) mockStore.On("Team").Return(&mockTeamStore)
mockStore.On("GetDBSchemaVersion").Return(1, nil) mockStore.On("GetDBSchemaVersion").Return(1, nil)
th.App.ClearTeamMembersCache("teamID") require.NoError(t, th.App.ClearTeamMembersCache("teamID"))
} }
func TestInviteNewUsersToTeamGracefully(t *testing.T) { func TestInviteNewUsersToTeamGracefully(t *testing.T) {

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

@@ -883,7 +883,7 @@ func (a *App) UpdatePasswordAsUser(c request.CTX, userID, currentPassword, newPa
return a.UpdatePasswordSendEmail(c, user, newPassword, T("api.user.update_password.menu")) return a.UpdatePasswordSendEmail(c, user, newPassword, T("api.user.update_password.menu"))
} }
func (a *App) userDeactivated(c *request.Context, userID string) *model.AppError { func (a *App) userDeactivated(c request.CTX, userID string) *model.AppError {
a.SetStatusOffline(userID, false) a.SetStatusOffline(userID, false)
user, err := a.GetUser(userID) user, err := a.GetUser(userID)
@@ -928,7 +928,7 @@ func (a *App) invalidateUserChannelMembersCaches(c request.CTX, userID string) *
return nil return nil
} }
func (a *App) UpdateActive(c *request.Context, user *model.User, active bool) (*model.User, *model.AppError) { func (a *App) UpdateActive(c request.CTX, user *model.User, active bool) (*model.User, *model.AppError) {
user.UpdateAt = model.GetMillis() user.UpdateAt = model.GetMillis()
if active { if active {
user.DeleteAt = 0 user.DeleteAt = 0
@@ -1220,7 +1220,7 @@ func (a *App) UpdateUser(c request.CTX, user *model.User, sendNotifications bool
return userUpdate.New, nil return userUpdate.New, nil
} }
func (a *App) UpdateUserActive(c *request.Context, userID string, active bool) *model.AppError { func (a *App) UpdateUserActive(c request.CTX, userID string, active bool) *model.AppError {
user, err := a.GetUser(userID) user, err := a.GetUser(userID)
if err != nil { if err != nil {
@@ -1416,7 +1416,6 @@ func (a *App) CreatePasswordRecoveryToken(userID, email string) (*model.Token, *
email, email,
} }
jsonData, err := json.Marshal(tokenExtra) jsonData, err := json.Marshal(tokenExtra)
if err != nil { if err != nil {
return nil, model.NewAppError("CreatePasswordRecoveryToken", "api.user.create_password_token.error", nil, "", http.StatusInternalServerError) return nil, model.NewAppError("CreatePasswordRecoveryToken", "api.user.create_password_token.error", nil, "", http.StatusInternalServerError)
} }
@@ -2196,7 +2195,7 @@ func (a *App) PromoteGuestToUser(c *request.Context, user *model.User, requestor
evt := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", user.Id, nil) evt := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", user.Id, nil)
memberJSON, jsonErr := json.Marshal(member) memberJSON, jsonErr := json.Marshal(member)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode channel member to JSON", mlog.Err(jsonErr)) return model.NewAppError("PromoteGuestToUser", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
evt.Add("channelMember", string(memberJSON)) evt.Add("channelMember", string(memberJSON))
a.Publish(evt) a.Publish(evt)
@@ -2241,7 +2240,7 @@ func (a *App) DemoteUserToGuest(c request.CTX, user *model.User) *model.AppError
evt := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", user.Id, nil) evt := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", user.Id, nil)
memberJSON, jsonErr := json.Marshal(member) memberJSON, jsonErr := json.Marshal(member)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode channel member to JSON", mlog.Err(jsonErr)) return model.NewAppError("DemoteUserToGuest", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
evt.Add("channelMember", string(memberJSON)) evt.Add("channelMember", string(memberJSON))
a.Publish(evt) a.Publish(evt)
@@ -2518,7 +2517,7 @@ func (a *App) UpdateThreadFollowForUserFromChannelAdd(c request.CTX, userID, tea
payload, jsonErr := json.Marshal(userThread) payload, jsonErr := json.Marshal(userThread)
if jsonErr != nil { if jsonErr != nil {
c.Logger().Warn("Failed to encode thread to JSON") return model.NewAppError("UpdateThreadFollowForUserFromChannelAdd", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
} }
message.Add("thread", string(payload)) message.Add("thread", string(payload))
message.Add("previous_unread_replies", int64(0)) message.Add("previous_unread_replies", int64(0))

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

@@ -157,8 +157,8 @@ func (a *App) HubUnregister(webConn *WebConn) {
} }
func (s *Server) Publish(message *model.WebSocketEvent) { func (s *Server) Publish(message *model.WebSocketEvent) {
if s.Metrics != nil { if s.GetMetrics() != nil {
s.Metrics.IncrementWebsocketEvent(message.EventType()) s.GetMetrics().IncrementWebsocketEvent(message.EventType())
} }
s.PublishSkipClusterSend(message) s.PublishSkipClusterSend(message)
@@ -357,7 +357,7 @@ func (h *Hub) Broadcast(message *model.WebSocketEvent) {
// And possibly, we can look into doing the hub initialization inside // And possibly, we can look into doing the hub initialization inside
// NewServer itself. // NewServer itself.
if h != nil && message != nil { if h != nil && message != nil {
if metrics := h.srv.Metrics; metrics != nil { if metrics := h.srv.GetMetrics(); metrics != nil {
metrics.IncrementWebSocketBroadcastBufferSize(strconv.Itoa(h.connectionIndex), 1) metrics.IncrementWebSocketBroadcastBufferSize(strconv.Itoa(h.connectionIndex), 1)
} }
select { select {
@@ -525,7 +525,7 @@ func (h *Hub) Start() {
connIndex.Remove(directMsg.conn) connIndex.Remove(directMsg.conn)
} }
case msg := <-h.broadcast: case msg := <-h.broadcast:
if metrics := h.srv.Metrics; metrics != nil { if metrics := h.srv.GetMetrics(); metrics != nil {
metrics.DecrementWebSocketBroadcastBufferSize(strconv.Itoa(h.connectionIndex), 1) metrics.DecrementWebSocketBroadcastBufferSize(strconv.Itoa(h.connectionIndex), 1)
} }
msg = msg.PrecomputeJSON() msg = msg.PrecomputeJSON()

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

@@ -10,6 +10,7 @@ import (
"path/filepath" "path/filepath"
"time" "time"
"github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/audit" "github.com/mattermost/mattermost-server/v6/audit"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
@@ -229,7 +230,7 @@ func bulkExportCmdF(command *cobra.Command, args []string) error {
var opts model.BulkExportOpts var opts model.BulkExportOpts
opts.IncludeAttachments = attachments opts.IncludeAttachments = attachments
opts.CreateArchive = archive opts.CreateArchive = archive
if err := a.BulkExport(fileWriter, filepath.Dir(outPath), opts); err != nil { if err := a.BulkExport(request.EmptyContext(a.Log()), fileWriter, filepath.Dir(outPath), opts); err != nil {
CommandPrintErrorln(err.Error()) CommandPrintErrorln(err.Error())
return err return err
} }

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

@@ -2045,10 +2045,6 @@
"id": "api.license.request_trial_license.fail_get_user_count.app_error", "id": "api.license.request_trial_license.fail_get_user_count.app_error",
"translation": "Unable to get a trial license, please try again or contact with support@mattermost.com. Cannot obtain the number of registered users." "translation": "Unable to get a trial license, please try again or contact with support@mattermost.com. Cannot obtain the number of registered users."
}, },
{
"id": "api.license.request_trial_license.no-site-url.app_error",
"translation": "Unable to request a trial license. Please configure a Site URL in the web server section of the Mattermost System Console."
},
{ {
"id": "api.license.upgrade_needed.app_error", "id": "api.license.upgrade_needed.app_error",
"translation": "Feature requires an upgrade to Enterprise Edition." "translation": "Feature requires an upgrade to Enterprise Edition."
@@ -6155,6 +6151,10 @@
"id": "app.team.clear_all_custom_role_assignments.select.app_error", "id": "app.team.clear_all_custom_role_assignments.select.app_error",
"translation": "Failed to retrieve the team members." "translation": "Failed to retrieve the team members."
}, },
{
"id": "app.team.clear_cache.app_error",
"translation": "Error clearing team member cache"
},
{ {
"id": "app.team.get.find.app_error", "id": "app.team.get.find.app_error",
"translation": "Unable to find the existing team." "translation": "Unable to find the existing team."

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

@@ -7,6 +7,7 @@ import (
"io" "io"
"path/filepath" "path/filepath"
"github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/jobs" "github.com/mattermost/mattermost-server/v6/jobs"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/services/configservice" "github.com/mattermost/mattermost-server/v6/services/configservice"
@@ -18,7 +19,8 @@ const jobName = "ExportProcess"
type AppIface interface { type AppIface interface {
configservice.ConfigService configservice.ConfigService
WriteFile(fr io.Reader, path string) (int64, *model.AppError) WriteFile(fr io.Reader, path string) (int64, *model.AppError)
BulkExport(writer io.Writer, outPath string, opts model.BulkExportOpts) *model.AppError BulkExport(ctx request.CTX, writer io.Writer, outPath string, opts model.BulkExportOpts) *model.AppError
Log() *mlog.Logger
} }
func MakeWorker(jobServer *jobs.JobServer, app AppIface) model.Worker { func MakeWorker(jobServer *jobs.JobServer, app AppIface) model.Worker {
@@ -45,7 +47,7 @@ func MakeWorker(jobServer *jobs.JobServer, app AppIface) model.Worker {
errCh <- appErr errCh <- appErr
}() }()
appErr := app.BulkExport(wr, outPath, opts) appErr := app.BulkExport(request.EmptyContext(app.Log()), wr, outPath, opts)
if err := wr.Close(); err != nil { if err := wr.Close(); err != nil {
mlog.Warn("Worker: error closing writer") mlog.Warn("Worker: error closing writer")
} }

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

@@ -98,11 +98,11 @@ func (f *FeatureFlags) SetDefaults() {
f.GraphQL = false f.GraphQL = false
f.InsightsEnabled = true f.InsightsEnabled = true
f.CommandPalette = false f.CommandPalette = false
f.PostForwarding = false f.PostForwarding = true
f.AdvancedTextEditor = true f.AdvancedTextEditor = true
f.CallsEnabled = true f.CallsEnabled = true
f.BoardsProduct = false f.BoardsProduct = false
f.PlanUpgradeButtonText = "Upgrade" f.PlanUpgradeButtonText = "upgrade"
} }
func (f *FeatureFlags) Plugins() map[string]string { func (f *FeatureFlags) Plugins() map[string]string {

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

@@ -269,13 +269,13 @@ func (_m *MockAppIface) InvalidateCacheForUser(userID string) {
_m.Called(userID) _m.Called(userID)
} }
// MentionsToTeamMembers provides a mock function with given fields: message, teamID // MentionsToTeamMembers provides a mock function with given fields: c, message, teamID
func (_m *MockAppIface) MentionsToTeamMembers(message string, teamID string) model.UserMentionMap { func (_m *MockAppIface) MentionsToTeamMembers(c request.CTX, message string, teamID string) model.UserMentionMap {
ret := _m.Called(message, teamID) ret := _m.Called(c, message, teamID)
var r0 model.UserMentionMap var r0 model.UserMentionMap
if rf, ok := ret.Get(0).(func(string, string) model.UserMentionMap); ok { if rf, ok := ret.Get(0).(func(request.CTX, string, string) model.UserMentionMap); ok {
r0 = rf(message, teamID) r0 = rf(c, message, teamID)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(model.UserMentionMap) r0 = ret.Get(0).(model.UserMentionMap)

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

@@ -59,7 +59,7 @@ type AppIface interface {
PatchChannelModerationsForChannel(c request.CTX, channel *model.Channel, channelModerationsPatch []*model.ChannelModerationPatch) ([]*model.ChannelModeration, *model.AppError) PatchChannelModerationsForChannel(c request.CTX, channel *model.Channel, channelModerationsPatch []*model.ChannelModerationPatch) ([]*model.ChannelModeration, *model.AppError)
CreateUploadSession(c request.CTX, us *model.UploadSession) (*model.UploadSession, *model.AppError) CreateUploadSession(c request.CTX, us *model.UploadSession) (*model.UploadSession, *model.AppError)
FileReader(path string) (filestore.ReadCloseSeeker, *model.AppError) FileReader(path string) (filestore.ReadCloseSeeker, *model.AppError)
MentionsToTeamMembers(message, teamID string) model.UserMentionMap MentionsToTeamMembers(c request.CTX, message, teamID string) model.UserMentionMap
GetProfileImage(user *model.User) ([]byte, bool, *model.AppError) GetProfileImage(user *model.User) ([]byte, bool, *model.AppError)
InvalidateCacheForUser(userID string) InvalidateCacheForUser(userID string)
NotifySharedChannelUserUpdate(user *model.User) NotifySharedChannelUserUpdate(user *model.User)

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

@@ -11,6 +11,7 @@ import (
"github.com/wiggin77/merror" "github.com/wiggin77/merror"
"github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/services/remotecluster" "github.com/mattermost/mattermost-server/v6/services/remotecluster"
"github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/shared/mlog"
@@ -271,7 +272,7 @@ func (scs *Service) fetchPostUsersForSync(sd *syncData) error {
userIDs[post.UserId] = p2mm{} userIDs[post.UserId] = p2mm{}
// get mentions and users for each mention // get mentions and users for each mention
mentionMap := scs.app.MentionsToTeamMembers(post.Message, sc.TeamId) mentionMap := scs.app.MentionsToTeamMembers(request.EmptyContext(scs.server.GetLogger()), post.Message, sc.TeamId)
for _, userID := range mentionMap { for _, userID := range mentionMap {
userIDs[userID] = p2mm{ userIDs[userID] = p2mm{
post: post, post: post,

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

@@ -368,7 +368,10 @@ func (b *S3FileBackend) WriteFile(fr io.Reader, path string) (int64, error) {
options := s3PutOptions(b.encrypt, contentType) options := s3PutOptions(b.encrypt, contentType)
objSize := -1 objSize := -1
if buf, ok := fr.(*bytes.Buffer); ok { isCloud := os.Getenv("MM_CLOUD_FILESTORE_BIFROST") != ""
// We pass an object size only in situations where bifrost is not
// used. Bifrost needs to run in HTTPS, which is not yet deployed.
if buf, ok := fr.(*bytes.Buffer); ok && !isCloud {
objSize = buf.Len() objSize = buf.Len()
} }
@@ -401,7 +404,10 @@ func (b *S3FileBackend) AppendFile(fr io.Reader, path string) (int64, error) {
ctx2, cancel2 := context.WithTimeout(context.Background(), b.timeout) ctx2, cancel2 := context.WithTimeout(context.Background(), b.timeout)
defer cancel2() defer cancel2()
objSize := -1 objSize := -1
if buf, ok := fr.(*bytes.Buffer); ok { isCloud := os.Getenv("MM_CLOUD_FILESTORE_BIFROST") != ""
// We pass an object size only in situations where bifrost is not
// used. Bifrost needs to run in HTTPS, which is not yet deployed.
if buf, ok := fr.(*bytes.Buffer); ok && !isCloud {
objSize = buf.Len() objSize = buf.Len()
} }
info, err := b.client.PutObject(ctx2, b.bucket, partName, fr, int64(objSize), options) info, err := b.client.PutObject(ctx2, b.bucket, partName, fr, int64(objSize), options)

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

@@ -784,6 +784,13 @@ func (s *SqlPostStore) Get(ctx context.Context, id string, opts model.GetPostsOp
} }
for _, p := range posts { for _, p := range posts {
if p.Id == id {
// Based on the conditions above such as sq.Or{ sq.Eq{"p.Id": rootId}, sq.Eq{"p.RootId": rootId}, }
// posts may contain the "id" post which has already been fetched and added in the "pl"
// So, skip the "id" to avoid duplicate entry of the post
continue
}
pl.AddPost(p) pl.AddPost(p)
pl.AddOrder(p.Id) pl.AddOrder(p.Id)
} }
@@ -2188,7 +2195,7 @@ func (s *SqlPostStore) AnalyticsPostCountsByDay(options *model.AnalyticsPostCoun
func (s *SqlPostStore) AnalyticsPostCount(options *model.PostCountOptions) (int64, error) { func (s *SqlPostStore) AnalyticsPostCount(options *model.PostCountOptions) (int64, error) {
query := s.getQueryBuilder(). query := s.getQueryBuilder().
Select("COUNT(p.Id) AS Value"). Select("COUNT(*) AS Value").
From("Posts p") From("Posts p")
if options.TeamId != "" { if options.TeamId != "" {
@@ -2840,8 +2847,23 @@ func (s *SqlPostStore) updateThreadAfterReplyDeletion(transaction *sqlxTxWrapper
} }
} }
lastReplyAtSubquery := sq.Select("COALESCE(MAX(CreateAt), 0)").
From("Posts").
Where(sq.Eq{
"RootId": rootId,
"DeleteAt": 0,
})
lastReplyCountSubquery := sq.Select("Count(*)").
From("Posts").
Where(sq.Eq{
"RootId": rootId,
"DeleteAt": 0,
})
updateQueryString, updateArgs, err := updateQuery. updateQueryString, updateArgs, err := updateQuery.
Set("ReplyCount", sq.Expr("ReplyCount - 1")). Set("LastReplyAt", lastReplyAtSubquery).
Set("ReplyCount", lastReplyCountSubquery).
Where(sq.And{ Where(sq.And{
sq.Eq{"PostId": rootId}, sq.Eq{"PostId": rootId},
sq.Gt{"ReplyCount": 0}, sq.Gt{"ReplyCount": 0},

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

@@ -1500,17 +1500,20 @@ func generateSearchQuery(query sq.SelectBuilder, terms []string, fields []string
for _, term := range terms { for _, term := range terms {
searchFields := []string{} searchFields := []string{}
termArgs := []any{} termArgs := []any{}
var dbSpecificTerm string
for _, field := range fields { for _, field := range fields {
if isPostgreSQL { if isPostgreSQL {
searchFields = append(searchFields, fmt.Sprintf("lower(%s) LIKE lower(?) escape '*' ", field)) searchFields = append(searchFields, fmt.Sprintf("to_tsvector(lower(%[1]s)) @@ to_tsquery(concat(lower(?),':*'))", field))
dbSpecificTerm = strings.TrimLeft(term, "@")
} else { } else {
searchFields = append(searchFields, fmt.Sprintf("%s LIKE ? escape '*' ", field)) searchFields = append(searchFields, fmt.Sprintf("%s LIKE ? escape '*' ", field))
dbSpecificTerm = fmt.Sprintf("%s%%", strings.TrimLeft(term, "@"))
} }
termArgs = append(termArgs, fmt.Sprintf("%s%%", strings.TrimLeft(term, "@"))) termArgs = append(termArgs, dbSpecificTerm)
} }
query = query.Where(fmt.Sprintf("(%s)", strings.Join(searchFields, " OR ")), termArgs...) query = query.Where(fmt.Sprintf("(%s)", strings.Join(searchFields, " OR ")), termArgs...)
} }
return query return query
} }

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

@@ -569,6 +569,7 @@ func testPostStoreGetForThread(t *testing.T, ss store.Store) {
}) })
t.Run("Pagination", func(t *testing.T) { t.Run("Pagination", func(t *testing.T) {
t.Skip("MM-46134")
o1, err := ss.Post().Save(&model.Post{ChannelId: model.NewId(), UserId: model.NewId(), Message: NewTestId()}) o1, err := ss.Post().Save(&model.Post{ChannelId: model.NewId(), UserId: model.NewId(), Message: NewTestId()})
require.NoError(t, err) require.NoError(t, err)
_, err = ss.Post().Save(&model.Post{ChannelId: o1.ChannelId, UserId: model.NewId(), Message: NewTestId(), RootId: o1.Id}) _, err = ss.Post().Save(&model.Post{ChannelId: o1.ChannelId, UserId: model.NewId(), Message: NewTestId(), RootId: o1.Id})
@@ -644,7 +645,7 @@ func testPostStoreGetForThread(t *testing.T, ss store.Store) {
} }
r1, err = ss.Post().Get(context.Background(), o1.Id, opts, o1.UserId, map[string]bool{}) r1, err = ss.Post().Get(context.Background(), o1.Id, opts, o1.UserId, map[string]bool{})
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, r1.Order, 3) // including the root post assert.Len(t, r1.Order, 2) // including the root post
assert.True(t, r1.HasNext) assert.True(t, r1.HasNext)
lastPostID = r1.Order[len(r1.Order)-1] lastPostID = r1.Order[len(r1.Order)-1]
@@ -676,7 +677,7 @@ func testPostStoreGetForThread(t *testing.T, ss store.Store) {
} }
r1, err = ss.Post().Get(context.Background(), o1.Id, opts, o1.UserId, map[string]bool{}) r1, err = ss.Post().Get(context.Background(), o1.Id, opts, o1.UserId, map[string]bool{})
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, r1.Order, 3) // including the root post assert.Len(t, r1.Order, 2) // including the root post
assert.LessOrEqual(t, r1.Posts[r1.Order[1]].CreateAt, firstPostCreateAt) assert.LessOrEqual(t, r1.Posts[r1.Order[1]].CreateAt, firstPostCreateAt)
assert.False(t, r1.HasNext) assert.False(t, r1.HasNext)
@@ -980,6 +981,74 @@ func testPostStoreDelete(t *testing.T, ss store.Store) {
_, err = ss.Post().Get(context.Background(), rootPost2.Id, model.GetPostsOptions{}, "", map[string]bool{}) _, err = ss.Post().Get(context.Background(), rootPost2.Id, model.GetPostsOptions{}, "", map[string]bool{})
require.NoError(t, err) require.NoError(t, err)
}) })
t.Run("thread with multiple replies, update thread last reply at", func(t *testing.T) {
// Create a root post
rootPost1, err := ss.Post().Save(&model.Post{
ChannelId: model.NewId(),
UserId: model.NewId(),
Message: NewTestId(),
})
require.NoError(t, err)
// Reply to that root post
replyPost1, err := ss.Post().Save(&model.Post{
ChannelId: rootPost1.ChannelId,
UserId: model.NewId(),
Message: NewTestId(),
RootId: rootPost1.Id,
})
require.NoError(t, err)
// Reply to that root post a second time
replyPost2, err := ss.Post().Save(&model.Post{
ChannelId: rootPost1.ChannelId,
UserId: model.NewId(),
Message: NewTestId(),
RootId: rootPost1.Id,
})
require.NoError(t, err)
// Reply to that root post a third time
replyPost3, err := ss.Post().Save(&model.Post{
ChannelId: rootPost1.ChannelId,
UserId: model.NewId(),
Message: NewTestId(),
RootId: rootPost1.Id,
})
require.NoError(t, err)
thread, err := ss.Thread().Get(rootPost1.Id)
require.NoError(t, err)
require.Equal(t, replyPost3.CreateAt, thread.LastReplyAt)
// Delete the reply previous to last
err = ss.Post().Delete(replyPost2.Id, model.GetMillis(), "")
require.NoError(t, err)
thread, err = ss.Thread().Get(rootPost1.Id)
require.NoError(t, err)
// last reply at should be unchanged
require.Equal(t, replyPost3.CreateAt, thread.LastReplyAt)
// Delete the last reply
err = ss.Post().Delete(replyPost3.Id, model.GetMillis(), "")
require.NoError(t, err)
thread, err = ss.Thread().Get(rootPost1.Id)
require.NoError(t, err)
// last reply at should have changed
require.Equal(t, replyPost1.CreateAt, thread.LastReplyAt)
// Delete the last reply
err = ss.Post().Delete(replyPost1.Id, model.GetMillis(), "")
require.NoError(t, err)
thread, err = ss.Thread().Get(rootPost1.Id)
require.NoError(t, err)
// last reply at should be 0
require.Equal(t, int64(0), thread.LastReplyAt)
})
} }
func testPostStorePermDelete1Level(t *testing.T, ss store.Store) { func testPostStorePermDelete1Level(t *testing.T, ss store.Store) {

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

@@ -94,6 +94,7 @@ func TestUserStore(t *testing.T, ss store.Store, s SqlStore) {
t.Run("ResetLastPictureUpdate", func(t *testing.T) { testUserStoreResetLastPictureUpdate(t, ss) }) t.Run("ResetLastPictureUpdate", func(t *testing.T) { testUserStoreResetLastPictureUpdate(t, ss) })
t.Run("GetKnownUsers", func(t *testing.T) { testGetKnownUsers(t, ss) }) t.Run("GetKnownUsers", func(t *testing.T) { testGetKnownUsers(t, ss) })
t.Run("GetUsersWithInvalidEmails", func(t *testing.T) { testGetUsersWithInvalidEmails(t, ss) }) t.Run("GetUsersWithInvalidEmails", func(t *testing.T) { testGetUsersWithInvalidEmails(t, ss) })
t.Run("SearchMultilingual", func(t *testing.T) { testUserStoreSearchUsersMultilingual(t, ss, s) })
} }
func testUserStoreSave(t *testing.T, ss store.Store) { func testUserStoreSave(t *testing.T, ss store.Store) {
@@ -6010,3 +6011,174 @@ func testGetUsersWithInvalidEmails(t *testing.T, ss store.Store) {
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, users, 1) assert.Len(t, users, 1)
} }
func testUserStoreSearchUsersMultilingual(t *testing.T, ss store.Store, s SqlStore) {
u1 := &model.User{
Username: "test1" + model.NewId(),
FirstName: "Inígo",
LastName: "Martínez",
Nickname: "Berridi",
Email: MakeEmail(),
}
_, err := ss.User().Save(u1)
require.NoError(t, err)
defer func() { require.NoError(t, ss.User().PermanentDelete(u1.Id)) }()
u2 := &model.User{
Username: "test2" + model.NewId(),
FirstName: "Zinëdìne",
LastName: "Zidanë",
Email: MakeEmail(),
}
_, err = ss.User().Save(u2)
require.NoError(t, err)
defer func() { require.NoError(t, ss.User().PermanentDelete(u2.Id)) }()
u3 := &model.User{
Username: "test3" + model.NewId(),
FirstName: "Thomas ",
LastName: "Müller",
Nickname: "Fußballspieler",
Email: MakeEmail(),
}
_, err = ss.User().Save(u3)
require.NoError(t, err)
defer func() { require.NoError(t, ss.User().PermanentDelete(u3.Id)) }()
u4 := &model.User{
Username: "test4" + model.NewId(),
FirstName: "Jérémie ",
LastName: "Jéry",
Email: MakeEmail(),
}
_, err = ss.User().Save(u4)
require.NoError(t, err)
defer func() { require.NoError(t, ss.User().PermanentDelete(u4.Id)) }()
// The users returned from the database will have AuthData as an empty string.
nilAuthData := new(string)
*nilAuthData = ""
u1.AuthData = nilAuthData
u2.AuthData = nilAuthData
u3.AuthData = nilAuthData
u4.AuthData = nilAuthData
testCases := []struct {
Description string
Term string
Options *model.UserSearchOptions
ExpectedPostgres []*model.User
ExpectedMysql []*model.User
Language string
}{
{
"search test1 player",
"inig",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.UserSearchDefaultLimit,
},
[]*model.User{u1},
[]*model.User{u1},
"spanish",
},
{
"search test2 player",
"zine",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.UserSearchDefaultLimit,
},
[]*model.User{u2},
[]*model.User{u2},
"french",
},
{
"search test2 player",
"zidane",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.UserSearchDefaultLimit,
},
[]*model.User{u2},
[]*model.User{u2},
"french",
},
{
"search test3 player",
"muller",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.UserSearchDefaultLimit,
},
[]*model.User{u3},
[]*model.User{u3},
"german",
},
{
"search test3 player",
"muller",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.UserSearchDefaultLimit,
},
[]*model.User{},
[]*model.User{u3},
"english",
},
{
"search test4 player",
"jere",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.UserSearchDefaultLimit,
},
[]*model.User{u4},
[]*model.User{u4},
"spanish",
},
{
"search test4 player",
"jere",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.UserSearchDefaultLimit,
},
[]*model.User{},
[]*model.User{u4},
"english",
},
}
var initialDefaultTextSearchConfig string
if s.DriverName() == model.DatabaseDriverPostgres {
error := s.GetMasterX().Get(&initialDefaultTextSearchConfig, `SHOW default_text_search_config`)
require.NoError(t, error)
}
for _, testCase := range testCases {
if s.DriverName() == model.DatabaseDriverPostgres {
_, error := s.GetMasterX().Exec("SET default_text_search_config TO '" + testCase.Language + "'")
require.NoError(t, error)
}
t.Run(testCase.Description, func(t *testing.T) {
users, err := ss.User().SearchWithoutTeam(
testCase.Term,
testCase.Options,
)
if s.DriverName() != model.DatabaseDriverPostgres {
require.NoError(t, err)
assertUsers(t, testCase.ExpectedMysql, users)
} else {
require.NoError(t, err)
assertUsers(t, testCase.ExpectedPostgres, users)
}
})
}
if s.DriverName() == model.DatabaseDriverPostgres {
_, error := s.GetMasterX().Exec("SET default_text_search_config TO '" + initialDefaultTextSearchConfig + "'")
require.NoError(t, error)
}
}

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

@@ -96,7 +96,7 @@ func setupTestHelper(tb testing.TB, includeCacheLayer bool) *TestHelper {
} }
if includeCacheLayer { if includeCacheLayer {
// Adds the cache layer to the test store // Adds the cache layer to the test store
s.Store, err = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider) s.Store, err = localcachelayer.NewLocalCacheLayer(s.Store, s.GetMetrics(), s.Cluster, s.CacheProvider)
if err != nil { if err != nil {
panic(err) panic(err)
} }