focalboard/mattermost-plugin/product/boards_product.go
Doug Lauder 73d77682ac
Expose boards APIs for MPA (#4372)
* add Boards APIs to services map
2022-12-23 10:47:51 -05:00

331 lines
10 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package product
import (
"errors"
"fmt"
"github.com/mattermost/focalboard/mattermost-plugin/server/boards"
"github.com/mattermost/focalboard/server/model"
mm_model "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/mlog"
)
const (
boardsProductName = "boards"
boardsProductID = "com.mattermost.boards"
)
var errServiceTypeAssert = errors.New("type assertion failed")
func init() {
product.RegisterProduct(boardsProductName, product.Manifest{
Initializer: newBoardsProduct,
Dependencies: map[product.ServiceKey]struct{}{
product.TeamKey: {},
product.ChannelKey: {},
product.UserKey: {},
product.PostKey: {},
product.PermissionsKey: {},
product.BotKey: {},
product.ClusterKey: {},
product.ConfigKey: {},
product.LogKey: {},
product.LicenseKey: {},
product.FilestoreKey: {},
product.FileInfoStoreKey: {},
product.RouterKey: {},
product.CloudKey: {},
product.KVStoreKey: {},
product.StoreKey: {},
product.SystemKey: {},
product.PreferencesKey: {},
product.HooksKey: {},
},
})
}
type boardsProduct struct {
teamService product.TeamService
channelService product.ChannelService
userService product.UserService
postService product.PostService
permissionsService product.PermissionService
botService product.BotService
clusterService product.ClusterService
configService product.ConfigService
logger mlog.LoggerIFace
licenseService product.LicenseService
filestoreService product.FilestoreService
fileInfoStoreService product.FileInfoStoreService
routerService product.RouterService
cloudService product.CloudService
kvStoreService product.KVStoreService
storeService product.StoreService
systemService product.SystemService
preferencesService product.PreferencesService
hooksService product.HooksService
boardsApp *boards.BoardsApp
}
func newBoardsProduct(services map[product.ServiceKey]interface{}) (product.Product, error) {
boardsProd := &boardsProduct{}
if err := populateServices(boardsProd, services); err != nil {
return nil, err
}
boardsProd.logger.Info("Creating boards service")
adapter := newServiceAPIAdapter(boardsProd)
boardsApp, err := boards.NewBoardsApp(adapter)
if err != nil {
return nil, fmt.Errorf("failed to create Boards service: %w", err)
}
boardsProd.boardsApp = boardsApp
// Add the Boards services API to the services map so other products can access Boards functionality.
boardsAPI := boards.NewBoardsServiceAPI(boardsApp)
services[product.BoardsKey] = boardsAPI
return boardsProd, nil
}
// populateServices populates the boardProduct with all the services needed from the suite.
func populateServices(boardsProd *boardsProduct, services map[product.ServiceKey]interface{}) error {
for key, service := range services {
switch key {
case product.TeamKey:
teamService, ok := service.(product.TeamService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.teamService = teamService
case product.ChannelKey:
channelService, ok := service.(product.ChannelService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.channelService = channelService
case product.UserKey:
userService, ok := service.(product.UserService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.userService = userService
case product.PostKey:
postService, ok := service.(product.PostService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.postService = postService
case product.PermissionsKey:
permissionsService, ok := service.(product.PermissionService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.permissionsService = permissionsService
case product.BotKey:
botService, ok := service.(product.BotService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.botService = botService
case product.ClusterKey:
clusterService, ok := service.(product.ClusterService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.clusterService = clusterService
case product.ConfigKey:
configService, ok := service.(product.ConfigService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.configService = configService
case product.LogKey:
logger, ok := service.(mlog.LoggerIFace)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.logger = logger.With(mlog.String("product", boardsProductName))
case product.LicenseKey:
licenseService, ok := service.(product.LicenseService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.licenseService = licenseService
case product.FilestoreKey:
filestoreService, ok := service.(product.FilestoreService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.filestoreService = filestoreService
case product.FileInfoStoreKey:
fileInfoStoreService, ok := service.(product.FileInfoStoreService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.fileInfoStoreService = fileInfoStoreService
case product.RouterKey:
routerService, ok := service.(product.RouterService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.routerService = routerService
case product.CloudKey:
cloudService, ok := service.(product.CloudService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.cloudService = cloudService
case product.KVStoreKey:
kvStoreService, ok := service.(product.KVStoreService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.kvStoreService = kvStoreService
case product.StoreKey:
storeService, ok := service.(product.StoreService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.storeService = storeService
case product.SystemKey:
systemService, ok := service.(product.SystemService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.systemService = systemService
case product.PreferencesKey:
preferencesService, ok := service.(product.PreferencesService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.preferencesService = preferencesService
case product.HooksKey:
hooksService, ok := service.(product.HooksService)
if !ok {
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boardsProd.hooksService = hooksService
}
}
return nil
}
func (bp *boardsProduct) Start() error {
if !bp.configService.Config().FeatureFlags.BoardsProduct {
bp.logger.Info("Boards product disabled via feature flag")
return nil
}
bp.logger.Info("Starting boards service")
adapter := newServiceAPIAdapter(bp)
boardsApp, err := boards.NewBoardsApp(adapter)
if err != nil {
return fmt.Errorf("failed to create Boards service: %w", err)
}
model.LogServerInfo(bp.logger)
if err := bp.hooksService.RegisterHooks(boardsProductName, bp); err != nil {
return fmt.Errorf("failed to register hooks: %w", err)
}
bp.boardsApp = boardsApp
if err := bp.boardsApp.Start(); err != nil {
return fmt.Errorf("failed to start Boards service: %w", err)
}
return nil
}
func (bp *boardsProduct) Stop() error {
bp.logger.Info("Stopping boards service")
if bp.boardsApp == nil {
return nil
}
if err := bp.boardsApp.Stop(); err != nil {
return fmt.Errorf("error while stopping Boards service: %w", err)
}
return nil
}
//
// These callbacks are called by the suite automatically
//
func (bp *boardsProduct) OnConfigurationChange() error {
if bp.boardsApp == nil {
return nil
}
return bp.boardsApp.OnConfigurationChange()
}
func (bp *boardsProduct) OnWebSocketConnect(webConnID, userID string) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.OnWebSocketConnect(webConnID, userID)
}
func (bp *boardsProduct) OnWebSocketDisconnect(webConnID, userID string) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.OnWebSocketDisconnect(webConnID, userID)
}
func (bp *boardsProduct) WebSocketMessageHasBeenPosted(webConnID, userID string, req *mm_model.WebSocketRequest) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.WebSocketMessageHasBeenPosted(webConnID, userID, req)
}
func (bp *boardsProduct) OnPluginClusterEvent(ctx *plugin.Context, ev mm_model.PluginClusterEvent) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.OnPluginClusterEvent(ctx, ev)
}
func (bp *boardsProduct) MessageWillBePosted(ctx *plugin.Context, post *mm_model.Post) (*mm_model.Post, string) {
if bp.boardsApp == nil {
return post, ""
}
return bp.boardsApp.MessageWillBePosted(ctx, post)
}
func (bp *boardsProduct) MessageWillBeUpdated(ctx *plugin.Context, newPost, oldPost *mm_model.Post) (*mm_model.Post, string) {
if bp.boardsApp == nil {
return newPost, ""
}
return bp.boardsApp.MessageWillBeUpdated(ctx, newPost, oldPost)
}
func (bp *boardsProduct) OnCloudLimitsUpdated(limits *mm_model.ProductLimits) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.OnCloudLimitsUpdated(limits)
}
func (bp *boardsProduct) RunDataRetention(nowTime, batchSize int64) (int64, error) {
if bp.boardsApp == nil {
return 0, nil
}
return bp.boardsApp.RunDataRetention(nowTime, batchSize)
}