From 2aaf4cf0fb58cbbcff94b34051cecc556b3930d4 Mon Sep 17 00:00:00 2001 From: Doug Lauder Date: Fri, 15 Jul 2022 13:20:40 -0400 Subject: [PATCH] Fix broken master; ensure all product service APIs have correct implementations (#20663) * fix broken master; ensure all product service APIs are implemented by the structs passed to products * use zero allocation interface checks --- app/app.go | 4 ++++ app/bot.go | 5 +++++ app/channel.go | 21 +++++++++++++-------- app/channels.go | 3 +++ app/cloud.go | 5 +++++ app/cluster.go | 5 +++++ app/config.go | 4 ++++ app/file.go | 5 +++++ app/license.go | 4 ++++ app/permissions.go | 9 +++++++-- app/plugin.go | 4 ++++ app/plugin_key_value_store.go | 5 +++++ app/post.go | 5 +++++ app/server.go | 4 ++++ app/team.go | 5 +++++ product/api.go | 8 +------- store/store.go | 4 ++++ 17 files changed, 83 insertions(+), 17 deletions(-) diff --git a/app/app.go b/app/app.go index 95df31ea1a..ac7cf62dd1 100644 --- a/app/app.go +++ b/app/app.go @@ -11,6 +11,7 @@ import ( "github.com/mattermost/mattermost-server/v6/einterfaces" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/services/httpservice" "github.com/mattermost/mattermost-server/v6/services/imageproxy" "github.com/mattermost/mattermost-server/v6/services/searchengine" @@ -174,6 +175,9 @@ func (a *App) UpdateExpiredDNDStatuses() ([]*model.Status, error) { return a.Srv().Store.Status().UpdateExpiredDNDStatuses() } +// Ensure system service adapter implements `product.SystemService` +var _ product.SystemService = (*systemServiceAdapter)(nil) + // systemServiceAdapter provides a collection of system APIs for use by products. type systemServiceAdapter struct { server *Server diff --git a/app/bot.go b/app/bot.go index 543de8d2e1..5ec00cb093 100644 --- a/app/bot.go +++ b/app/bot.go @@ -11,6 +11,7 @@ import ( "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/shared/i18n" "github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/store" @@ -21,6 +22,10 @@ const ( botUserKey = internalKeyPrefix + "botid" ) +// Ensure bot service wrapper implements `product.BotService` +var _ product.BotService = (*botServiceWrapper)(nil) + +// botServiceWrapper provides an implementation of `product.BotService` for use by products. type botServiceWrapper struct { app AppIface } diff --git a/app/channel.go b/app/channel.go index 80fcb9c978..3021a42c8b 100644 --- a/app/channel.go +++ b/app/channel.go @@ -15,6 +15,7 @@ import ( "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/shared/i18n" "github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/store" @@ -22,28 +23,32 @@ import ( "github.com/mattermost/mattermost-server/v6/utils" ) +// channelsWrapper provides an implementation of `product.ChannelService` to be used by products. type channelsWrapper struct { srv *Server } -func (s *channelsWrapper) GetDirectChannel(c request.CTX, userID1, userID2 string) (*model.Channel, *model.AppError) { - return s.srv.getDirectChannel(c, userID1, userID2) +func (s *channelsWrapper) GetDirectChannel(userID1, userID2 string) (*model.Channel, *model.AppError) { + return s.srv.getDirectChannel(request.EmptyContext(s.srv.GetLogger()), userID1, userID2) } // GetChannelByID gets a Channel by its ID. -func (s *channelsWrapper) GetChannelByID(c request.CTX, channelID string) (*model.Channel, *model.AppError) { - return s.srv.getChannel(c, channelID) +func (s *channelsWrapper) GetChannelByID(channelID string) (*model.Channel, *model.AppError) { + return s.srv.getChannel(request.EmptyContext(s.srv.GetLogger()), channelID) } // GetChannelMember gets a channel member by userID. -func (s *channelsWrapper) GetChannelMember(c request.CTX, channelID string, userID string) (*model.ChannelMember, *model.AppError) { - return s.srv.getChannelMember(c, channelID, userID) +func (s *channelsWrapper) GetChannelMember(channelID string, userID string) (*model.ChannelMember, *model.AppError) { + return s.srv.getChannelMember(request.EmptyContext(s.srv.GetLogger()), channelID, userID) } -func (s *channelsWrapper) GetChannelsForTeamForUser(c request.CTX, teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError) { - return s.srv.getChannelsForTeamForUser(c, teamID, userID, opts) +func (s *channelsWrapper) GetChannelsForTeamForUser(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError) { + return s.srv.getChannelsForTeamForUser(request.EmptyContext(s.srv.GetLogger()), teamID, userID, opts) } +// Ensure the wrapper implements the product service. +var _ product.ChannelService = (*channelsWrapper)(nil) + // DefaultChannelNames returns the list of system-wide default channel names. // // By default the list will be (not necessarily in this order): diff --git a/app/channels.go b/app/channels.go index ee2670eb0f..24a2f460d1 100644 --- a/app/channels.go +++ b/app/channels.go @@ -312,6 +312,9 @@ func (ch *Channels) RequestTrialLicense(requesterID string, users int, termsAcce receiveEmailsAccepted) } +// Ensure hooksService implements `product.HooksService` +var _ product.HooksService = (*hooksService)(nil) + type hooksService struct { ch *Channels } diff --git a/app/cloud.go b/app/cloud.go index 4d78bdef82..bb38e6bb22 100644 --- a/app/cloud.go +++ b/app/cloud.go @@ -13,6 +13,7 @@ import ( "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/einterfaces" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/shared/i18n" "github.com/mattermost/mattermost-server/v6/shared/mlog" ) @@ -106,6 +107,10 @@ func (a *App) NotifySystemAdminsToUpgrade(c *request.Context, currentUserTeamID return nil } +// Ensure cloud service wrapper implements `product.CloudService` +var _ product.CloudService = (*cloudWrapper)(nil) + +// cloudWrapper provides an implementation of `product.CloudService` for use by products. type cloudWrapper struct { cloud einterfaces.CloudInterface } diff --git a/app/cluster.go b/app/cluster.go index 9fcc5bb825..9cc0d56e0b 100644 --- a/app/cluster.go +++ b/app/cluster.go @@ -7,8 +7,13 @@ import ( "fmt" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" ) +// ensure cluster service wrapper implements `product.ClusterService` +var _ product.ClusterService = (*clusterWrapper)(nil) + +// clusterWrapper provides an implementation of `product.ClusterService` for use by products. type clusterWrapper struct { srv *Server } diff --git a/app/config.go b/app/config.go index 86d59afdf8..bbbc92ff44 100644 --- a/app/config.go +++ b/app/config.go @@ -22,6 +22,7 @@ import ( "github.com/mattermost/mattermost-server/v6/config" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/shared/mail" "github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/utils" @@ -31,6 +32,9 @@ const ( ErrorTermsOfServiceNoRowsFound = "app.terms_of_service.get.no_rows.app_error" ) +// ensure the config wrapper implements `product.ConfigService` +var _ product.ConfigService = (*configWrapper)(nil) + // configWrapper is an adapter struct that only exposes the // config related functionality to be passed down to other products. type configWrapper struct { diff --git a/app/file.go b/app/file.go index 8d50a5815f..9d7a382563 100644 --- a/app/file.go +++ b/app/file.go @@ -27,6 +27,7 @@ import ( "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/services/docextractor" "github.com/mattermost/mattermost-server/v6/shared/filestore" "github.com/mattermost/mattermost-server/v6/shared/mlog" @@ -47,6 +48,10 @@ const ( maxContentExtractionSize = 1024 * 1024 // 1MB ) +// Ensure fileInfo service wrapper implements `product.FileInfoStoreService` +var _ product.FileInfoStoreService = (*fileInfoWrapper)(nil) + +// fileInfoWrapper implements `product.FileInfoStoreService` for use by products. type fileInfoWrapper struct { srv *Server } diff --git a/app/license.go b/app/license.go index 6da4287daf..5f4b1a79d4 100644 --- a/app/license.go +++ b/app/license.go @@ -16,6 +16,7 @@ import ( "github.com/mattermost/mattermost-server/v6/jobs" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/store" "github.com/mattermost/mattermost-server/v6/utils" @@ -29,6 +30,9 @@ const ( var RequestTrialURL = "https://customers.mattermost.com/api/v1/trials" +// ensure the license service wrapper implements `product.LicenseService` +var _ product.LicenseService = (*licenseWrapper)(nil) + // licenseWrapper is an adapter struct that only exposes the // config related functionality to be passed down to other products. type licenseWrapper struct { diff --git a/app/permissions.go b/app/permissions.go index 80f4b05c21..9c813b1f3f 100644 --- a/app/permissions.go +++ b/app/permissions.go @@ -15,11 +15,16 @@ import ( "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" ) const permissionsExportBatchSize = 100 const systemSchemeName = "00000000-0000-0000-0000-000000000000" // Prevents collisions with user-created schemes. +// Ensure permissions service wrapper implements `product.PermissionService` +var _ product.PermissionService = (*permissionsServiceWrapper)(nil) + +// permissionsServiceWrapper provides an implementation of `product.PermissionService` for use by products. type permissionsServiceWrapper struct { app AppIface } @@ -28,8 +33,8 @@ func (s *permissionsServiceWrapper) HasPermissionToTeam(userID string, teamID st return s.app.HasPermissionToTeam(userID, teamID, permission) } -func (s *permissionsServiceWrapper) HasPermissionToChannel(c request.CTX, askingUserID string, channelID string, permission *model.Permission) bool { - return s.app.HasPermissionToChannel(c, askingUserID, channelID, permission) +func (s *permissionsServiceWrapper) HasPermissionToChannel(askingUserID string, channelID string, permission *model.Permission) bool { + return s.app.HasPermissionToChannel(request.EmptyContext(s.app.Log()), askingUserID, channelID, permission) } func (a *App) ResetPermissionsSystem() *model.AppError { diff --git a/app/plugin.go b/app/plugin.go index 85fc3db292..4fb0abc501 100644 --- a/app/plugin.go +++ b/app/plugin.go @@ -24,6 +24,7 @@ import ( "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/services/marketplace" "github.com/mattermost/mattermost-server/v6/shared/filestore" "github.com/mattermost/mattermost-server/v6/shared/mlog" @@ -38,6 +39,9 @@ type pluginSignaturePath struct { signaturePath string } +//Ensure routerService implements `product.RouterService` +var _ product.RouterService = (*routerService)(nil) + type routerService struct { mu sync.Mutex routerMap map[string]*mux.Router diff --git a/app/plugin_key_value_store.go b/app/plugin_key_value_store.go index 85a62b48c0..23419a7ff6 100644 --- a/app/plugin_key_value_store.go +++ b/app/plugin_key_value_store.go @@ -10,10 +10,15 @@ import ( "net/http" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/store" ) +// Ensure KV store wrapper implements `product.KVStoreService` +var _ product.KVStoreService = (*kvStoreWrapper)(nil) + +// kvStoreWrapper provides an implementation of `product.KVStoreService` for use by products. type kvStoreWrapper struct { srv *Server } diff --git a/app/post.go b/app/post.go index 01c17df6dd..2379ee300f 100644 --- a/app/post.go +++ b/app/post.go @@ -18,6 +18,7 @@ import ( "github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/services/cache" "github.com/mattermost/mattermost-server/v6/shared/i18n" "github.com/mattermost/mattermost-server/v6/shared/mlog" @@ -33,6 +34,10 @@ const ( var atMentionPattern = regexp.MustCompile(`\B@`) +// Ensure post service wrapper implements `product.PostService` +var _ product.PostService = (*postServiceWrapper)(nil) + +// postServiceWrapper provides an implementation of `product.PostService` for use by products. type postServiceWrapper struct { app AppIface } diff --git a/app/server.go b/app/server.go index e047dc3a96..5b556c55b4 100644 --- a/app/server.go +++ b/app/server.go @@ -55,6 +55,7 @@ import ( "github.com/mattermost/mattermost-server/v6/jobs/resend_invitation_email" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin/scheduler" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/services/awsmeter" "github.com/mattermost/mattermost-server/v6/services/cache" "github.com/mattermost/mattermost-server/v6/services/httpservice" @@ -394,6 +395,9 @@ func NewServer(options ...Option) (*Server, error) { return nil, errors.Wrapf(err, "unable to create teams service") } + // ensure app implements `product.UserService` + var _ product.UserService = (*App)(nil) + serviceMap := map[ServiceKey]any{ ChannelKey: &channelsWrapper{srv: s}, ConfigKey: s.configStore, diff --git a/app/team.go b/app/team.go index 965459f412..94c25aae79 100644 --- a/app/team.go +++ b/app/team.go @@ -24,12 +24,14 @@ import ( "github.com/mattermost/mattermost-server/v6/app/users" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" + "github.com/mattermost/mattermost-server/v6/product" "github.com/mattermost/mattermost-server/v6/shared/i18n" "github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/store" "github.com/mattermost/mattermost-server/v6/store/sqlstore" ) +// teamServiceWrapper provides an implementation of `product.TeamService` to be used by products. type teamServiceWrapper struct { app AppIface } @@ -42,6 +44,9 @@ func (w *teamServiceWrapper) CreateMember(ctx *request.Context, teamID, userID s return w.app.AddTeamMember(ctx, teamID, userID) } +// Ensure the wrapper implements the product service. +var _ product.TeamService = (*teamServiceWrapper)(nil) + func (a *App) AdjustTeamsFromProductLimits(teamLimits *model.TeamsLimits) *model.AppError { maxActiveTeams := *teamLimits.Active teams, appErr := a.GetAllTeams() diff --git a/product/api.go b/product/api.go index fe4f635335..539b497a31 100644 --- a/product/api.go +++ b/product/api.go @@ -5,7 +5,6 @@ package product import ( "database/sql" - "io" "github.com/gorilla/mux" @@ -136,12 +135,7 @@ type HooksService interface { // // The service shall be registered via app.FilestoreKey service key. type FilestoreService interface { - Reader(path string) (filestore.ReadCloseSeeker, error) - FileExists(path string) (bool, error) - CopyFile(oldPath, newPath string) error - MoveFile(oldPath, newPath string) error - WriteFile(fr io.Reader, path string) (int64, error) - RemoveFile(path string) error + filestore.FileBackend } // FileInfoStoreService is the API for accessing the file info store. diff --git a/store/store.go b/store/store.go index d5f67ccdbb..370dad74dc 100644 --- a/store/store.go +++ b/store/store.go @@ -11,6 +11,7 @@ import ( "time" "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost-server/v6/product" ) type StoreResult struct { @@ -1025,6 +1026,9 @@ type SidebarCategorySearchOpts struct { ExcludeTeam bool } +// Ensure store service adapter implements `product.StoreService` +var _ product.StoreService = (*StoreServiceAdapter)(nil) + // StoreServiceAdapter provides a simple Store wrapper for use with products. type StoreServiceAdapter struct { store Store