diff --git a/app/user.go b/app/user.go index 6e12bda34b..d259439859 100644 --- a/app/user.go +++ b/app/user.go @@ -316,7 +316,11 @@ func (a *App) createUserOrGuest(c request.CTX, user *model.User, guest bool) (*m }, plugin.UserHasBeenCreatedID) }) - // Create/Update the subscriptionHistoryEvent + // For cloud yearly subscriptions, if the current user count of the workspace exceeds the number of seats initially purchased + // (plus the “threshold” of 10%), then a subscriptionHistoryEvent object would need to be created and added to the subscriptionHistory + // table in CWS. This is then used to calculate how much the customers have to pay in addition for the extra users. If the + // workspace is currently on a monthly plan, then this function will not do anything. + go func() { _, err := a.SendSubscriptionHistoryEvent(ruser.Id) if err != nil { diff --git a/build/Dockerfile b/build/Dockerfile index d373e54fdc..aaa82b99ca 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -8,7 +8,7 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"] ENV PATH="/mattermost/bin:${PATH}" ARG PUID=2000 ARG PGID=2000 -ARG MM_PACKAGE="https://releases.mattermost.com/7.5.1/mattermost-7.5.1-linux-amd64.tar.gz?src=docker" +ARG MM_PACKAGE="https://releases.mattermost.com/7.5.2/mattermost-7.5.2-linux-amd64.tar.gz?src=docker" # # Install needed packages and indirect dependencies RUN apt-get update \ diff --git a/cmd/mattermost/commands/db.go b/cmd/mattermost/commands/db.go index db33032297..c0d186c265 100644 --- a/cmd/mattermost/commands/db.go +++ b/cmd/mattermost/commands/db.go @@ -10,6 +10,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" + "github.com/mattermost/mattermost-server/v6/app" "github.com/mattermost/mattermost-server/v6/audit" "github.com/mattermost/mattermost-server/v6/config" "github.com/mattermost/mattermost-server/v6/store/sqlstore" @@ -100,7 +101,7 @@ func initDbCmdF(command *cobra.Command, _ []string) error { } func resetCmdF(command *cobra.Command, args []string) error { - a, err := InitDBCommandContextCobra(command) + a, err := InitDBCommandContextCobra(command, app.SkipPostInitialization()) if err != nil { return err } diff --git a/cmd/mattermost/commands/export.go b/cmd/mattermost/commands/export.go index fa0f251e1b..d5573ee975 100644 --- a/cmd/mattermost/commands/export.go +++ b/cmd/mattermost/commands/export.go @@ -10,6 +10,7 @@ import ( "path/filepath" "time" + "github.com/mattermost/mattermost-server/v6/app" "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/audit" "github.com/mattermost/mattermost-server/v6/model" @@ -93,7 +94,7 @@ func init() { } func scheduleExportCmdF(command *cobra.Command, args []string) error { - a, err := InitDBCommandContextCobra(command) + a, err := InitDBCommandContextCobra(command, app.SkipPostInitialization()) if err != nil { return err } @@ -153,7 +154,7 @@ func scheduleExportCmdF(command *cobra.Command, args []string) error { func buildExportCmdF(format string) func(command *cobra.Command, args []string) error { return func(command *cobra.Command, args []string) error { - a, err := InitDBCommandContextCobra(command) + a, err := InitDBCommandContextCobra(command, app.SkipPostInitialization()) license := a.Srv().License() if err != nil { return err @@ -201,7 +202,7 @@ func buildExportCmdF(format string) func(command *cobra.Command, args []string) } func bulkExportCmdF(command *cobra.Command, args []string) error { - a, err := InitDBCommandContextCobra(command) + a, err := InitDBCommandContextCobra(command, app.SkipPostInitialization()) if err != nil { return err } diff --git a/cmd/mattermost/commands/init.go b/cmd/mattermost/commands/init.go index e93d9640fe..1c7e8baf07 100644 --- a/cmd/mattermost/commands/init.go +++ b/cmd/mattermost/commands/init.go @@ -14,8 +14,8 @@ import ( "github.com/mattermost/mattermost-server/v6/utils" ) -func initDBCommandContextCobra(command *cobra.Command, readOnlyConfigStore bool) (*app.App, error) { - a, err := initDBCommandContext(getConfigDSN(command, config.GetEnvironment()), readOnlyConfigStore) +func initDBCommandContextCobra(command *cobra.Command, readOnlyConfigStore bool, options ...app.Option) (*app.App, error) { + a, err := initDBCommandContext(getConfigDSN(command, config.GetEnvironment()), readOnlyConfigStore, options...) if err != nil { // Returning an error just prints the usage message, so actually panic panic(err) @@ -27,25 +27,19 @@ func initDBCommandContextCobra(command *cobra.Command, readOnlyConfigStore bool) return a, nil } -func InitDBCommandContextCobra(command *cobra.Command) (*app.App, error) { - return initDBCommandContextCobra(command, true) +func InitDBCommandContextCobra(command *cobra.Command, options ...app.Option) (*app.App, error) { + return initDBCommandContextCobra(command, true, options...) } -func InitDBCommandContextCobraReadWrite(command *cobra.Command) (*app.App, error) { - return initDBCommandContextCobra(command, false) -} - -func initDBCommandContext(configDSN string, readOnlyConfigStore bool) (*app.App, error) { +func initDBCommandContext(configDSN string, readOnlyConfigStore bool, options ...app.Option) (*app.App, error) { if err := utils.TranslationsPreInit(); err != nil { return nil, err } model.AppErrorInit(i18n.T) - s, err := app.NewServer( - // The option order is important as app.Config option reads app.StartMetrics option. - app.StartMetrics, - app.Config(configDSN, readOnlyConfigStore, nil), - ) + // The option order is important as app.Config option reads app.StartMetrics option. + options = append(options, app.Config(configDSN, readOnlyConfigStore, nil)) + s, err := app.NewServer(options...) if err != nil { return nil, err } diff --git a/cmd/mattermost/commands/jobserver.go b/cmd/mattermost/commands/jobserver.go index 488b3f8fe7..be59971aab 100644 --- a/cmd/mattermost/commands/jobserver.go +++ b/cmd/mattermost/commands/jobserver.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/cobra" + "github.com/mattermost/mattermost-server/v6/app" "github.com/mattermost/mattermost-server/v6/audit" "github.com/mattermost/mattermost-server/v6/config" "github.com/mattermost/mattermost-server/v6/shared/mlog" @@ -34,7 +35,7 @@ func jobserverCmdF(command *cobra.Command, args []string) error { noSchedule, _ := command.Flags().GetBool("noschedule") // Initialize - a, err := initDBCommandContext(getConfigDSN(command, config.GetEnvironment()), false) + a, err := initDBCommandContext(getConfigDSN(command, config.GetEnvironment()), false, app.StartMetrics) if err != nil { return err } diff --git a/cmd/mattermost/commands/test.go b/cmd/mattermost/commands/test.go index 75c49a4ee7..1a50d53221 100644 --- a/cmd/mattermost/commands/test.go +++ b/cmd/mattermost/commands/test.go @@ -14,6 +14,7 @@ import ( "github.com/spf13/cobra" "github.com/mattermost/mattermost-server/v6/api4" + "github.com/mattermost/mattermost-server/v6/app" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/shared/i18n" "github.com/mattermost/mattermost-server/v6/wsapi" @@ -46,7 +47,7 @@ func init() { } func webClientTestsCmdF(command *cobra.Command, args []string) error { - a, err := InitDBCommandContextCobra(command) + a, err := InitDBCommandContextCobra(command, app.StartMetrics) if err != nil { return err } @@ -70,7 +71,7 @@ func webClientTestsCmdF(command *cobra.Command, args []string) error { } func serverForWebClientTestsCmdF(command *cobra.Command, args []string) error { - a, err := InitDBCommandContextCobra(command) + a, err := InitDBCommandContextCobra(command, app.StartMetrics) if err != nil { return err } diff --git a/config/client.go b/config/client.go index b8160993fd..e26c2bea40 100644 --- a/config/client.go +++ b/config/client.go @@ -92,6 +92,8 @@ func GenerateClientConfig(c *model.Config, telemetryID string, license *model.Li props["EnableEmailInvitations"] = strconv.FormatBool(*c.ServiceSettings.EnableEmailInvitations) + props["CWSURL"] = *c.CloudSettings.CWSURL + // Set default values for all options that require a license. props["ExperimentalEnableAuthenticationTransfer"] = "true" props["LdapNicknameAttributeSet"] = "false" @@ -123,7 +125,6 @@ func GenerateClientConfig(c *model.Config, telemetryID string, license *model.Li props["DataRetentionFileRetentionDays"] = "0" props["DataRetentionEnableBoardsDeletion"] = "false" props["DataRetentionBoardsRetentionDays"] = "0" - props["CWSURL"] = "" props["CustomUrlSchemes"] = strings.Join(c.DisplaySettings.CustomURLSchemes, ",") props["IsDefaultMarketplace"] = strconv.FormatBool(*c.PluginSettings.MarketplaceURL == model.PluginSettingsDefaultMarketplaceURL) @@ -195,10 +196,6 @@ func GenerateClientConfig(c *model.Config, telemetryID string, license *model.Li props["DataRetentionBoardsRetentionDays"] = strconv.FormatInt(int64(*c.DataRetentionSettings.BoardsRetentionDays), 10) } - if license.IsCloud() { - props["CWSURL"] = *c.CloudSettings.CWSURL - } - if *license.Features.SharedChannels { props["ExperimentalSharedChannels"] = strconv.FormatBool(*c.ExperimentalSettings.EnableSharedChannels) props["ExperimentalRemoteClusterService"] = strconv.FormatBool(c.FeatureFlags.EnableRemoteClusterService && *c.ExperimentalSettings.EnableRemoteClusterService) diff --git a/go.mod b/go.mod index c157155e51..2e04b4e93c 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 github.com/lib/pq v1.10.7 + github.com/mattermost/focalboard/server v0.0.0-20221222174020-fd4cf95f8ac9 github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 github.com/mattermost/gziphandler v0.0.1 github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d @@ -85,6 +86,7 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/bits-and-blooms/bitset v1.3.3 // indirect github.com/bits-and-blooms/bloom/v3 v3.3.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/blevesearch/bleve_index_api v1.0.5 // indirect github.com/blevesearch/geo v0.1.15 // indirect github.com/blevesearch/go-porterstemmer v1.0.3 // indirect @@ -131,10 +133,10 @@ require ( github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/levigross/exp-html v0.0.0-20120902181939-8df60c69a8f5 // indirect + github.com/mattermost/mattermost-plugin-api v0.0.29-0.20220801143717-73008cfda2fb // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -179,7 +181,7 @@ require ( gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect - lukechampine.com/uint128 v1.1.1 // indirect + lukechampine.com/uint128 v1.2.0 // indirect modernc.org/cc/v3 v3.36.0 // indirect modernc.org/ccgo/v3 v3.16.6 // indirect modernc.org/libc v1.16.7 // indirect diff --git a/go.sum b/go.sum index 5bfeee94ff..196d356a53 100644 --- a/go.sum +++ b/go.sum @@ -216,6 +216,8 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/blevesearch/bleve/v2 v2.3.6-0.20221111171245-56dc9b25507e h1:r/cWPLUPgAM3SWWniQ6j0Hzb++h+uEycDD9UOUuC1Vk= github.com/blevesearch/bleve/v2 v2.3.6-0.20221111171245-56dc9b25507e/go.mod h1:mfCWvuwg/XnPVZHEejATm5TyFqyeLmm8p9Y3xDvwz4k= github.com/blevesearch/bleve_index_api v1.0.3/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= @@ -979,6 +981,8 @@ github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsI github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattermost/focalboard/server v0.0.0-20221222174020-fd4cf95f8ac9 h1:UE3KuILWJwTnaXAy2YHqkCu1f7i+VdX2VNukBGYbPuI= +github.com/mattermost/focalboard/server v0.0.0-20221222174020-fd4cf95f8ac9/go.mod h1:h1HQ8UVoNMyDHzjPD7UtYbTPMWjP6d1qJZuLdT6ElNg= github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 h1:Khvh6waxG1cHc4Cz5ef9n3XVCxRWpAKUtqg9PJl5+y8= github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34= github.com/mattermost/gziphandler v0.0.1 h1:uXHcXF5agnQ6bXabvpiwwwZOlCYoa7mKHH0lxns/o8w= @@ -987,6 +991,8 @@ github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d h1:/RJ/UV7M5c7L2TQ github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ= github.com/mattermost/logr/v2 v2.0.15 h1:+WNbGcsc3dBao65eXlceB6dTILNJRIrvubnsTl3zBew= github.com/mattermost/logr/v2 v2.0.15/go.mod h1:mpPp935r5dIkFDo2y9Q87cQWhFR/4xXpNh0k/y8Hmwg= +github.com/mattermost/mattermost-plugin-api v0.0.29-0.20220801143717-73008cfda2fb h1:q1qXKVv59rA2gcQ7lVLc5OlWBmfsR3i8mdGD5EZesyk= +github.com/mattermost/mattermost-plugin-api v0.0.29-0.20220801143717-73008cfda2fb/go.mod h1:PIeo40t9VTA4Wu1FwjzH7QmcgC3SRyk/ohCwJw4/oSo= github.com/mattermost/morph v1.0.5-0.20221115094356-4c18a75b1f5e h1:VfNz+fvJ3DxOlALM22Eea8ONp5jHrybKBCcCtDPVlss= github.com/mattermost/morph v1.0.5-0.20221115094356-4c18a75b1f5e/go.mod h1:xo0ljDknTpPxEdhhrUdwhLCexIsYyDKS6b41HqG8wGU= github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0 h1:G9tL6JXRBMzjuD1kkBtcnd42kUiT6QDwxfFYu7adM6o= @@ -1028,7 +1034,6 @@ github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= -github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= @@ -2282,8 +2287,9 @@ k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg= modernc.org/cc/v3 v3.32.4/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878= modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo= diff --git a/product/api.go b/product/api.go index 5067c20ce9..587f9d788c 100644 --- a/product/api.go +++ b/product/api.go @@ -12,6 +12,8 @@ import ( "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/shared/filestore" "github.com/mattermost/mattermost-server/v6/shared/mlog" + + fb_model "github.com/mattermost/focalboard/server/model" ) // RouterService enables registering the product router to the server. After registering the @@ -189,3 +191,22 @@ type PreferencesService interface { UpdatePreferencesForUser(userID string, preferences model.Preferences) *model.AppError DeletePreferencesForUser(userID string, preferences model.Preferences) *model.AppError } + +// BoardsService is the API for accessing Boards service APIs. +// +// The service shall be registered via app.BoardsKey service key. +type BoardsService interface { + GetTemplates(teamID string, userID string) ([]*fb_model.Board, error) + GetBoard(boardID string) (*fb_model.Board, error) + CreateBoard(board *fb_model.Board, userID string, addmember bool) (*fb_model.Board, error) + PatchBoard(boardPatch *fb_model.BoardPatch, boardID string, userID string) (*fb_model.Board, error) + DeleteBoard(boardID string, userID string) error + SearchBoards(searchTerm string, searchField fb_model.BoardSearchField, userID string, includePublicBoards bool) ([]*fb_model.Board, error) + LinkBoardToChannel(boardID string, channelID string, userID string) (*fb_model.Board, error) + GetCards(boardID string) ([]*fb_model.Card, error) + GetCard(cardID string) (*fb_model.Card, error) + CreateCard(card *fb_model.Card, boardID string, userID string) (*fb_model.Card, error) + PatchCard(cardPatch *fb_model.CardPatch, cardID string, userID string) (*fb_model.Card, error) + DeleteCard(cardID string, userID string) error + HasPermissionToBoard(userID, boardID string, permission *model.Permission) bool +} diff --git a/product/service.go b/product/service.go index 221fa1c168..a0a92e6adc 100644 --- a/product/service.go +++ b/product/service.go @@ -25,4 +25,5 @@ const ( StoreKey ServiceKey = "storekey" SystemKey ServiceKey = "systemkey" PreferencesKey ServiceKey = "preferenceskey" + BoardsKey ServiceKey = "boards" ) diff --git a/store/opentracinglayer/opentracinglayer.go b/store/opentracinglayer/opentracinglayer.go index e15fc3830d..289b7f9582 100644 --- a/store/opentracinglayer/opentracinglayer.go +++ b/store/opentracinglayer/opentracinglayer.go @@ -3207,7 +3207,7 @@ func (s *OpenTracingLayerComplianceStore) GetAll(offset int, limit int) (model.C return result, err } -func (s *OpenTracingLayerComplianceStore) MessageExport(cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { +func (s *OpenTracingLayerComplianceStore) MessageExport(ctx context.Context, cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ComplianceStore.MessageExport") s.Root.Store.SetContext(newCtx) @@ -3216,7 +3216,7 @@ func (s *OpenTracingLayerComplianceStore) MessageExport(cursor model.MessageExpo }() defer span.Finish() - result, resultVar1, err := s.ComplianceStore.MessageExport(cursor, limit) + result, resultVar1, err := s.ComplianceStore.MessageExport(ctx, cursor, limit) if err != nil { span.LogFields(spanlog.Error(err)) ext.Error.Set(span, true) diff --git a/store/retrylayer/retrylayer.go b/store/retrylayer/retrylayer.go index 9668e55c77..c474c10718 100644 --- a/store/retrylayer/retrylayer.go +++ b/store/retrylayer/retrylayer.go @@ -3577,11 +3577,11 @@ func (s *RetryLayerComplianceStore) GetAll(offset int, limit int) (model.Complia } -func (s *RetryLayerComplianceStore) MessageExport(cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { +func (s *RetryLayerComplianceStore) MessageExport(ctx context.Context, cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { tries := 0 for { - result, resultVar1, err := s.ComplianceStore.MessageExport(cursor, limit) + result, resultVar1, err := s.ComplianceStore.MessageExport(ctx, cursor, limit) if err == nil { return result, resultVar1, nil } diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go index 85864f3784..ca7575924a 100644 --- a/store/sqlstore/channel_store.go +++ b/store/sqlstore/channel_store.go @@ -3850,7 +3850,31 @@ func (s SqlChannelStore) MigrateChannelMembers(fromChannelId string, fromUserId defer finalizeTransactionX(transaction, &err) channelMembers := []channelMember{} - if err := transaction.Select(&channelMembers, "SELECT * from ChannelMembers WHERE (ChannelId, UserId) > (?, ?) ORDER BY ChannelId, UserId LIMIT 100", fromChannelId, fromUserId); err != nil { + query := ` + SELECT + ChannelId, + UserId, + Roles, + LastViewedAt, + MsgCount, + MentionCount, + MentionCountRoot, + COALESCE(UrgentMentionCount, 0) AS UrgentMentionCount, + MsgCountRoot, + NotifyProps, + LastUpdateAt, + SchemeUser, + SchemeAdmin, + SchemeGuest + FROM + ChannelMembers + WHERE + (ChannelId, UserId) > (?, ?) + ORDER BY ChannelId, UserId + LIMIT 100 + ` + + if err := transaction.Select(&channelMembers, query, fromChannelId, fromUserId); err != nil { return nil, errors.Wrap(err, "failed to find ChannelMembers") } @@ -3954,7 +3978,31 @@ func (s SqlChannelStore) ClearAllCustomRoleAssignments() (err error) { } channelMembers := []*channelMember{} - if err = transaction.Select(&channelMembers, "SELECT * from ChannelMembers WHERE (ChannelId, UserId) > (?, ?) ORDER BY ChannelId, UserId LIMIT 1000", lastChannelId, lastUserId); err != nil { + query := ` + SELECT + ChannelId, + UserId, + Roles, + LastViewedAt, + MsgCount, + MentionCount, + MentionCountRoot, + COALESCE(UrgentMentionCount, 0) AS UrgentMentionCount, + MsgCountRoot, + NotifyProps, + LastUpdateAt, + SchemeUser, + SchemeAdmin, + SchemeGuest + FROM + ChannelMembers + WHERE + (ChannelId, UserId) > (?, ?) + ORDER BY ChannelId, UserId + LIMIT 1000 + ` + + if err = transaction.Select(&channelMembers, query, lastChannelId, lastUserId); err != nil { finalizeTransactionX(transaction, &err) return errors.Wrap(err, "failed to find ChannelMembers") } diff --git a/store/sqlstore/compliance_store.go b/store/sqlstore/compliance_store.go index 6e2ae38ac1..9c76cea3d6 100644 --- a/store/sqlstore/compliance_store.go +++ b/store/sqlstore/compliance_store.go @@ -4,6 +4,7 @@ package sqlstore import ( + "context" "database/sql" "fmt" "strings" @@ -270,7 +271,7 @@ func (s SqlComplianceStore) ComplianceExport(job *model.Compliance, cursor model return append(channelPosts, directMessagePosts...), cursor, nil } -func (s SqlComplianceStore) MessageExport(cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { +func (s SqlComplianceStore) MessageExport(ctx context.Context, cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { var args []any args = append(args, model.ChannelTypeDirect, model.ChannelTypeGroup, cursor.LastPostUpdateAt, cursor.LastPostUpdateAt, cursor.LastPostId, limit) query := @@ -317,7 +318,7 @@ func (s SqlComplianceStore) MessageExport(cursor model.MessageExportCursor, limi LIMIT ?` cposts := []*model.MessageExport{} - if err := s.GetReplicaX().Select(&cposts, query, args...); err != nil { + if err := s.GetReplicaX().SelectCtx(ctx, &cposts, query, args...); err != nil { return nil, cursor, errors.Wrap(err, "unable to export messages") } if len(cposts) > 0 { diff --git a/store/sqlstore/sqlx_wrapper.go b/store/sqlstore/sqlx_wrapper.go index 95b274aae9..3d215ff8a5 100644 --- a/store/sqlstore/sqlx_wrapper.go +++ b/store/sqlstore/sqlx_wrapper.go @@ -224,8 +224,12 @@ func (w *sqlxDBWrapper) QueryX(query string, args ...any) (*sqlx.Rows, error) { } func (w *sqlxDBWrapper) Select(dest any, query string, args ...any) error { + return w.SelectCtx(context.Background(), dest, query, args...) +} + +func (w *sqlxDBWrapper) SelectCtx(ctx context.Context, dest any, query string, args ...any) error { query = w.DB.Rebind(query) - ctx, cancel := context.WithTimeout(context.Background(), w.queryTimeout) + ctx, cancel := context.WithTimeout(ctx, w.queryTimeout) defer cancel() if w.trace { diff --git a/store/sqlstore/store.go b/store/sqlstore/store.go index bf32b5984b..9a1ceceb2d 100644 --- a/store/sqlstore/store.go +++ b/store/sqlstore/store.go @@ -9,7 +9,7 @@ import ( dbsql "database/sql" "fmt" "log" - "path/filepath" + "path" "strconv" "strings" "sync" @@ -228,7 +228,9 @@ func New(settings model.SqlSettings, metrics einterfaces.MetricsInterface) *SqlS return store } -func setupConnection(connType string, dataSource string, settings *model.SqlSettings) *dbsql.DB { +// SetupConnection sets up the connection to the database and pings it to make sure it's alive. +// It also applies any database configuration settings that are required. +func SetupConnection(connType string, dataSource string, settings *model.SqlSettings) *dbsql.DB { db, err := dbsql.Open(*settings.DriverName, dataSource) if err != nil { mlog.Fatal("Failed to open SQL connection to err.", mlog.Err(err)) @@ -294,7 +296,7 @@ func (ss *SqlStore) initConnection() { } } - handle := setupConnection("master", dataSource, ss.settings) + handle := SetupConnection("master", dataSource, ss.settings) ss.masterX = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()), time.Duration(*ss.settings.QueryTimeout)*time.Second, *ss.settings.Trace) @@ -305,7 +307,7 @@ func (ss *SqlStore) initConnection() { if len(ss.settings.DataSourceReplicas) > 0 { ss.ReplicaXs = make([]*sqlxDBWrapper, len(ss.settings.DataSourceReplicas)) for i, replica := range ss.settings.DataSourceReplicas { - handle := setupConnection(fmt.Sprintf("replica-%v", i), replica, ss.settings) + handle := SetupConnection(fmt.Sprintf("replica-%v", i), replica, ss.settings) ss.ReplicaXs[i] = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()), time.Duration(*ss.settings.QueryTimeout)*time.Second, *ss.settings.Trace) @@ -318,7 +320,7 @@ func (ss *SqlStore) initConnection() { if len(ss.settings.DataSourceSearchReplicas) > 0 { ss.searchReplicaXs = make([]*sqlxDBWrapper, len(ss.settings.DataSourceSearchReplicas)) for i, replica := range ss.settings.DataSourceSearchReplicas { - handle := setupConnection(fmt.Sprintf("search-replica-%v", i), replica, ss.settings) + handle := SetupConnection(fmt.Sprintf("search-replica-%v", i), replica, ss.settings) ss.searchReplicaXs[i] = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()), time.Duration(*ss.settings.QueryTimeout)*time.Second, *ss.settings.Trace) @@ -334,7 +336,7 @@ func (ss *SqlStore) initConnection() { if src.DataSource == nil { continue } - ss.replicaLagHandles[i] = setupConnection(fmt.Sprintf(replicaLagPrefix+"-%d", i), *src.DataSource, ss.settings) + ss.replicaLagHandles[i] = SetupConnection(fmt.Sprintf(replicaLagPrefix+"-%d", i), *src.DataSource, ss.settings) } } } @@ -1047,7 +1049,7 @@ func (ss *SqlStore) hasLicense() bool { func (ss *SqlStore) migrate(direction migrationDirection) error { assets := db.Assets() - assetsList, err := assets.ReadDir(filepath.Join("migrations", ss.DriverName())) + assetsList, err := assets.ReadDir(path.Join("migrations", ss.DriverName())) if err != nil { return err } @@ -1060,7 +1062,7 @@ func (ss *SqlStore) migrate(direction migrationDirection) error { src, err := mbindata.WithInstance(&mbindata.AssetSource{ Names: assetNamesForDriver, AssetFunc: func(name string) ([]byte, error) { - return assets.ReadFile(filepath.Join("migrations", ss.DriverName(), name)) + return assets.ReadFile(path.Join("migrations", ss.DriverName(), name)) }, }) if err != nil { @@ -1079,7 +1081,7 @@ func (ss *SqlStore) migrate(direction migrationDirection) error { if err != nil { return err } - db := setupConnection("master", dataSource, ss.settings) + db := SetupConnection("master", dataSource, ss.settings) driver, err = ms.WithInstance(db) defer db.Close() case model.DatabaseDriverPostgres: diff --git a/store/store.go b/store/store.go index f24c81d4f3..a752cb784a 100644 --- a/store/store.go +++ b/store/store.go @@ -550,7 +550,7 @@ type ComplianceStore interface { Get(id string) (*model.Compliance, error) GetAll(offset, limit int) (model.Compliances, error) ComplianceExport(compliance *model.Compliance, cursor model.ComplianceExportCursor, limit int) ([]*model.CompliancePost, model.ComplianceExportCursor, error) - MessageExport(cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) + MessageExport(ctx context.Context, cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) } type OAuthStore interface { diff --git a/store/storetest/compliance_store.go b/store/storetest/compliance_store.go index f39b1c43ef..7c2d106325 100644 --- a/store/storetest/compliance_store.go +++ b/store/storetest/compliance_store.go @@ -4,6 +4,7 @@ package storetest import ( + "context" "encoding/json" "testing" "time" @@ -399,7 +400,7 @@ func testMessageExportPublicChannel(t *testing.T, ss store.Store) { // get the starting number of message export entries startTime := model.GetMillis() - messages, _, err := ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) + messages, _, err := ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) require.NoError(t, err) assert.Equal(t, 0, len(messages)) @@ -469,7 +470,7 @@ func testMessageExportPublicChannel(t *testing.T, ss store.Store) { // fetch the message exports for both posts that user1 sent messageExportMap := map[string]model.MessageExport{} - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) require.NoError(t, err) assert.Equal(t, 2, len(messages)) @@ -503,7 +504,7 @@ func testMessageExportPrivateChannel(t *testing.T, ss store.Store) { // get the starting number of message export entries startTime := model.GetMillis() - messages, _, err := ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) + messages, _, err := ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) require.NoError(t, err) assert.Equal(t, 0, len(messages)) @@ -573,7 +574,7 @@ func testMessageExportPrivateChannel(t *testing.T, ss store.Store) { // fetch the message exports for both posts that user1 sent messageExportMap := map[string]model.MessageExport{} - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) require.NoError(t, err) assert.Equal(t, 2, len(messages)) @@ -609,7 +610,7 @@ func testMessageExportDirectMessageChannel(t *testing.T, ss store.Store) { // get the starting number of message export entries startTime := model.GetMillis() - messages, _, err := ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) + messages, _, err := ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) require.NoError(t, err) assert.Equal(t, 0, len(messages)) @@ -664,7 +665,7 @@ func testMessageExportDirectMessageChannel(t *testing.T, ss store.Store) { // fetch the message export for the post that user1 sent messageExportMap := map[string]model.MessageExport{} - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) require.NoError(t, err) assert.Equal(t, 1, len(messages)) @@ -690,7 +691,7 @@ func testMessageExportGroupMessageChannel(t *testing.T, ss store.Store) { // get the starting number of message export entries startTime := model.GetMillis() - messages, _, err := ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) + messages, _, err := ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) require.NoError(t, err) assert.Equal(t, 0, len(messages)) @@ -762,7 +763,7 @@ func testMessageExportGroupMessageChannel(t *testing.T, ss store.Store) { // fetch the message export for the post that user1 sent messageExportMap := map[string]model.MessageExport{} - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 10}, 10) require.NoError(t, err) assert.Equal(t, 1, len(messages)) @@ -787,7 +788,7 @@ func testEditExportMessage(t *testing.T, ss store.Store) { defer cleanupStoreState(t, ss) // get the starting number of message export entries startTime := model.GetMillis() - messages, _, err := ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) + messages, _, err := ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 0, len(messages)) @@ -842,7 +843,7 @@ func testEditExportMessage(t *testing.T, ss store.Store) { require.NoError(t, err) // fetch the message exports from the start - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 2, len(messages)) @@ -879,7 +880,7 @@ func testEditAfterExportMessage(t *testing.T, ss store.Store) { defer cleanupStoreState(t, ss) // get the starting number of message export entries startTime := model.GetMillis() - messages, _, err := ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) + messages, _, err := ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 0, len(messages)) @@ -927,7 +928,7 @@ func testEditAfterExportMessage(t *testing.T, ss store.Store) { require.NoError(t, err) // fetch the message exports from the start - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 1, len(messages)) @@ -953,7 +954,7 @@ func testEditAfterExportMessage(t *testing.T, ss store.Store) { require.NoError(t, err) // fetch the message exports after edit - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: postEditTime - 1}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: postEditTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 2, len(messages)) @@ -990,7 +991,7 @@ func testDeleteExportMessage(t *testing.T, ss store.Store) { defer cleanupStoreState(t, ss) // get the starting number of message export entries startTime := model.GetMillis() - messages, _, err := ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) + messages, _, err := ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 0, len(messages)) @@ -1043,7 +1044,7 @@ func testDeleteExportMessage(t *testing.T, ss store.Store) { require.NoError(t, err) // fetch the message exports from the start - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 1, len(messages)) @@ -1075,7 +1076,7 @@ func testDeleteAfterExportMessage(t *testing.T, ss store.Store) { defer cleanupStoreState(t, ss) // get the starting number of message export entries startTime := model.GetMillis() - messages, _, err := ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) + messages, _, err := ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 0, len(messages)) @@ -1123,7 +1124,7 @@ func testDeleteAfterExportMessage(t *testing.T, ss store.Store) { require.NoError(t, err) // fetch the message exports from the start - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: startTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 1, len(messages)) @@ -1146,7 +1147,7 @@ func testDeleteAfterExportMessage(t *testing.T, ss store.Store) { require.NoError(t, err) // fetch the message exports after delete - messages, _, err = ss.Compliance().MessageExport(model.MessageExportCursor{LastPostUpdateAt: postDeleteTime - 1}, 10) + messages, _, err = ss.Compliance().MessageExport(context.Background(), model.MessageExportCursor{LastPostUpdateAt: postDeleteTime - 1}, 10) require.NoError(t, err) assert.Equal(t, 1, len(messages)) diff --git a/store/storetest/mocks/ComplianceStore.go b/store/storetest/mocks/ComplianceStore.go index 657670b023..a1041e3bae 100644 --- a/store/storetest/mocks/ComplianceStore.go +++ b/store/storetest/mocks/ComplianceStore.go @@ -5,6 +5,8 @@ package mocks import ( + context "context" + model "github.com/mattermost/mattermost-server/v6/model" mock "github.com/stretchr/testify/mock" ) @@ -90,13 +92,13 @@ func (_m *ComplianceStore) GetAll(offset int, limit int) (model.Compliances, err return r0, r1 } -// MessageExport provides a mock function with given fields: cursor, limit -func (_m *ComplianceStore) MessageExport(cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { - ret := _m.Called(cursor, limit) +// MessageExport provides a mock function with given fields: ctx, cursor, limit +func (_m *ComplianceStore) MessageExport(ctx context.Context, cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { + ret := _m.Called(ctx, cursor, limit) var r0 []*model.MessageExport - if rf, ok := ret.Get(0).(func(model.MessageExportCursor, int) []*model.MessageExport); ok { - r0 = rf(cursor, limit) + if rf, ok := ret.Get(0).(func(context.Context, model.MessageExportCursor, int) []*model.MessageExport); ok { + r0 = rf(ctx, cursor, limit) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*model.MessageExport) @@ -104,15 +106,15 @@ func (_m *ComplianceStore) MessageExport(cursor model.MessageExportCursor, limit } var r1 model.MessageExportCursor - if rf, ok := ret.Get(1).(func(model.MessageExportCursor, int) model.MessageExportCursor); ok { - r1 = rf(cursor, limit) + if rf, ok := ret.Get(1).(func(context.Context, model.MessageExportCursor, int) model.MessageExportCursor); ok { + r1 = rf(ctx, cursor, limit) } else { r1 = ret.Get(1).(model.MessageExportCursor) } var r2 error - if rf, ok := ret.Get(2).(func(model.MessageExportCursor, int) error); ok { - r2 = rf(cursor, limit) + if rf, ok := ret.Get(2).(func(context.Context, model.MessageExportCursor, int) error); ok { + r2 = rf(ctx, cursor, limit) } else { r2 = ret.Error(2) } diff --git a/store/timerlayer/timerlayer.go b/store/timerlayer/timerlayer.go index f89afb897d..dfd2e145a2 100644 --- a/store/timerlayer/timerlayer.go +++ b/store/timerlayer/timerlayer.go @@ -2942,10 +2942,10 @@ func (s *TimerLayerComplianceStore) GetAll(offset int, limit int) (model.Complia return result, err } -func (s *TimerLayerComplianceStore) MessageExport(cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { +func (s *TimerLayerComplianceStore) MessageExport(ctx context.Context, cursor model.MessageExportCursor, limit int) ([]*model.MessageExport, model.MessageExportCursor, error) { start := time.Now() - result, resultVar1, err := s.ComplianceStore.MessageExport(cursor, limit) + result, resultVar1, err := s.ComplianceStore.MessageExport(ctx, cursor, limit) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil {