Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry pick pr4400 rolling stable #4404

Merged
merged 2 commits into from
Dec 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 65 additions & 40 deletions mattermost-plugin/product/boards_product.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func init() {
product.ChannelKey: {},
product.UserKey: {},
product.PostKey: {},
product.PermissionsKey: {},
product.BotKey: {},
product.ClusterKey: {},
product.ConfigKey: {},
Expand All @@ -44,6 +45,7 @@ func init() {
product.StoreKey: {},
product.SystemKey: {},
product.PreferencesKey: {},
product.HooksKey: {},
},
})
}
Expand Down Expand Up @@ -73,127 +75,150 @@ type boardsProduct struct {
}

func newBoardsProduct(services map[product.ServiceKey]interface{}) (product.Product, error) {
boards := &boardsProduct{}
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 nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.teamService = teamService
boardsProd.teamService = teamService
case product.ChannelKey:
channelService, ok := service.(product.ChannelService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.channelService = channelService
boardsProd.channelService = channelService
case product.UserKey:
userService, ok := service.(product.UserService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.userService = userService
boardsProd.userService = userService
case product.PostKey:
postService, ok := service.(product.PostService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.postService = postService
boardsProd.postService = postService
case product.PermissionsKey:
permissionsService, ok := service.(product.PermissionService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.permissionsService = permissionsService
boardsProd.permissionsService = permissionsService
case product.BotKey:
botService, ok := service.(product.BotService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.botService = botService
boardsProd.botService = botService
case product.ClusterKey:
clusterService, ok := service.(product.ClusterService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.clusterService = clusterService
boardsProd.clusterService = clusterService
case product.ConfigKey:
configService, ok := service.(product.ConfigService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.configService = configService
boardsProd.configService = configService
case product.LogKey:
logger, ok := service.(mlog.LoggerIFace)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.logger = logger.With(mlog.String("product", boardsProductName))
boardsProd.logger = logger.With(mlog.String("product", boardsProductName))
case product.LicenseKey:
licenseService, ok := service.(product.LicenseService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.licenseService = licenseService
boardsProd.licenseService = licenseService
case product.FilestoreKey:
filestoreService, ok := service.(product.FilestoreService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.filestoreService = filestoreService
boardsProd.filestoreService = filestoreService
case product.FileInfoStoreKey:
fileInfoStoreService, ok := service.(product.FileInfoStoreService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.fileInfoStoreService = fileInfoStoreService
boardsProd.fileInfoStoreService = fileInfoStoreService
case product.RouterKey:
routerService, ok := service.(product.RouterService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.routerService = routerService
boardsProd.routerService = routerService
case product.CloudKey:
cloudService, ok := service.(product.CloudService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.cloudService = cloudService
boardsProd.cloudService = cloudService
case product.KVStoreKey:
kvStoreService, ok := service.(product.KVStoreService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.kvStoreService = kvStoreService
boardsProd.kvStoreService = kvStoreService
case product.StoreKey:
storeService, ok := service.(product.StoreService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.storeService = storeService
boardsProd.storeService = storeService
case product.SystemKey:
systemService, ok := service.(product.SystemService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.systemService = systemService
boardsProd.systemService = systemService
case product.PreferencesKey:
preferencesService, ok := service.(product.PreferencesService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.preferencesService = preferencesService
boardsProd.preferencesService = preferencesService
case product.HooksKey:
hooksService, ok := service.(product.HooksService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
return fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.hooksService = hooksService
boardsProd.hooksService = hooksService
}
}
return boards, nil
return nil
}

func (bp *boardsProduct) Start() error {
Expand Down
84 changes: 84 additions & 0 deletions mattermost-plugin/server/boards/boards_service_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package boards

import (
"github.com/mattermost/focalboard/server/app"
"github.com/mattermost/focalboard/server/model"

mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/product"
)

// boardsServiceAPI provides a service API for other products such as Channels.
type boardsServiceAPI struct {
app *app.App
}

func NewBoardsServiceAPI(app *BoardsApp) *boardsServiceAPI {
return &boardsServiceAPI{
app: app.server.App(),
}
}

func (bs *boardsServiceAPI) GetTemplates(teamID string, userID string) ([]*model.Board, error) {
return bs.app.GetTemplateBoards(teamID, userID)
}

func (bs *boardsServiceAPI) GetBoard(boardID string) (*model.Board, error) {
return bs.app.GetBoard(boardID)
}

func (bs *boardsServiceAPI) CreateBoard(board *model.Board, userID string, addmember bool) (*model.Board, error) {
return bs.app.CreateBoard(board, userID, addmember)
}

func (bs *boardsServiceAPI) PatchBoard(boardPatch *model.BoardPatch, boardID string, userID string) (*model.Board, error) {
return bs.app.PatchBoard(boardPatch, boardID, userID)
}

func (bs *boardsServiceAPI) DeleteBoard(boardID string, userID string) error {
return bs.app.DeleteBoard(boardID, userID)
}

func (bs *boardsServiceAPI) SearchBoards(searchTerm string, searchField model.BoardSearchField,
userID string, includePublicBoards bool) ([]*model.Board, error) {
return bs.app.SearchBoardsForUser(searchTerm, searchField, userID, includePublicBoards)
}

func (bs *boardsServiceAPI) LinkBoardToChannel(boardID string, channelID string, userID string) (*model.Board, error) {
patch := &model.BoardPatch{
ChannelID: &channelID,
}
return bs.app.PatchBoard(patch, boardID, userID)
}

func (bs *boardsServiceAPI) GetCards(boardID string) ([]*model.Card, error) {
return bs.app.GetCardsForBoard(boardID, 0, 0)
}

func (bs *boardsServiceAPI) GetCard(cardID string) (*model.Card, error) {
return bs.app.GetCardByID(cardID)
}

func (bs *boardsServiceAPI) CreateCard(card *model.Card, boardID string, userID string) (*model.Card, error) {
return bs.app.CreateCard(card, boardID, userID, false)
}

func (bs *boardsServiceAPI) PatchCard(cardPatch *model.CardPatch, cardID string, userID string) (*model.Card, error) {
return bs.app.PatchCard(cardPatch, cardID, userID, false)
}

func (bs *boardsServiceAPI) DeleteCard(cardID string, userID string) error {
return bs.app.DeleteBlock(cardID, userID)
}

func (bs *boardsServiceAPI) HasPermissionToBoard(userID, boardID string, permission *mm_model.Permission) bool {
return bs.app.HasPermissionToBoard(userID, boardID, permission)
}

func (bs *boardsServiceAPI) DuplicateBoard(boardID string, userID string,
toTeam string, asTemplate bool) (*model.BoardsAndBlocks, []*model.BoardMember, error) {
return bs.app.DuplicateBoard(boardID, userID, toTeam, asTemplate)
}

// Ensure boardsServiceAPI implements product.BoardsService interface.
var _ product.BoardsService = (*boardsServiceAPI)(nil)
2 changes: 2 additions & 0 deletions server/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type App struct {
metrics *metrics.Metrics
notifications *notify.Service
logger mlog.LoggerIFace
permissions permissions.PermissionsService
blockChangeNotifier *utils.CallbackQueue
servicesAPI servicesAPI

Expand All @@ -90,6 +91,7 @@ func New(config *config.Configuration, wsAdapter ws.Adapter, services Services)
metrics: services.Metrics,
notifications: services.Notifications,
logger: services.Logger,
permissions: services.Permissions,
blockChangeNotifier: utils.NewCallbackQueue("blockChangeNotifier", blockChangeNotifierQueueSize, blockChangeNotifierPoolSize, services.Logger),
servicesAPI: services.ServicesAPI,
}
Expand Down
9 changes: 9 additions & 0 deletions server/app/permissions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package app

import (
mm_model "github.com/mattermost/mattermost-server/v6/model"
)

func (a *App) HasPermissionToBoard(userID, boardID string, permission *mm_model.Permission) bool {
return a.permissions.HasPermissionToBoard(userID, boardID, permission)
}
15 changes: 15 additions & 0 deletions server/model/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ type Board struct {
DeleteAt int64 `json:"deleteAt"`
}

// GetPropertyString returns the value of the specified property as a string,
// or error if the property does not exist or is not of type string.
func (b *Board) GetPropertyString(propName string) (string, error) {
val, ok := b.Properties[propName]
if !ok {
return "", NewErrNotFound(propName)
}

s, ok := val.(string)
if !ok {
return "", ErrInvalidPropertyValueType
}
return s, nil
}

// BoardPatch is a patch for modify boards
// swagger:model
type BoardPatch struct {
Expand Down