Merge branch 'master' into MM-45118_my_top_dms
Этот коммит содержится в:
@@ -17,7 +17,7 @@ jobs:
|
||||
setup:
|
||||
working_directory: ~/mattermost/mattermost-server
|
||||
docker:
|
||||
- image: mattermost/mattermost-build-webapp:20210524_node-16
|
||||
- image: mattermost/mattermost-build-webapp:20220802_node-16.10.0@sha256:3272aa759f10c2ef1719ed08cc82ddb07224bec5be86f09800c72f5e2a623c3d
|
||||
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.
|
||||
steps:
|
||||
|
||||
@@ -117,7 +117,7 @@ func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, ent
|
||||
if includeCache {
|
||||
// Adds the cache layer to the test 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 {
|
||||
panic(err2)
|
||||
}
|
||||
@@ -218,7 +218,7 @@ func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, ent
|
||||
return th
|
||||
}
|
||||
|
||||
func SetupEnterprise(tb testing.TB) *TestHelper {
|
||||
func SetupEnterprise(tb testing.TB, options ...app.Option) *TestHelper {
|
||||
if testing.Short() {
|
||||
tb.SkipNow()
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func SetupEnterprise(tb testing.TB) *TestHelper {
|
||||
dbStore.MarkSystemRanUnitTests()
|
||||
mainHelper.PreloadMigrations()
|
||||
searchEngine := mainHelper.GetSearchEngine()
|
||||
th := setupTestHelper(dbStore, searchEngine, true, true, nil, nil)
|
||||
th := setupTestHelper(dbStore, searchEngine, true, true, nil, options)
|
||||
th.InitLogin()
|
||||
return th
|
||||
}
|
||||
@@ -322,8 +322,8 @@ func SetupWithStoreMock(tb testing.TB) *TestHelper {
|
||||
return th
|
||||
}
|
||||
|
||||
func SetupEnterpriseWithStoreMock(tb testing.TB) *TestHelper {
|
||||
th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, true, false, nil, nil)
|
||||
func SetupEnterpriseWithStoreMock(tb testing.TB, options ...app.Option) *TestHelper {
|
||||
th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, true, false, nil, options)
|
||||
statusMock := mocks.StatusStore{}
|
||||
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, 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 {
|
||||
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")
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
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) {
|
||||
nUsers := 1
|
||||
license := model.NewTestLicense()
|
||||
|
||||
@@ -3172,11 +3172,6 @@ func unfollowThreadByUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
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)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
|
||||
@@ -117,7 +117,7 @@ func (a *App) MessageExport() einterfaces.MessageExportInterface {
|
||||
return a.ch.MessageExport
|
||||
}
|
||||
func (a *App) Metrics() einterfaces.MetricsInterface {
|
||||
return a.ch.srv.Metrics
|
||||
return a.ch.srv.GetMetrics()
|
||||
}
|
||||
func (a *App) Notification() einterfaces.NotificationInterface {
|
||||
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.
|
||||
type AppIface interface {
|
||||
// @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
|
||||
// previous ListCommands now ListAutocompleteCommands
|
||||
ListAutocompleteCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError)
|
||||
// @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(c request.CTX, userID string, channel *model.Channel, opts ChannelMemberOpts) (*model.ChannelMember, *model.AppError)
|
||||
// AddCursorIdsForPostList adds NextPostId and PrevPostId as cursor to the PostList.
|
||||
@@ -84,7 +84,7 @@ type AppIface interface {
|
||||
// ConvertUserToBot converts a user to bot.
|
||||
ConvertUserToBot(user *model.User) (*model.Bot, *model.AppError)
|
||||
// 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(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
|
||||
@@ -132,7 +132,7 @@ type AppIface interface {
|
||||
// any ensureBotOptions hence it is not required for now.
|
||||
// TODO: Once the focalboard migration completed, we should add this logic to the app and
|
||||
// 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
|
||||
// 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
|
||||
@@ -250,7 +250,7 @@ type AppIface interface {
|
||||
MentionsToPublicChannels(c request.CTX, message, teamID string) model.ChannelMentionMap
|
||||
// MentionsToTeamMembers returns all the @ mentions found in message that
|
||||
// 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
|
||||
// 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
|
||||
@@ -328,7 +328,7 @@ type AppIface interface {
|
||||
SyncPlugins() *model.AppError
|
||||
// SyncRolesAndMembership updates the SchemeAdmin status and membership of all of the members of the given
|
||||
// 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
|
||||
// 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.
|
||||
@@ -354,7 +354,7 @@ type AppIface interface {
|
||||
// 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
|
||||
// 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(botUserId, newOwnerId string) (*model.Bot, *model.AppError)
|
||||
// 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(session model.Session, activityAt int64)
|
||||
// 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
|
||||
// constraints, executes plugins and image processing logic as needed. It
|
||||
// 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)
|
||||
AddStatusCache(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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
@@ -428,10 +428,10 @@ type AppIface interface {
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
BulkImportWithPath(c *request.Context, jsonlReader io.Reader, attachmentsReader *zip.Reader, dryRun bool, workers int, importPath string) (*model.AppError, int)
|
||||
CancelJob(jobId string) *model.AppError
|
||||
@@ -449,13 +449,13 @@ type AppIface interface {
|
||||
CheckUserPostflightAuthenticationCriteria(user *model.User) *model.AppError
|
||||
CheckUserPreflightAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError
|
||||
CheckWebConn(userID, connectionID string) *CheckConnResult
|
||||
ClearChannelMembersCache(c request.CTX, channelID string)
|
||||
ClearChannelMembersCache(c request.CTX, channelID string) error
|
||||
ClearLatestVersionCache()
|
||||
ClearSessionCacheForAllUsers()
|
||||
ClearSessionCacheForAllUsersSkipClusterSend()
|
||||
ClearSessionCacheForUser(userID string)
|
||||
ClearSessionCacheForUserSkipClusterSend(userID string)
|
||||
ClearTeamMembersCache(teamID string)
|
||||
ClearTeamMembersCache(teamID string) error
|
||||
ClientConfig() map[string]string
|
||||
ClientConfigHash() string
|
||||
Cloud() einterfaces.CloudInterface
|
||||
@@ -484,7 +484,7 @@ type AppIface interface {
|
||||
CreateOutgoingWebhook(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, *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)
|
||||
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)
|
||||
CreateRetentionPolicy(policy *model.RetentionPolicyWithTeamAndChannelIDs) (*model.RetentionPolicyWithTeamAndChannelCounts, *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)
|
||||
DoSystemConsoleRolesCreationMigration()
|
||||
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)
|
||||
EnableUserAccessToken(token *model.UserAccessToken) *model.AppError
|
||||
EnvironmentConfig(filter func(reflect.StructField) bool) map[string]any
|
||||
@@ -837,8 +837,8 @@ type AppIface interface {
|
||||
GetWarnMetricsStatus() (map[string]*model.WarnMetricStatus, *model.AppError)
|
||||
HTTPService() httpservice.HTTPService
|
||||
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)
|
||||
HandleCommandResponsePost(c *request.Context, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.Post, *model.AppError)
|
||||
HandleCommandResponse(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *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
|
||||
HandleImages(previewPathList []string, thumbnailPathList []string, fileData [][]byte)
|
||||
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)
|
||||
Ldap() einterfaces.LdapInterface
|
||||
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
|
||||
LimitedClientConfig() map[string]string
|
||||
ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError)
|
||||
@@ -955,7 +955,7 @@ type AppIface interface {
|
||||
RemoveTeamIcon(teamID string) *model.AppError
|
||||
RemoveTeamsFromRetentionPolicy(policyID string, teamIDs []string) *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
|
||||
RequestLicenseAndAckWarnMetric(c *request.Context, warnMetricId string, isBot bool) *model.AppError
|
||||
ResetPasswordFromToken(c request.CTX, userSuppliedTokenString, newPassword string) *model.AppError
|
||||
@@ -1077,7 +1077,7 @@ type AppIface interface {
|
||||
TotalWebsocketConnections() int
|
||||
TriggerWebhook(c request.CTX, payload *model.OutgoingWebhookPayload, hook *model.OutgoingWebhook, post *model.Post, channel *model.Channel)
|
||||
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)
|
||||
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)
|
||||
@@ -1122,7 +1122,7 @@ type AppIface interface {
|
||||
UpdateThreadReadForUserByPost(c request.CTX, currentSessionId, userID, teamID, threadID, postID string) (*model.ThreadResponse, *model.AppError)
|
||||
UpdateThreadsReadForUser(userID, teamID string) *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)
|
||||
UpdateUserAuth(userID string, userAuth *model.UserAuth) (*model.UserAuth, *model.AppError)
|
||||
UpdateUserRoles(c request.CTX, userID string, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError)
|
||||
|
||||
14
app/bot.go
14
app/bot.go
@@ -38,7 +38,7 @@ func (w *botServiceWrapper) EnsureBot(c *request.Context, productID string, bot
|
||||
// any ensureBotOptions hence it is not required for now.
|
||||
// TODO: Once the focalboard migration completed, we should add this logic to the app and
|
||||
// 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 {
|
||||
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)
|
||||
}
|
||||
} 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 "+
|
||||
"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 "+
|
||||
@@ -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.
|
||||
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()
|
||||
if vErr != nil {
|
||||
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.
|
||||
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)
|
||||
if nErr != nil {
|
||||
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.
|
||||
func (a *App) disableUserBots(c *request.Context, userID string) *model.AppError {
|
||||
func (a *App) disableUserBots(c request.CTX, userID string) *model.AppError {
|
||||
perPage := 20
|
||||
for {
|
||||
options := &model.BotGetOptions{
|
||||
@@ -516,7 +516,7 @@ func (a *App) disableUserBots(c *request.Context, userID string) *model.AppError
|
||||
for _, bot := range userBots {
|
||||
_, err := a.UpdateBotActive(c, bot.UserId, false)
|
||||
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
|
||||
}
|
||||
|
||||
func (a *App) notifySysadminsBotOwnerDeactivated(c *request.Context, userID string) *model.AppError {
|
||||
func (a *App) notifySysadminsBotOwnerDeactivated(c request.CTX, userID string) *model.AppError {
|
||||
perPage := 25
|
||||
botOptions := &model.BotGetOptions{
|
||||
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) {
|
||||
channel, channelErr := a.Srv().Store.Channel().GetByName(teamID, channelName, true)
|
||||
if channelErr != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
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)
|
||||
}
|
||||
c.Logger().Warn("No default channel with this name", mlog.String("channelName", channelName), mlog.String("teamID", teamID), mlog.Err(channelErr))
|
||||
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)
|
||||
channelJSON, jsonErr := json.Marshal(channel)
|
||||
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))
|
||||
a.Publish(messageWs)
|
||||
@@ -1019,7 +1012,9 @@ func (a *App) PatchChannelModerationsForChannel(c request.CTX, channel *model.Ch
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.sendUpdatedRoleEvent(adminRole)
|
||||
if appErr := a.sendUpdatedRoleEvent(adminRole); appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
message := model.NewWebSocketEvent(model.WebsocketEventChannelSchemeUpdated, "", channel.Id, "", nil)
|
||||
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)
|
||||
memberJSON, jsonErr := json.Marshal(member)
|
||||
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))
|
||||
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)
|
||||
memberJSON, jsonErr := json.Marshal(member)
|
||||
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))
|
||||
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 err := a.postJoinChannelMessage(c, user, channel); err != nil {
|
||||
mlog.Error("Failed to post join channel message", mlog.Err(err))
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
a.Srv().Go(func() {
|
||||
@@ -2513,11 +2508,9 @@ func (a *App) RemoveUserFromChannel(c request.CTX, userIDToRemove string, remove
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
a.Srv().Go(func() {
|
||||
if err := a.postRemoveFromChannelMessage(c, removerUserId, user, channel); err != nil {
|
||||
mlog.Error("Failed to post user removal message", mlog.Err(err))
|
||||
}
|
||||
})
|
||||
if err := a.postRemoveFromChannelMessage(c, removerUserId, user, channel); err != nil {
|
||||
c.Logger().Error("Failed to post user removal message", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -2701,7 +2694,7 @@ func (a *App) markChannelAsUnreadFromPostCRTUnsupported(c request.CTX, postID st
|
||||
if a.IsCRTEnabledForUser(c, userID) {
|
||||
payload, jsonErr := json.Marshal(thread)
|
||||
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.Add("thread", string(payload))
|
||||
@@ -3268,7 +3261,7 @@ func (a *App) setChannelsMuted(c request.CTX, channelIDs []string, userID string
|
||||
|
||||
memberJSON, jsonErr := json.Marshal(member)
|
||||
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))
|
||||
@@ -3369,21 +3362,22 @@ func (a *App) forEachChannelMember(c request.CTX, channelID string, f func(model
|
||||
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 {
|
||||
a.ClearSessionCacheForUser(channelMember.UserId)
|
||||
message := model.NewWebSocketEvent(model.WebsocketEventChannelMemberUpdated, "", "", channelMember.UserId, nil)
|
||||
memberJSON, jsonErr := json.Marshal(channelMember)
|
||||
if jsonErr != nil {
|
||||
c.Logger().Warn("Failed to encode channel member to JSON", mlog.Err(jsonErr))
|
||||
return jsonErr
|
||||
}
|
||||
message.Add("channelMember", string(memberJSON))
|
||||
a.Publish(message)
|
||||
return 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) {
|
||||
|
||||
@@ -151,7 +151,7 @@ func (a *App) UpdateSidebarCategories(c request.CTX, userID, teamID string, cate
|
||||
|
||||
updatedCategoriesJSON, jsonErr := json.Marshal(updatedCategories)
|
||||
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))
|
||||
|
||||
@@ -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) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
@@ -2065,7 +2092,7 @@ func TestClearChannelMembersCache(t *testing.T) {
|
||||
mockStore.On("Channel").Return(&mockChannelStore)
|
||||
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) {
|
||||
|
||||
@@ -33,7 +33,7 @@ var atMentionRegexp = regexp.MustCompile(`\B@[[:alnum:]][[:alnum:]\.\-_:]*`)
|
||||
type CommandProvider interface {
|
||||
GetTrigger() string
|
||||
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)
|
||||
@@ -52,7 +52,7 @@ func GetCommandProvider(name string) CommandProvider {
|
||||
}
|
||||
|
||||
// @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 {
|
||||
post.Message = response.Text
|
||||
} else {
|
||||
@@ -180,7 +180,7 @@ func (a *App) ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Com
|
||||
}
|
||||
|
||||
// @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 := ""
|
||||
message := ""
|
||||
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())
|
||||
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
|
||||
@@ -235,7 +235,7 @@ func (a *App) ExecuteCommand(c *request.Context, args *model.CommandArgs) (*mode
|
||||
|
||||
// MentionsToTeamMembers returns all the @ mentions found in message that
|
||||
// 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 {
|
||||
Name string
|
||||
Id string
|
||||
@@ -253,7 +253,7 @@ func (a *App) MentionsToTeamMembers(message, teamID string) model.UserMentionMap
|
||||
|
||||
var nfErr *store.ErrNotFound
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
// 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)
|
||||
if provider == nil {
|
||||
return nil, nil
|
||||
@@ -443,7 +443,7 @@ func (a *App) tryExecuteCustomCommand(c request.CTX, args *model.CommandArgs, tr
|
||||
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.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)
|
||||
|
||||
userMentionMap := a.MentionsToTeamMembers(message, team.Id)
|
||||
userMentionMap := a.MentionsToTeamMembers(c, message, team.Id)
|
||||
for key, values := range userMentionMap.ToURLValues() {
|
||||
p[key] = values
|
||||
}
|
||||
@@ -536,7 +536,7 @@ func (a *App) DoCommandRequest(cmd *model.Command, p url.Values) (*model.Command
|
||||
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 := ""
|
||||
if args.Command != "" {
|
||||
parts := strings.Split(args.Command, " ")
|
||||
@@ -570,7 +570,7 @@ func (a *App) HandleCommandResponse(c *request.Context, command *model.Command,
|
||||
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.ChannelId = args.ChannelId
|
||||
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{
|
||||
Text: "I do nothing!",
|
||||
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.Metrics != nil {
|
||||
w.srv.Metrics.Register()
|
||||
if w.srv.GetMetrics() != nil {
|
||||
w.srv.GetMetrics().Register()
|
||||
}
|
||||
w.srv.SetupMetricsServer()
|
||||
w.srv.platform.RestartMetrics() // TODO: remove when this moved to the platform service
|
||||
} else {
|
||||
w.srv.StopMetricsServer()
|
||||
w.srv.platform.ShutdownMetrics() // TODO: remove when this moved to the platform service
|
||||
}
|
||||
|
||||
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)
|
||||
emojiJSON, jsonErr := json.Marshal(emoji)
|
||||
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))
|
||||
a.Publish(message)
|
||||
|
||||
@@ -112,10 +112,6 @@ func RegisterLicenseInterface(f func(*Server) einterfaces.LicenseInterface) {
|
||||
}
|
||||
|
||||
func (s *Server) initEnterprise() {
|
||||
if metricsInterface != nil {
|
||||
s.Metrics = metricsInterface(s)
|
||||
}
|
||||
|
||||
if clusterInterface != nil && s.Cluster == nil {
|
||||
s.Cluster = clusterInterface(s)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"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/shared/mlog"
|
||||
"github.com/mattermost/mattermost-server/v6/store"
|
||||
@@ -61,7 +62,7 @@ var exportablePreferences = map[ComparablePreference]string{{
|
||||
}: "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
|
||||
if opts.CreateArchive {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
mlog.Info("Bulk export: exporting teams")
|
||||
ctx.Logger().Info("Bulk export: exporting teams")
|
||||
teamNames, err := a.exportAllTeams(writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mlog.Info("Bulk export: exporting channels")
|
||||
ctx.Logger().Info("Bulk export: exporting channels")
|
||||
if err = a.exportAllChannels(writer, teamNames); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mlog.Info("Bulk export: exporting users")
|
||||
ctx.Logger().Info("Bulk export: exporting users")
|
||||
if err = a.exportAllUsers(writer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mlog.Info("Bulk export: exporting posts")
|
||||
attachments, err := a.exportAllPosts(writer, opts.IncludeAttachments)
|
||||
ctx.Logger().Info("Bulk export: exporting posts")
|
||||
attachments, err := a.exportAllPosts(ctx, writer, opts.IncludeAttachments)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mlog.Info("Bulk export: exporting direct channels")
|
||||
ctx.Logger().Info("Bulk export: exporting direct channels")
|
||||
if err = a.exportAllDirectChannels(writer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mlog.Info("Bulk export: exporting direct posts")
|
||||
directAttachments, err := a.exportAllDirectPosts(writer, opts.IncludeAttachments)
|
||||
ctx.Logger().Info("Bulk export: exporting direct posts")
|
||||
directAttachments, err := a.exportAllDirectPosts(ctx, writer, opts.IncludeAttachments)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.IncludeAttachments {
|
||||
mlog.Info("Bulk export: exporting file attachments")
|
||||
ctx.Logger().Info("Bulk export: exporting file attachments")
|
||||
for _, attachment := range attachments {
|
||||
if err := a.exportFile(outPath, *attachment.Path, zipWr); err != nil {
|
||||
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
|
||||
afterId := strings.Repeat("0", 26)
|
||||
|
||||
@@ -407,7 +408,7 @@ func (a *App) exportAllPosts(writer io.Writer, withAttachments bool) ([]Attachme
|
||||
|
||||
postLine := ImportLineForPost(post)
|
||||
|
||||
replies, replyAttachments, err := a.buildPostReplies(post.Id, withAttachments)
|
||||
replies, replyAttachments, err := a.buildPostReplies(ctx, post.Id, withAttachments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -419,7 +420,7 @@ func (a *App) exportAllPosts(writer io.Writer, withAttachments bool) ([]Attachme
|
||||
postLine.Post.Replies = &replies
|
||||
postLine.Post.Reactions = &[]ReactionImportData{}
|
||||
if post.HasReactions {
|
||||
postLine.Post.Reactions, err = a.BuildPostReactions(post.Id)
|
||||
postLine.Post.Reactions, err = a.BuildPostReactions(ctx, post.Id)
|
||||
if err != nil {
|
||||
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 attachments []AttachmentImportData
|
||||
|
||||
@@ -457,7 +458,7 @@ func (a *App) buildPostReplies(postID string, withAttachments bool) ([]ReplyImpo
|
||||
replyImportObject := ImportReplyFromPost(reply)
|
||||
if reply.HasReactions {
|
||||
var appErr *model.AppError
|
||||
replyImportObject.Reactions, appErr = a.BuildPostReactions(reply.Id)
|
||||
replyImportObject.Reactions, appErr = a.BuildPostReactions(ctx, reply.Id)
|
||||
if appErr != nil {
|
||||
return nil, nil, appErr
|
||||
}
|
||||
@@ -479,7 +480,7 @@ func (a *App) buildPostReplies(postID string, withAttachments bool) ([]ReplyImpo
|
||||
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
|
||||
|
||||
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 {
|
||||
var nfErr *store.ErrNotFound
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
afterId := strings.Repeat("0", 26)
|
||||
for {
|
||||
@@ -670,7 +671,7 @@ func (a *App) exportAllDirectPosts(writer io.Writer, withAttachments bool) ([]At
|
||||
}
|
||||
|
||||
// Do the Replies.
|
||||
replies, replyAttachments, err := a.buildPostReplies(post.Id, withAttachments)
|
||||
replies, replyAttachments, err := a.buildPostReplies(ctx, post.Id, withAttachments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestReactionsOfPost(t *testing.T) {
|
||||
|
||||
th.App.SaveReactionForPost(th.Context, &reactionObject)
|
||||
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)
|
||||
|
||||
assert.Equal(t, reactionObject.EmojiName, *(*reactionsOfPost)[0].EmojiName)
|
||||
@@ -179,7 +179,7 @@ func TestExportAllUsers(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
|
||||
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)
|
||||
|
||||
th2 := Setup(t)
|
||||
@@ -227,7 +227,7 @@ func TestExportDMChannel(t *testing.T) {
|
||||
th1.CreateDmChannel(th1.BasicUser2)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
th2 := Setup(t).InitBasic()
|
||||
@@ -292,7 +292,7 @@ func TestExportDMChannelToSelf(t *testing.T) {
|
||||
th1.CreateDmChannel(th1.BasicUser)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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))
|
||||
|
||||
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)
|
||||
|
||||
th1.TearDown()
|
||||
@@ -520,7 +520,7 @@ func TestExportPostWithProps(t *testing.T) {
|
||||
require.NotEmpty(t, posts[1].Props)
|
||||
|
||||
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)
|
||||
|
||||
th1.TearDown()
|
||||
@@ -558,7 +558,7 @@ func TestExportDMPostWithSelf(t *testing.T) {
|
||||
th1.CreatePost(dmChannel)
|
||||
|
||||
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)
|
||||
|
||||
posts, nErr := th1.App.Srv().Store.Post().GetDirectPostParentsForExportAfter(1000, "0000000")
|
||||
@@ -626,7 +626,7 @@ func TestBulkExport(t *testing.T) {
|
||||
IncludeAttachments: true,
|
||||
CreateArchive: true,
|
||||
}
|
||||
appErr = th.App.BulkExport(exportFile, dir, opts)
|
||||
appErr = th.App.BulkExport(th.Context, exportFile, dir, opts)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
th.TearDown()
|
||||
@@ -663,7 +663,7 @@ func TestBuildPostReplies(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.Empty(t, data)
|
||||
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) {
|
||||
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.Empty(t, data)
|
||||
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) {
|
||||
post := createPostWithAttachments(th, 5, "")
|
||||
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.Len(t, data, 1)
|
||||
require.Empty(t, attachments)
|
||||
@@ -690,7 +690,7 @@ func TestBuildPostReplies(t *testing.T) {
|
||||
post := createPostWithAttachments(th, 5, "")
|
||||
reply1 := createPostWithAttachments(th, 2, 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.Len(t, data, 2)
|
||||
require.Len(t, attachments, 5)
|
||||
@@ -717,7 +717,7 @@ func TestExportDeletedTeams(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
|
||||
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)
|
||||
|
||||
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.
|
||||
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)
|
||||
if err != nil && channelID != "" {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
teamID := filepath.Base(rawTeamId)
|
||||
channelID := filepath.Base(rawChannelId)
|
||||
|
||||
30
app/group.go
30
app/group.go
@@ -9,7 +9,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
"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):
|
||||
return nil, model.NewAppError("CreateGroupWithUserIds", "app.group.id.app_error", nil, invErr.Error(), http.StatusBadRequest)
|
||||
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:
|
||||
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))
|
||||
groupJSON, jsonErr := json.Marshal(newGroup)
|
||||
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))
|
||||
a.Publish(messageWs)
|
||||
@@ -172,13 +171,13 @@ func (a *App) UpdateGroup(group *model.Group) (*model.Group, *model.AppError) {
|
||||
if err == nil {
|
||||
count, countErr := a.Srv().Store.Group().GetMemberCount(updatedGroup.Id)
|
||||
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))
|
||||
messageWs := model.NewWebSocketEvent(model.WebsocketEventReceivedGroup, "", "", "", nil)
|
||||
groupJSON, jsonErr := json.Marshal(updatedGroup)
|
||||
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))
|
||||
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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -743,7 +746,9 @@ func (a *App) UpsertGroupMembers(groupID string, userIDs []string) ([]*model.Gro
|
||||
}
|
||||
|
||||
for _, groupMember := range members {
|
||||
a.publishGroupMemberEvent(model.WebsocketEventGroupMemberAdd, groupMember)
|
||||
if appErr := a.publishGroupMemberEvent(model.WebsocketEventGroupMemberAdd, groupMember); appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
}
|
||||
|
||||
return members, nil
|
||||
@@ -765,18 +770,21 @@ func (a *App) DeleteGroupMembers(groupID string, userIDs []string) ([]*model.Gro
|
||||
}
|
||||
|
||||
for _, groupMember := range members {
|
||||
a.publishGroupMemberEvent(model.WebsocketEventGroupMemberDelete, groupMember)
|
||||
if appErr := a.publishGroupMemberEvent(model.WebsocketEventGroupMemberDelete, groupMember); appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
groupMemberJSON, jsonErr := json.Marshal(groupMember)
|
||||
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))
|
||||
a.Publish(messageWs)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
|
||||
if includeCacheLayer {
|
||||
// Adds the cache layer to the test 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 {
|
||||
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"}
|
||||
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 {
|
||||
@@ -584,14 +584,14 @@ func (a *App) importUser(c request.CTX, data *UserImportData, dryRun bool) *mode
|
||||
}
|
||||
|
||||
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 {
|
||||
defer file.Close()
|
||||
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)
|
||||
}
|
||||
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.CreateAt = *replyData.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
|
||||
}
|
||||
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{
|
||||
ServerID: w.srv.TelemetryId(),
|
||||
Name: requester.GetDisplayName(model.ShowFullName),
|
||||
|
||||
@@ -383,7 +383,7 @@ func (a *OpenTracingAppLayer) AddStatusCacheSkipClusterSend(status *model.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
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddUserToTeam")
|
||||
|
||||
@@ -951,7 +951,7 @@ func (a *OpenTracingAppLayer) BroadcastStatus(status *model.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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.BuildPostReactions")
|
||||
|
||||
@@ -963,7 +963,7 @@ func (a *OpenTracingAppLayer) BuildPostReactions(postID string) (*[]app.Reaction
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.BuildPostReactions(postID)
|
||||
resultVar0, resultVar1 := a.app.BuildPostReactions(ctx, postID)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@@ -1017,7 +1017,7 @@ func (a *OpenTracingAppLayer) BuildSamlMetadataObject(idpMetadata []byte) (*mode
|
||||
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
|
||||
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()
|
||||
resultVar0 := a.app.BulkExport(writer, outPath, opts)
|
||||
resultVar0 := a.app.BulkExport(ctx, writer, outPath, opts)
|
||||
|
||||
if resultVar0 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar0))
|
||||
@@ -1469,7 +1469,7 @@ func (a *OpenTracingAppLayer) CheckWebConn(userID string, connectionID string) *
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) ClearChannelMembersCache(c request.CTX, channelID string) {
|
||||
func (a *OpenTracingAppLayer) ClearChannelMembersCache(c request.CTX, channelID string) error {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ClearChannelMembersCache")
|
||||
|
||||
@@ -1481,7 +1481,14 @@ func (a *OpenTracingAppLayer) ClearChannelMembersCache(c request.CTX, channelID
|
||||
}()
|
||||
|
||||
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() {
|
||||
@@ -1559,7 +1566,7 @@ func (a *OpenTracingAppLayer) ClearSessionCacheForUserSkipClusterSend(userID str
|
||||
a.app.ClearSessionCacheForUserSkipClusterSend(userID)
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) ClearTeamMembersCache(teamID string) {
|
||||
func (a *OpenTracingAppLayer) ClearTeamMembersCache(teamID string) error {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ClearTeamMembersCache")
|
||||
|
||||
@@ -1571,7 +1578,14 @@ func (a *OpenTracingAppLayer) ClearTeamMembersCache(teamID string) {
|
||||
}()
|
||||
|
||||
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 {
|
||||
@@ -1857,7 +1871,7 @@ func (a *OpenTracingAppLayer) CopyFileInfos(userID string, fileIDs []string) ([]
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateBot")
|
||||
|
||||
@@ -1967,7 +1981,7 @@ func (a *OpenTracingAppLayer) CreateCommand(cmd *model.Command) (*model.Command,
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.DoUploadFileExpectModification")
|
||||
|
||||
@@ -3948,7 +3962,7 @@ func (a *OpenTracingAppLayer) EnableUserAccessToken(token *model.UserAccessToken
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.EnsureBot")
|
||||
|
||||
@@ -3987,7 +4001,7 @@ func (a *OpenTracingAppLayer) EnvironmentConfig(filter func(reflect.StructField)
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.HandleCommandResponse")
|
||||
|
||||
@@ -11019,7 +11033,7 @@ func (a *OpenTracingAppLayer) HandleCommandResponse(c *request.Context, command
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.HandleCommandResponsePost")
|
||||
|
||||
@@ -11753,7 +11767,7 @@ func (a *OpenTracingAppLayer) LeaveChannel(c request.CTX, channelID string, user
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.LeaveTeam")
|
||||
|
||||
@@ -12173,7 +12187,7 @@ func (a *OpenTracingAppLayer) MentionsToPublicChannels(c request.CTX, message st
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.MentionsToTeamMembers")
|
||||
|
||||
@@ -12185,7 +12199,7 @@ func (a *OpenTracingAppLayer) MentionsToTeamMembers(message string, teamID strin
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0 := a.app.MentionsToTeamMembers(message, teamID)
|
||||
resultVar0 := a.app.MentionsToTeamMembers(c, message, teamID)
|
||||
|
||||
return resultVar0
|
||||
}
|
||||
@@ -13708,7 +13722,7 @@ func (a *OpenTracingAppLayer) RemoveUserFromChannel(c request.CTX, userIDToRemov
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RemoveUserFromTeam")
|
||||
|
||||
@@ -16175,7 +16189,7 @@ func (a *OpenTracingAppLayer) SyncPlugins() *model.AppError {
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateUserActive")
|
||||
|
||||
@@ -17791,7 +17805,7 @@ func (a *OpenTracingAppLayer) UploadEmojiImage(id string, imageData *multipart.F
|
||||
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
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UploadFile")
|
||||
|
||||
|
||||
@@ -3,14 +3,34 @@
|
||||
|
||||
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.
|
||||
// The mandatory fields will be checked during the initialization of the service.
|
||||
type ServiceConfig struct {
|
||||
// Mandatory fields
|
||||
ConfigStore *config.Store
|
||||
Logger *mlog.Logger
|
||||
StartMetrics bool // TODO: find an elegant way to start/stop metrics server by default
|
||||
// Optional fields
|
||||
Metrics einterfaces.MetricsInterface
|
||||
Cluster einterfaces.ClusterInterface
|
||||
}
|
||||
|
||||
func (c *ServiceConfig) validate() error {
|
||||
// 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
|
||||
}
|
||||
|
||||
184
app/platform/metrics.go
Обычный файл
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
|
||||
|
||||
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
|
||||
// responsible for non-entity related functionalities that are required
|
||||
// by a product such as database access, configuration access, licensing etc.
|
||||
type PlatformService struct {
|
||||
serviceConfig ServiceConfig
|
||||
configStore *config.Store
|
||||
logger *mlog.Logger
|
||||
|
||||
metrics *platformMetrics
|
||||
|
||||
cluster einterfaces.ClusterInterface
|
||||
}
|
||||
|
||||
// New creates a new PlatformService.
|
||||
func New(c ServiceConfig) (*PlatformService, error) {
|
||||
if err := c.validate(); err != nil {
|
||||
func New(sc ServiceConfig) (*PlatformService, error) {
|
||||
if err := sc.validate(); err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
mlog.Error("Failed to start up plugins", mlog.Err(err))
|
||||
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.Message = message
|
||||
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
|
||||
// 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, " ")
|
||||
trigger := parts[0][1:]
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ func (s *postServiceWrapper) CreatePost(ctx *request.Context, post *model.Post)
|
||||
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
|
||||
channel, errCh := a.Srv().Store.Channel().Get(post.ChannelId, true)
|
||||
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)
|
||||
if !fromWebhook && !fromBot && !isCRTReply {
|
||||
if _, err := a.MarkChannelsAsViewed(c, []string{post.ChannelId}, post.UserId, currentSessionId, true); err != nil {
|
||||
mlog.Warn(
|
||||
c.Logger().Warn(
|
||||
"Encountered error updating last viewed",
|
||||
mlog.String("channel_id", post.ChannelId),
|
||||
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)
|
||||
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)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"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) {
|
||||
@@ -69,7 +68,7 @@ func (a *App) UpdatePreferences(userID string, preferences model.Preferences) *m
|
||||
message = model.NewWebSocketEvent(model.WebsocketEventPreferencesChanged, "", "", userID, nil)
|
||||
prefsJSON, jsonErr := json.Marshal(preferences)
|
||||
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))
|
||||
a.Publish(message)
|
||||
@@ -103,7 +102,7 @@ func (a *App) DeletePreferences(userID string, preferences model.Preferences) *m
|
||||
message = model.NewWebSocketEvent(model.WebsocketEventPreferencesDeleted, "", "", userID, nil)
|
||||
prefsJSON, jsonErr := json.Marshal(preferences)
|
||||
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))
|
||||
a.Publish(message)
|
||||
|
||||
20
app/role.go
20
app/role.go
@@ -12,7 +12,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"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/utils"
|
||||
)
|
||||
@@ -138,7 +137,9 @@ func (a *App) PatchRole(role *model.Role, patch *model.RolePatch) (*model.Role,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a.sendUpdatedRoleEvent(role)
|
||||
if appErr := a.sendUpdatedRoleEvent(role); appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
return role, err
|
||||
}
|
||||
@@ -225,7 +226,10 @@ func (a *App) UpdateRole(role *model.Role) (*model.Role, *model.AppError) {
|
||||
|
||||
for _, ir := range impactedRoles {
|
||||
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
|
||||
}
|
||||
|
||||
func (a *App) sendUpdatedRoleEvent(role *model.Role) {
|
||||
func (a *App) sendUpdatedRoleEvent(role *model.Role) *model.AppError {
|
||||
message := model.NewWebSocketEvent(model.WebsocketEventRoleUpdated, "", "", "", nil)
|
||||
roleJSON, jsonErr := json.Marshal(role)
|
||||
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))
|
||||
|
||||
a.Srv().Go(func() {
|
||||
a.Publish(message)
|
||||
})
|
||||
a.Publish(message)
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveRoles(rolesToRemove []string, roles string) string {
|
||||
|
||||
195
app/server.go
195
app/server.go
@@ -9,10 +9,8 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"hash/maphash"
|
||||
"html/template"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -27,7 +25,6 @@ import (
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
sentryhttp "github.com/getsentry/sentry-go/http"
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/cors"
|
||||
@@ -35,6 +32,7 @@ import (
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/app/email"
|
||||
"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/teams"
|
||||
"github.com/mattermost/mattermost-server/v6/app/users"
|
||||
@@ -131,10 +129,6 @@ type Server struct {
|
||||
|
||||
localModeServer *http.Server
|
||||
|
||||
metricsServer *http.Server
|
||||
metricsRouter *mux.Router
|
||||
metricsLock sync.Mutex
|
||||
|
||||
didFinishListen chan struct{}
|
||||
|
||||
goroutineCount int32
|
||||
@@ -177,6 +171,7 @@ type Server struct {
|
||||
configStore *configWrapper
|
||||
filestore filestore.FileBackend
|
||||
|
||||
platform *platform.PlatformService
|
||||
telemetryService *telemetry.TelemetryService
|
||||
userService *users.UserService
|
||||
teamService *teams.TeamService
|
||||
@@ -200,7 +195,6 @@ type Server struct {
|
||||
|
||||
Cluster einterfaces.ClusterInterface
|
||||
Cloud einterfaces.CloudInterface
|
||||
Metrics einterfaces.MetricsInterface
|
||||
LicenseManager einterfaces.LicenseInterface
|
||||
|
||||
CacheProvider cache.Provider
|
||||
@@ -286,6 +280,22 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
// Depends on step 3 (s.SearchEngine must be non-nil)
|
||||
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.
|
||||
// At the moment we only have this implementation
|
||||
// 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).
|
||||
if s.newStore == nil {
|
||||
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(
|
||||
retrylayer.New(s.sqlStore),
|
||||
s.Metrics,
|
||||
s.GetMetrics(),
|
||||
s.Cluster,
|
||||
s.CacheProvider,
|
||||
)
|
||||
@@ -327,7 +337,7 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
|
||||
return timerlayer.New(
|
||||
searchStore,
|
||||
s.Metrics,
|
||||
s.GetMetrics(),
|
||||
), nil
|
||||
}
|
||||
}
|
||||
@@ -343,7 +353,7 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
SessionStore: s.Store.Session(),
|
||||
OAuthStore: s.Store.OAuth(),
|
||||
ConfigFn: s.Config,
|
||||
Metrics: s.Metrics,
|
||||
Metrics: s.GetMetrics(),
|
||||
Cluster: s.Cluster,
|
||||
LicenseFn: s.License,
|
||||
})
|
||||
@@ -620,7 +630,9 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -632,7 +644,9 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
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())
|
||||
@@ -701,24 +715,6 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
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 {
|
||||
if a > b {
|
||||
return a
|
||||
@@ -951,11 +947,11 @@ func (s *Server) startInterClusterServices(license *model.License) error {
|
||||
}
|
||||
|
||||
func (s *Server) enableLoggingMetrics() {
|
||||
if s.Metrics == nil {
|
||||
if s.GetMetrics() == nil {
|
||||
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.
|
||||
if err := s.initLogging(); err != nil {
|
||||
@@ -991,7 +987,7 @@ func (s *Server) StopHTTPServer() {
|
||||
}
|
||||
|
||||
func (s *Server) Shutdown() {
|
||||
mlog.Info("Stopping Server...")
|
||||
s.Log.Info("Stopping Server...")
|
||||
|
||||
defer sentry.Flush(2 * time.Second)
|
||||
|
||||
@@ -1002,24 +998,24 @@ func (s *Server) Shutdown() {
|
||||
|
||||
if s.tracer != 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()
|
||||
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()
|
||||
if s.sharedChannelService != 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 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()
|
||||
@@ -1046,7 +1042,9 @@ func (s *Server) Shutdown() {
|
||||
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.
|
||||
if s.Jobs != nil {
|
||||
@@ -1054,10 +1052,10 @@ func (s *Server) Shutdown() {
|
||||
// before stopping them as both calls essentially become no-ops
|
||||
// if nothing is running.
|
||||
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) {
|
||||
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.
|
||||
for name, product := range s.products {
|
||||
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 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.
|
||||
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) {
|
||||
if s.metricsRouter != nil {
|
||||
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()))
|
||||
s.platform.HandleMetrics(route, h)
|
||||
}
|
||||
|
||||
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() {
|
||||
s.Jobs = jobs.NewJobServer(s, s.Store, s.Metrics)
|
||||
s.Jobs = jobs.NewJobServer(s, s.Store, s.GetMetrics())
|
||||
|
||||
if jobsDataRetentionJobInterface != nil {
|
||||
builder := jobsDataRetentionJobInterface(s)
|
||||
@@ -2039,7 +1941,7 @@ func (s *Server) initJobs() {
|
||||
|
||||
s.Jobs.RegisterJobType(
|
||||
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),
|
||||
)
|
||||
|
||||
@@ -2106,7 +2008,10 @@ func (s *Server) GetSharedChannelSyncService() SharedChannelServiceIFace {
|
||||
// GetMetrics returns the server's Metrics interface. Exposing via a method
|
||||
// allows interfaces to be created with subsets of server APIs.
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
if cfg.Fuzzy {
|
||||
displayName = utils.FuzzName()
|
||||
@@ -60,7 +60,7 @@ func (cfg *AutoChannelCreator) createRandomChannel(c *request.Context) (*model.C
|
||||
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)
|
||||
channels := make([]*model.Channel, numChannels)
|
||||
|
||||
@@ -75,7 +75,7 @@ func (cfg *AutoChannelCreator) CreateTestChannels(c *request.Context, num utils.
|
||||
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)
|
||||
dms := make([]*model.Channel, numDMs)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ type TestEnvironment struct {
|
||||
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())
|
||||
|
||||
teamCreator := NewAutoTeamCreator(client)
|
||||
@@ -48,7 +48,7 @@ func CreateTestEnvironmentWithTeams(a *app.App, c *request.Context, client *mode
|
||||
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())
|
||||
|
||||
// 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})]
|
||||
|
||||
path, _ := fileutils.FindDir("tests")
|
||||
@@ -69,11 +69,11 @@ func (cfg *AutoPostCreator) UploadTestFile(c *request.Context) ([]string, error)
|
||||
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, "")
|
||||
}
|
||||
|
||||
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
|
||||
if cfg.HasImage {
|
||||
var err error
|
||||
|
||||
@@ -78,7 +78,7 @@ func CreateBasicUser(a *app.App, client *model.Client4) error {
|
||||
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 userName string
|
||||
if cfg.Fuzzy {
|
||||
@@ -113,7 +113,7 @@ func (cfg *AutoUserCreator) createRandomUser(c *request.Context) (*model.User, e
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
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 == "" {
|
||||
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 {
|
||||
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)
|
||||
|
||||
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 == "" {
|
||||
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/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/i18n"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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)
|
||||
|
||||
prefJSON, jsonErr := json.Marshal(pref)
|
||||
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))
|
||||
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{}
|
||||
targetUsersSlice := []string{args.UserId}
|
||||
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
|
||||
|
||||
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 == "" {
|
||||
return &model.CommandResponse{
|
||||
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) {
|
||||
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)
|
||||
|
||||
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 noChannelErr *model.AppError
|
||||
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)
|
||||
if err != nil {
|
||||
mlog.Error("failed command /"+CmdTest, mlog.Err(err))
|
||||
c.Logger().Error("failed command /"+CmdTest, mlog.Err(err))
|
||||
}
|
||||
|
||||
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
|
||||
if !*a.Config().ServiceSettings.EnableTesting {
|
||||
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}
|
||||
}
|
||||
|
||||
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"))
|
||||
doTeams := contains(tokens, "teams")
|
||||
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
|
||||
}
|
||||
|
||||
mlog.Info("Testing environment created")
|
||||
c.Logger().Info("Testing environment created")
|
||||
for i := 0; i < len(environment.Teams); i++ {
|
||||
mlog.Info("Team Created: " + environment.Teams[i].Name)
|
||||
mlog.Info("\t User to login: " + environment.Environments[i].Users[0].Email + ", " + UserPassword)
|
||||
c.Logger().Info("Team Created: " + environment.Teams[i].Name)
|
||||
c.Logger().Info("\t User to login: " + environment.Environments[i].Users[0].Email + ", " + UserPassword)
|
||||
}
|
||||
} else {
|
||||
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
|
||||
}
|
||||
|
||||
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"))
|
||||
if err := a.UpdateUserActive(c, user_id, true); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
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"))
|
||||
if err := a.UpdateUserActive(c, user_id, false); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
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"))
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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"))
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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"))
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
options := &model.UserGetOptions{InTeamId: args.TeamId, Page: 0, PerPage: 1000}
|
||||
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
|
||||
}
|
||||
|
||||
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"))
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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"))
|
||||
if url == "" {
|
||||
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
|
||||
}
|
||||
|
||||
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"))
|
||||
if url == "" {
|
||||
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.
|
||||
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{
|
||||
ResponseType: model.CommandResponseTypeInChannel,
|
||||
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)
|
||||
|
||||
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 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)
|
||||
|
||||
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)
|
||||
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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.
|
||||
return &model.CommandResponse{
|
||||
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.
|
||||
return &model.CommandResponse{
|
||||
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) {
|
||||
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.
|
||||
return &model.CommandResponse{
|
||||
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 := `¯\\\_(ツ)\_/¯`
|
||||
if message != "" {
|
||||
rmsg = message + " " + rmsg
|
||||
|
||||
@@ -525,7 +525,7 @@ func TestMentionsToTeamMembers(t *testing.T) {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
|
||||
options = append(options, app.ConfigStore(memoryStore))
|
||||
if includeCacheLayer {
|
||||
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 {
|
||||
panic(err2)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
// 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
|
||||
// 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)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
@@ -40,7 +40,7 @@ func (a *App) createDefaultChannelMemberships(c *request.Context, since int64, c
|
||||
_, err = a.AddTeamMember(c, channel.TeamId, userChannel.UserID)
|
||||
if err != nil {
|
||||
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("channel_id", userChannel.ChannelID),
|
||||
mlog.String("team_id", channel.TeamId),
|
||||
@@ -49,7 +49,7 @@ func (a *App) createDefaultChannelMemberships(c *request.Context, since int64, c
|
||||
}
|
||||
return err
|
||||
}
|
||||
a.Log().Info("added teammember",
|
||||
c.Logger().Info("added teammember",
|
||||
mlog.String("user_id", userChannel.UserID),
|
||||
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.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("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("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.
|
||||
// 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.
|
||||
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)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
@@ -93,7 +93,7 @@ func (a *App) createDefaultTeamMemberships(c *request.Context, since int64, team
|
||||
_, err := a.AddTeamMember(c, userTeam.TeamID, userTeam.UserID)
|
||||
if err != nil {
|
||||
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("team_id", userTeam.TeamID),
|
||||
)
|
||||
@@ -102,7 +102,7 @@ func (a *App) createDefaultTeamMemberships(c *request.Context, since int64, team
|
||||
return err
|
||||
}
|
||||
|
||||
a.Log().Info("added teammember",
|
||||
c.Logger().Info("added teammember",
|
||||
mlog.String("user_id", userTeam.UserID),
|
||||
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
|
||||
// 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.
|
||||
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)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
@@ -160,7 +160,7 @@ func (a *App) deleteGroupConstrainedTeamMemberships(c *request.Context, teamID *
|
||||
return err
|
||||
}
|
||||
|
||||
a.Log().Info("removed teammember",
|
||||
c.Logger().Info("removed teammember",
|
||||
mlog.String("user_id", userTeam.UserId),
|
||||
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
|
||||
// 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.
|
||||
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)
|
||||
if appErr != nil {
|
||||
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
|
||||
// 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)
|
||||
|
||||
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:
|
||||
a.createDefaultTeamMemberships(c, since, &syncableID, includeRemovedMembers)
|
||||
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:
|
||||
a.createDefaultChannelMemberships(c, since, &syncableID, includeRemovedMembers)
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
88
app/team.go
88
app/team.go
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
func (a *App) sendTeamEvent(team *model.Team, event string) {
|
||||
func (a *App) sendTeamEvent(team *model.Team, event string) *model.AppError {
|
||||
sanitizedTeam := &model.Team{}
|
||||
*sanitizedTeam = *team
|
||||
sanitizedTeam.Sanitize()
|
||||
@@ -407,10 +420,11 @@ func (a *App) sendTeamEvent(team *model.Team, event string) {
|
||||
message := model.NewWebSocketEvent(event, teamID, "", "", nil)
|
||||
teamJSON, jsonErr := json.Marshal(team)
|
||||
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))
|
||||
a.Publish(message)
|
||||
return nil
|
||||
}
|
||||
|
||||
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.sendUpdatedMemberRoleEvent(userID, member)
|
||||
if appErr := a.sendUpdatedMemberRoleEvent(userID, member); appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
return member, nil
|
||||
}
|
||||
@@ -544,22 +560,25 @@ func (a *App) UpdateTeamMemberSchemeRoles(teamID string, userID string, isScheme
|
||||
|
||||
a.ClearSessionCacheForUser(userID)
|
||||
|
||||
a.sendUpdatedMemberRoleEvent(userID, member)
|
||||
if appErr := a.sendUpdatedMemberRoleEvent(userID, member); appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
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)
|
||||
tmJSON, jsonErr := json.Marshal(member)
|
||||
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))
|
||||
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)
|
||||
go func() {
|
||||
team, err := a.Srv().Store.Team().Get(teamID)
|
||||
@@ -1059,7 +1078,7 @@ func (a *App) GetCommonTeamIDsForTwoUsers(userID, otherUserID string) ([]string,
|
||||
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, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1152,7 +1171,7 @@ func (a *App) GetTeamUnread(teamID, userID string) (*model.TeamUnread, *model.Ap
|
||||
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)
|
||||
go func() {
|
||||
team, err := a.Srv().Store.Team().Get(teamID)
|
||||
@@ -1245,7 +1264,7 @@ func (a *App) postProcessTeamMemberLeave(c request.CTX, teamMember *model.TeamMe
|
||||
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)
|
||||
if err != nil {
|
||||
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 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 {
|
||||
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
|
||||
}
|
||||
|
||||
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{
|
||||
ChannelId: channel.Id,
|
||||
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
|
||||
}
|
||||
|
||||
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{
|
||||
ChannelId: channel.Id,
|
||||
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)
|
||||
}
|
||||
|
||||
a.sendTeamEvent(team, model.WebsocketEventDeleteTeam)
|
||||
if appErr := a.sendTeamEvent(team, model.WebsocketEventDeleteTeam); appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -2022,7 +2048,9 @@ func (a *App) SetTeamIconFromFile(team *model.Team, file io.Reader) *model.AppEr
|
||||
// manually set time to avoid possible cluster inconsistencies
|
||||
team.LastTeamIconUpdate = curTime
|
||||
|
||||
a.sendTeamEvent(team, model.WebsocketEventUpdateTeam)
|
||||
if appErr := a.sendTeamEvent(team, model.WebsocketEventUpdateTeam); appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -2039,7 +2067,9 @@ func (a *App) RemoveTeamIcon(teamID string) *model.AppError {
|
||||
|
||||
team.LastTeamIconUpdate = 0
|
||||
|
||||
a.sendTeamEvent(team, model.WebsocketEventUpdateTeam)
|
||||
if appErr := a.sendTeamEvent(team, model.WebsocketEventUpdateTeam); appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -2072,15 +2102,14 @@ func (a *App) InvalidateAllResendInviteEmailJobs() *model.AppError {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) ClearTeamMembersCache(teamID string) {
|
||||
func (a *App) ClearTeamMembersCache(teamID string) error {
|
||||
perPage := 100
|
||||
page := 0
|
||||
|
||||
for {
|
||||
teamMembers, err := a.Srv().Store.Team().GetMembers(teamID, page*perPage, perPage, nil)
|
||||
if err != nil {
|
||||
a.Log().Warn("error clearing cache for team members", mlog.String("team_id", teamID), mlog.String("err", err.Error()))
|
||||
break
|
||||
return fmt.Errorf("failed to get team members: %v", err)
|
||||
}
|
||||
|
||||
for _, teamMember := range teamMembers {
|
||||
@@ -2089,7 +2118,7 @@ func (a *App) ClearTeamMembersCache(teamID string) {
|
||||
message := model.NewWebSocketEvent(model.WebsocketEventMemberroleUpdated, "", "", teamMember.UserId, nil)
|
||||
tmJSON, jsonErr := json.Marshal(teamMember)
|
||||
if jsonErr != nil {
|
||||
mlog.Warn("Failed to encode team member to JSON", mlog.Err(jsonErr))
|
||||
return jsonErr
|
||||
}
|
||||
message.Add("member", string(tmJSON))
|
||||
a.Publish(message)
|
||||
@@ -2102,4 +2131,5 @@ func (a *App) ClearTeamMembersCache(teamID string) {
|
||||
|
||||
page++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1433,7 +1433,7 @@ func TestClearTeamMembersCache(t *testing.T) {
|
||||
mockStore.On("Team").Return(&mockTeamStore)
|
||||
mockStore.On("GetDBSchemaVersion").Return(1, nil)
|
||||
|
||||
th.App.ClearTeamMembersCache("teamID")
|
||||
require.NoError(t, th.App.ClearTeamMembersCache("teamID"))
|
||||
}
|
||||
|
||||
func TestInviteNewUsersToTeamGracefully(t *testing.T) {
|
||||
|
||||
13
app/user.go
13
app/user.go
@@ -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"))
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
user, err := a.GetUser(userID)
|
||||
@@ -928,7 +928,7 @@ func (a *App) invalidateUserChannelMembersCaches(c request.CTX, userID string) *
|
||||
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()
|
||||
if active {
|
||||
user.DeleteAt = 0
|
||||
@@ -1220,7 +1220,7 @@ func (a *App) UpdateUser(c request.CTX, user *model.User, sendNotifications bool
|
||||
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)
|
||||
|
||||
if err != nil {
|
||||
@@ -1416,7 +1416,6 @@ func (a *App) CreatePasswordRecoveryToken(userID, email string) (*model.Token, *
|
||||
email,
|
||||
}
|
||||
jsonData, err := json.Marshal(tokenExtra)
|
||||
|
||||
if err != nil {
|
||||
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)
|
||||
memberJSON, jsonErr := json.Marshal(member)
|
||||
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))
|
||||
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)
|
||||
memberJSON, jsonErr := json.Marshal(member)
|
||||
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))
|
||||
a.Publish(evt)
|
||||
@@ -2518,7 +2517,7 @@ func (a *App) UpdateThreadFollowForUserFromChannelAdd(c request.CTX, userID, tea
|
||||
|
||||
payload, jsonErr := json.Marshal(userThread)
|
||||
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("previous_unread_replies", int64(0))
|
||||
|
||||
@@ -157,8 +157,8 @@ func (a *App) HubUnregister(webConn *WebConn) {
|
||||
}
|
||||
|
||||
func (s *Server) Publish(message *model.WebSocketEvent) {
|
||||
if s.Metrics != nil {
|
||||
s.Metrics.IncrementWebsocketEvent(message.EventType())
|
||||
if s.GetMetrics() != nil {
|
||||
s.GetMetrics().IncrementWebsocketEvent(message.EventType())
|
||||
}
|
||||
|
||||
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
|
||||
// NewServer itself.
|
||||
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)
|
||||
}
|
||||
select {
|
||||
@@ -525,7 +525,7 @@ func (h *Hub) Start() {
|
||||
connIndex.Remove(directMsg.conn)
|
||||
}
|
||||
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)
|
||||
}
|
||||
msg = msg.PrecomputeJSON()
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/app/request"
|
||||
"github.com/mattermost/mattermost-server/v6/audit"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
|
||||
@@ -229,7 +230,7 @@ func bulkExportCmdF(command *cobra.Command, args []string) error {
|
||||
var opts model.BulkExportOpts
|
||||
opts.IncludeAttachments = attachments
|
||||
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())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2045,10 +2045,6 @@
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"translation": "Feature requires an upgrade to Enterprise Edition."
|
||||
@@ -6155,6 +6151,10 @@
|
||||
"id": "app.team.clear_all_custom_role_assignments.select.app_error",
|
||||
"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",
|
||||
"translation": "Unable to find the existing team."
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/app/request"
|
||||
"github.com/mattermost/mattermost-server/v6/jobs"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/services/configservice"
|
||||
@@ -18,7 +19,8 @@ const jobName = "ExportProcess"
|
||||
type AppIface interface {
|
||||
configservice.ConfigService
|
||||
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 {
|
||||
@@ -45,7 +47,7 @@ func MakeWorker(jobServer *jobs.JobServer, app AppIface) model.Worker {
|
||||
errCh <- appErr
|
||||
}()
|
||||
|
||||
appErr := app.BulkExport(wr, outPath, opts)
|
||||
appErr := app.BulkExport(request.EmptyContext(app.Log()), wr, outPath, opts)
|
||||
if err := wr.Close(); err != nil {
|
||||
mlog.Warn("Worker: error closing writer")
|
||||
}
|
||||
|
||||
@@ -98,11 +98,11 @@ func (f *FeatureFlags) SetDefaults() {
|
||||
f.GraphQL = false
|
||||
f.InsightsEnabled = true
|
||||
f.CommandPalette = false
|
||||
f.PostForwarding = false
|
||||
f.PostForwarding = true
|
||||
f.AdvancedTextEditor = true
|
||||
f.CallsEnabled = true
|
||||
f.BoardsProduct = false
|
||||
f.PlanUpgradeButtonText = "Upgrade"
|
||||
f.PlanUpgradeButtonText = "upgrade"
|
||||
}
|
||||
|
||||
func (f *FeatureFlags) Plugins() map[string]string {
|
||||
|
||||
@@ -269,13 +269,13 @@ func (_m *MockAppIface) InvalidateCacheForUser(userID string) {
|
||||
_m.Called(userID)
|
||||
}
|
||||
|
||||
// MentionsToTeamMembers provides a mock function with given fields: message, teamID
|
||||
func (_m *MockAppIface) MentionsToTeamMembers(message string, teamID string) model.UserMentionMap {
|
||||
ret := _m.Called(message, teamID)
|
||||
// MentionsToTeamMembers provides a mock function with given fields: c, message, teamID
|
||||
func (_m *MockAppIface) MentionsToTeamMembers(c request.CTX, message string, teamID string) model.UserMentionMap {
|
||||
ret := _m.Called(c, message, teamID)
|
||||
|
||||
var r0 model.UserMentionMap
|
||||
if rf, ok := ret.Get(0).(func(string, string) model.UserMentionMap); ok {
|
||||
r0 = rf(message, teamID)
|
||||
if rf, ok := ret.Get(0).(func(request.CTX, string, string) model.UserMentionMap); ok {
|
||||
r0 = rf(c, message, teamID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
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)
|
||||
CreateUploadSession(c request.CTX, us *model.UploadSession) (*model.UploadSession, *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)
|
||||
InvalidateCacheForUser(userID string)
|
||||
NotifySharedChannelUserUpdate(user *model.User)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"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/services/remotecluster"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
@@ -271,7 +272,7 @@ func (scs *Service) fetchPostUsersForSync(sd *syncData) error {
|
||||
userIDs[post.UserId] = p2mm{}
|
||||
|
||||
// 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 {
|
||||
userIDs[userID] = p2mm{
|
||||
post: post,
|
||||
|
||||
@@ -368,7 +368,10 @@ func (b *S3FileBackend) WriteFile(fr io.Reader, path string) (int64, error) {
|
||||
options := s3PutOptions(b.encrypt, contentType)
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -401,7 +404,10 @@ func (b *S3FileBackend) AppendFile(fr io.Reader, path string) (int64, error) {
|
||||
ctx2, cancel2 := context.WithTimeout(context.Background(), b.timeout)
|
||||
defer cancel2()
|
||||
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()
|
||||
}
|
||||
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 {
|
||||
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.AddOrder(p.Id)
|
||||
}
|
||||
@@ -2188,7 +2195,7 @@ func (s *SqlPostStore) AnalyticsPostCountsByDay(options *model.AnalyticsPostCoun
|
||||
|
||||
func (s *SqlPostStore) AnalyticsPostCount(options *model.PostCountOptions) (int64, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("COUNT(p.Id) AS Value").
|
||||
Select("COUNT(*) AS Value").
|
||||
From("Posts p")
|
||||
|
||||
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.
|
||||
Set("ReplyCount", sq.Expr("ReplyCount - 1")).
|
||||
Set("LastReplyAt", lastReplyAtSubquery).
|
||||
Set("ReplyCount", lastReplyCountSubquery).
|
||||
Where(sq.And{
|
||||
sq.Eq{"PostId": rootId},
|
||||
sq.Gt{"ReplyCount": 0},
|
||||
|
||||
@@ -1500,17 +1500,20 @@ func generateSearchQuery(query sq.SelectBuilder, terms []string, fields []string
|
||||
for _, term := range terms {
|
||||
searchFields := []string{}
|
||||
termArgs := []any{}
|
||||
var dbSpecificTerm string
|
||||
|
||||
for _, field := range fields {
|
||||
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 {
|
||||
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...)
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
|
||||
@@ -569,6 +569,7 @@ func testPostStoreGetForThread(t *testing.T, ss store.Store) {
|
||||
})
|
||||
|
||||
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()})
|
||||
require.NoError(t, err)
|
||||
_, 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{})
|
||||
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)
|
||||
|
||||
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{})
|
||||
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.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{})
|
||||
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) {
|
||||
|
||||
@@ -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("GetKnownUsers", func(t *testing.T) { testGetKnownUsers(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) {
|
||||
@@ -6010,3 +6011,174 @@ func testGetUsersWithInvalidEmails(t *testing.T, ss store.Store) {
|
||||
require.NoError(t, err)
|
||||
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 {
|
||||
// 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 {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user