Merge pull request #21883 from mattermost/mpa-playbooks
Add services and functions for playbooks to work in mpa mode
Этот коммит содержится в:
24
Makefile
24
Makefile
@@ -93,6 +93,22 @@ else
|
|||||||
BUILD_BOARDS = false
|
BUILD_BOARDS = false
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Playbooks
|
||||||
|
BUILD_PLAYBOOKS_DIR ?= ../mattermost-plugin-playbooks
|
||||||
|
BUILD_PLAYBOOKS ?= false
|
||||||
|
BUILD_HASH_PLAYBOOKS = none
|
||||||
|
|
||||||
|
ifneq ($(wildcard $(BUILD_PLAYBOOKS_DIR)/.),)
|
||||||
|
ifeq ($(BUILD_PLAYBOOKS),true)
|
||||||
|
BUILD_PLAYBOOKS = true
|
||||||
|
BUILD_HASH_PLAYBOOKS = $(shell cd $(BUILD_PLAYBOOKS_DIR) && git rev-parse HEAD)
|
||||||
|
else
|
||||||
|
BUILD_PLAYBOOKS = false
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
BUILD_PLAYBOOKS = false
|
||||||
|
endif
|
||||||
|
|
||||||
# We need current user's UID for `run-haserver` so docker compose does not run server
|
# We need current user's UID for `run-haserver` so docker compose does not run server
|
||||||
# as root and mess up file permissions for devs. When running like this HOME will be blank
|
# as root and mess up file permissions for devs. When running like this HOME will be blank
|
||||||
# and docker will add '/', so we need to set the go-build cache location or we'll get
|
# and docker will add '/', so we need to set the go-build cache location or we'll get
|
||||||
@@ -116,6 +132,7 @@ LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHashEnterpr
|
|||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildEnterpriseReady=$(BUILD_ENTERPRISE_READY)"
|
||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHashBoards=$(BUILD_HASH_BOARDS)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHashBoards=$(BUILD_HASH_BOARDS)"
|
||||||
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildBoards=$(BUILD_BOARDS)"
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildBoards=$(BUILD_BOARDS)"
|
||||||
|
LDFLAGS += -X "github.com/mattermost/mattermost-server/v6/model.BuildHashPlaybooks=$(BUILD_HASH_PLAYBOOKS)"
|
||||||
|
|
||||||
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
|
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
|
||||||
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
|
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
|
||||||
@@ -198,6 +215,12 @@ else
|
|||||||
IGNORE:=$(shell rm -f imports/boards_imports.go)
|
IGNORE:=$(shell rm -f imports/boards_imports.go)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(BUILD_PLAYBOOKS),true)
|
||||||
|
IGNORE:=$(shell cp $(BUILD_PLAYBOOKS_DIR)/product/imports/playbooks_imports.go imports/)
|
||||||
|
else
|
||||||
|
IGNORE:=$(shell rm -f imports/playbooks_imports.go)
|
||||||
|
endif
|
||||||
|
|
||||||
all: run ## Alias for 'run'.
|
all: run ## Alias for 'run'.
|
||||||
|
|
||||||
-include config.override.mk
|
-include config.override.mk
|
||||||
@@ -421,6 +444,7 @@ endif
|
|||||||
|
|
||||||
setup-go-work: export BUILD_ENTERPRISE_READY := $(BUILD_ENTERPRISE_READY)
|
setup-go-work: export BUILD_ENTERPRISE_READY := $(BUILD_ENTERPRISE_READY)
|
||||||
setup-go-work: export BUILD_BOARDS := $(BUILD_BOARDS)
|
setup-go-work: export BUILD_BOARDS := $(BUILD_BOARDS)
|
||||||
|
setup-go-work: export BUILD_PLAYBOOKS := $(BUILD_PLAYBOOKS)
|
||||||
setup-go-work: ## Sets up your go.work file
|
setup-go-work: ## Sets up your go.work file
|
||||||
./scripts/setup_go_work.sh $(IGNORE_GO_WORK_IF_EXISTS)
|
./scripts/setup_go_work.sh $(IGNORE_GO_WORK_IF_EXISTS)
|
||||||
|
|
||||||
|
|||||||
@@ -960,6 +960,7 @@ type AppIface interface {
|
|||||||
RegenOutgoingWebhookToken(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.AppError)
|
RegenOutgoingWebhookToken(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.AppError)
|
||||||
RegenerateOAuthAppSecret(app *model.OAuthApp) (*model.OAuthApp, *model.AppError)
|
RegenerateOAuthAppSecret(app *model.OAuthApp) (*model.OAuthApp, *model.AppError)
|
||||||
RegenerateTeamInviteId(teamID string) (*model.Team, *model.AppError)
|
RegenerateTeamInviteId(teamID string) (*model.Team, *model.AppError)
|
||||||
|
RegisterCollectionAndTopic(pluginID, collectionType, topicType string) error
|
||||||
RegisterPluginCommand(pluginID string, command *model.Command) error
|
RegisterPluginCommand(pluginID string, command *model.Command) error
|
||||||
ReloadConfig() error
|
ReloadConfig() error
|
||||||
RemoveAllDeactivatedMembersFromChannel(c request.CTX, channel *model.Channel) *model.AppError
|
RemoveAllDeactivatedMembersFromChannel(c request.CTX, channel *model.Channel) *model.AppError
|
||||||
|
|||||||
@@ -27,30 +27,82 @@ import (
|
|||||||
|
|
||||||
// channelsWrapper provides an implementation of `product.ChannelService` to be used by products.
|
// channelsWrapper provides an implementation of `product.ChannelService` to be used by products.
|
||||||
type channelsWrapper struct {
|
type channelsWrapper struct {
|
||||||
srv *Server
|
|
||||||
app *App
|
app *App
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *channelsWrapper) GetDirectChannel(userID1, userID2 string) (*model.Channel, *model.AppError) {
|
func (s *channelsWrapper) GetDirectChannel(userID1, userID2 string) (*model.Channel, *model.AppError) {
|
||||||
return s.srv.getDirectChannel(request.EmptyContext(s.srv.Log()), userID1, userID2)
|
return s.app.getDirectChannel(request.EmptyContext(s.app.Log()), userID1, userID2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelByID gets a Channel by its ID.
|
// GetChannelByID gets a Channel by its ID.
|
||||||
func (s *channelsWrapper) GetChannelByID(channelID string) (*model.Channel, *model.AppError) {
|
func (s *channelsWrapper) GetChannelByID(channelID string) (*model.Channel, *model.AppError) {
|
||||||
return s.srv.getChannel(request.EmptyContext(s.srv.Log()), channelID)
|
return s.app.GetChannel(request.EmptyContext(s.app.Log()), channelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelMember gets a channel member by userID.
|
// GetChannelMember gets a channel member by userID.
|
||||||
func (s *channelsWrapper) GetChannelMember(channelID string, userID string) (*model.ChannelMember, *model.AppError) {
|
func (s *channelsWrapper) GetChannelMember(channelID string, userID string) (*model.ChannelMember, *model.AppError) {
|
||||||
return s.srv.getChannelMember(request.EmptyContext(s.srv.Log()), channelID, userID)
|
return s.app.GetChannelMember(request.EmptyContext(s.app.Log()), channelID, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *channelsWrapper) GetChannelsForTeamForUser(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError) {
|
func (s *channelsWrapper) GetChannelsForTeamForUser(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError) {
|
||||||
return s.srv.getChannelsForTeamForUser(request.EmptyContext(s.srv.Log()), teamID, userID, opts)
|
return s.app.GetChannelsForTeamForUser(request.EmptyContext(s.app.Log()), teamID, userID, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) GetChannelSidebarCategories(userID, teamID string) (*model.OrderedSidebarCategories, *model.AppError) {
|
||||||
|
return s.app.GetSidebarCategoriesForTeamForUser(request.EmptyContext(s.app.Log()), userID, teamID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) GetChannelMembers(channelID string, page, perPage int) (model.ChannelMembers, *model.AppError) {
|
||||||
|
return s.app.GetChannelMembersPage(request.EmptyContext(s.app.Log()), channelID, page, perPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) CreateChannelSidebarCategory(userID, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
return s.app.CreateSidebarCategory(request.EmptyContext(s.app.Log()), userID, teamID, newCategory)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) UpdateChannelSidebarCategories(userID, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) {
|
||||||
|
return s.app.UpdateSidebarCategories(request.EmptyContext(s.app.Log()), userID, teamID, categories)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) CreateChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
|
||||||
|
return s.app.CreateChannel(request.EmptyContext(s.app.Log()), channel, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) AddUserToChannel(channelID, userID, asUserID string) (*model.ChannelMember, *model.AppError) {
|
||||||
|
ctx := request.EmptyContext(s.app.Log())
|
||||||
|
channel, err := s.app.GetChannel(ctx, channelID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.app.AddChannelMember(ctx, userID, channel, ChannelMemberOpts{
|
||||||
|
UserRequestorID: asUserID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) UpdateChannelMemberRoles(channelID, userID, newRoles string) (*model.ChannelMember, *model.AppError) {
|
||||||
|
return s.app.UpdateChannelMemberRoles(request.EmptyContext(s.app.Log()), channelID, userID, newRoles)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) DeleteChannelMember(channelID, userID string) *model.AppError {
|
||||||
|
return s.app.LeaveChannel(request.EmptyContext(s.app.Log()), channelID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *channelsWrapper) AddChannelMember(channelID, userID string) (*model.ChannelMember, *model.AppError) {
|
||||||
|
channel, err := s.GetChannelByID(channelID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.app.AddChannelMember(request.EmptyContext(s.app.Log()), userID, channel, ChannelMemberOpts{
|
||||||
|
// For now, don't allow overriding these via the plugin API.
|
||||||
|
UserRequestorID: "",
|
||||||
|
PostRootID: "",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *channelsWrapper) GetDirectChannelOrCreate(userID1, userID2 string) (*model.Channel, *model.AppError) {
|
func (s *channelsWrapper) GetDirectChannelOrCreate(userID1, userID2 string) (*model.Channel, *model.AppError) {
|
||||||
return s.app.GetOrCreateDirectChannel(request.EmptyContext(s.srv.Log()), userID1, userID2)
|
return s.app.GetOrCreateDirectChannel(request.EmptyContext(s.app.Log()), userID1, userID2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the wrapper implements the product service.
|
// Ensure the wrapper implements the product service.
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ func NewChannels(services map[product.ServiceKey]any) (*Channels, error) {
|
|||||||
pluginsRoute.HandleFunc("/{anything:.*}", ch.ServePluginRequest)
|
pluginsRoute.HandleFunc("/{anything:.*}", ch.ServePluginRequest)
|
||||||
|
|
||||||
services[product.ChannelKey] = &channelsWrapper{
|
services[product.ChannelKey] = &channelsWrapper{
|
||||||
srv: s,
|
|
||||||
app: &App{ch: ch},
|
app: &App{ch: ch},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +243,10 @@ func NewChannels(services map[product.ServiceKey]any) (*Channels, error) {
|
|||||||
app: &App{ch: ch},
|
app: &App{ch: ch},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
services[product.CommandKey] = &App{ch: ch}
|
||||||
|
|
||||||
|
services[product.ThreadsKey] = &App{ch: ch}
|
||||||
|
|
||||||
return ch, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *App) registerCollectionAndTopic(pluginID, collectionType, topicType string) error {
|
func (a *App) RegisterCollectionAndTopic(pluginID, collectionType, topicType string) error {
|
||||||
// we have a race condition due to multiple plugins calling this method
|
// we have a race condition due to multiple plugins calling this method
|
||||||
a.ch.collectionAndTopicTypesMut.Lock()
|
a.ch.collectionAndTopicTypesMut.Lock()
|
||||||
defer a.ch.collectionAndTopicTypesMut.Unlock()
|
defer a.ch.collectionAndTopicTypesMut.Unlock()
|
||||||
|
|||||||
@@ -13682,6 +13682,28 @@ func (a *OpenTracingAppLayer) RegenerateTeamInviteId(teamID string) (*model.Team
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) RegisterCollectionAndTopic(pluginID string, collectionType string, topicType string) error {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RegisterCollectionAndTopic")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store().SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store().SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.RegisterCollectionAndTopic(pluginID, collectionType, topicType)
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) RegisterPluginCommand(pluginID string, command *model.Command) error {
|
func (a *OpenTracingAppLayer) RegisterPluginCommand(pluginID string, command *model.Command) error {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RegisterPluginCommand")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.RegisterPluginCommand")
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ func (s *permissionsServiceWrapper) HasPermissionToChannel(askingUserID string,
|
|||||||
return s.app.HasPermissionToChannel(request.EmptyContext(s.app.Log()), askingUserID, channelID, permission)
|
return s.app.HasPermissionToChannel(request.EmptyContext(s.app.Log()), askingUserID, channelID, permission)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *permissionsServiceWrapper) RolesGrantPermission(roleNames []string, permissionId string) bool {
|
||||||
|
return s.app.RolesGrantPermission(roleNames, permissionId)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) ResetPermissionsSystem() *model.AppError {
|
func (a *App) ResetPermissionsSystem() *model.AppError {
|
||||||
// Reset all Teams to not have a scheme.
|
// Reset all Teams to not have a scheme.
|
||||||
if err := a.Srv().Store().Team().ResetAllTeamSchemes(); err != nil {
|
if err := a.Srv().Store().Team().ResetAllTeamSchemes(); err != nil {
|
||||||
|
|||||||
@@ -1235,7 +1235,7 @@ func (api *PluginAPI) GetCloudLimits() (*model.ProductLimits, error) {
|
|||||||
// RegisterCollectionAndTopic informs the server that this plugin handles
|
// RegisterCollectionAndTopic informs the server that this plugin handles
|
||||||
// the given collection and topic types.
|
// the given collection and topic types.
|
||||||
func (api *PluginAPI) RegisterCollectionAndTopic(collectionType, topicType string) error {
|
func (api *PluginAPI) RegisterCollectionAndTopic(collectionType, topicType string) error {
|
||||||
return api.app.registerCollectionAndTopic(api.id, collectionType, topicType)
|
return api.app.RegisterCollectionAndTopic(api.id, collectionType, topicType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *PluginAPI) CreateUploadSession(us *model.UploadSession) (*model.UploadSession, error) {
|
func (api *PluginAPI) CreateUploadSession(us *model.UploadSession) (*model.UploadSession, error) {
|
||||||
|
|||||||
20
app/post.go
20
app/post.go
@@ -46,6 +46,26 @@ func (s *postServiceWrapper) CreatePost(ctx *request.Context, post *model.Post)
|
|||||||
return s.app.CreatePostMissingChannel(ctx, post, true)
|
return s.app.CreatePostMissingChannel(ctx, post, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *postServiceWrapper) GetPostsByIds(postIDs []string) ([]*model.Post, int64, *model.AppError) {
|
||||||
|
return s.app.GetPostsByIds(postIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *postServiceWrapper) SendEphemeralPost(ctx *request.Context, userID string, post *model.Post) *model.Post {
|
||||||
|
return s.app.SendEphemeralPost(ctx, userID, post)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *postServiceWrapper) GetPost(postID string) (*model.Post, *model.AppError) {
|
||||||
|
return s.app.GetSinglePost(postID, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *postServiceWrapper) DeletePost(ctx *request.Context, postID, productID string) (*model.Post, *model.AppError) {
|
||||||
|
return s.app.DeletePost(ctx, postID, productID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *postServiceWrapper) UpdatePost(ctx *request.Context, post *model.Post, safeUpdate bool) (*model.Post, *model.AppError) {
|
||||||
|
return s.app.UpdatePost(ctx, post, false)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) CreatePostAsUser(c request.CTX, 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
|
// Check that channel has not been deleted
|
||||||
channel, errCh := a.Srv().Store().Channel().Get(post.ChannelId, true)
|
channel, errCh := a.Srv().Store().Channel().Get(post.ChannelId, true)
|
||||||
|
|||||||
@@ -241,7 +241,6 @@ func NewServer(options ...Option) (*Server, error) {
|
|||||||
app := New(ServerConnector(s.Channels()))
|
app := New(ServerConnector(s.Channels()))
|
||||||
serviceMap := map[product.ServiceKey]any{
|
serviceMap := map[product.ServiceKey]any{
|
||||||
ServerKey: s,
|
ServerKey: s,
|
||||||
product.ChannelKey: &channelsWrapper{srv: s, app: app},
|
|
||||||
product.ConfigKey: s.platform,
|
product.ConfigKey: s.platform,
|
||||||
product.LicenseKey: s.licenseWrapper,
|
product.LicenseKey: s.licenseWrapper,
|
||||||
product.FilestoreKey: s.platform.FileBackend(),
|
product.FilestoreKey: s.platform.FileBackend(),
|
||||||
@@ -253,6 +252,8 @@ func NewServer(options ...Option) (*Server, error) {
|
|||||||
product.KVStoreKey: s.platform,
|
product.KVStoreKey: s.platform,
|
||||||
product.StoreKey: store.NewStoreServiceAdapter(s.Store()),
|
product.StoreKey: store.NewStoreServiceAdapter(s.Store()),
|
||||||
product.SystemKey: &systemServiceAdapter{server: s},
|
product.SystemKey: &systemServiceAdapter{server: s},
|
||||||
|
product.SessionKey: app,
|
||||||
|
product.FrontendKey: app,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: Initialize products.
|
// Step 4: Initialize products.
|
||||||
@@ -262,6 +263,13 @@ func NewServer(options ...Option) (*Server, error) {
|
|||||||
return nil, errors.Wrap(err, "failed to initialize products")
|
return nil, errors.Wrap(err, "failed to initialize products")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After channel is initialized set it to the App object
|
||||||
|
channelsWrapper, ok := serviceMap[product.ChannelKey].(*channelsWrapper)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.Wrap(err, "channels product is not initialized")
|
||||||
|
}
|
||||||
|
app.ch = channelsWrapper.app.ch
|
||||||
|
|
||||||
// It is important to initialize the hub only after the global logger is set
|
// It is important to initialize the hub only after the global logger is set
|
||||||
// to avoid race conditions while logging from inside the hub.
|
// to avoid race conditions while logging from inside the hub.
|
||||||
// Step 5: Start hub in platform which the hub depends on s.Channels() (step 4)
|
// Step 5: Start hub in platform which the hub depends on s.Channels() (step 4)
|
||||||
|
|||||||
13
app/team.go
13
app/team.go
@@ -44,6 +44,19 @@ func (w *teamServiceWrapper) CreateMember(ctx *request.Context, teamID, userID s
|
|||||||
return w.app.AddTeamMember(ctx, teamID, userID)
|
return w.app.AddTeamMember(ctx, teamID, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *teamServiceWrapper) GetGroup(groupID string) (*model.Group, *model.AppError) {
|
||||||
|
return w.app.GetGroup(groupID, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *teamServiceWrapper) GetTeam(teamID string) (*model.Team, *model.AppError) {
|
||||||
|
return w.app.GetTeam(teamID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *teamServiceWrapper) GetGroupMemberUsers(groupID string, page, perPage int) ([]*model.User, *model.AppError) {
|
||||||
|
users, _, err := w.app.GetGroupMemberUsersPage(groupID, page, perPage, nil)
|
||||||
|
return users, err
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the wrapper implements the product service.
|
// Ensure the wrapper implements the product service.
|
||||||
var _ product.TeamService = (*teamServiceWrapper)(nil)
|
var _ product.TeamService = (*teamServiceWrapper)(nil)
|
||||||
|
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ func GenerateLimitedClientConfig(c *model.Config, telemetryID string, license *m
|
|||||||
props["BuildEnterpriseReady"] = model.BuildEnterpriseReady
|
props["BuildEnterpriseReady"] = model.BuildEnterpriseReady
|
||||||
props["BuildHashBoards"] = model.BuildHashBoards
|
props["BuildHashBoards"] = model.BuildHashBoards
|
||||||
props["BuildBoards"] = model.BuildBoards
|
props["BuildBoards"] = model.BuildBoards
|
||||||
|
props["BuildHashPlaybooks"] = model.BuildHashPlaybooks
|
||||||
|
|
||||||
props["EnableBotAccountCreation"] = strconv.FormatBool(*c.ServiceSettings.EnableBotAccountCreation)
|
props["EnableBotAccountCreation"] = strconv.FormatBool(*c.ServiceSettings.EnableBotAccountCreation)
|
||||||
props["EnableFile"] = strconv.FormatBool(*c.LogSettings.EnableFile)
|
props["EnableFile"] = strconv.FormatBool(*c.LogSettings.EnableFile)
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ var BuildHashEnterprise string
|
|||||||
var BuildEnterpriseReady string
|
var BuildEnterpriseReady string
|
||||||
var BuildHashBoards string
|
var BuildHashBoards string
|
||||||
var BuildBoards string
|
var BuildBoards string
|
||||||
|
var BuildHashPlaybooks string
|
||||||
var versionsWithoutHotFixes []string
|
var versionsWithoutHotFixes []string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ type RouterService interface {
|
|||||||
// The service shall be registered via app.PostKey service key.
|
// The service shall be registered via app.PostKey service key.
|
||||||
type PostService interface {
|
type PostService interface {
|
||||||
CreatePost(context *request.Context, post *model.Post) (*model.Post, *model.AppError)
|
CreatePost(context *request.Context, post *model.Post) (*model.Post, *model.AppError)
|
||||||
|
GetPostsByIds(postIDs []string) ([]*model.Post, int64, *model.AppError)
|
||||||
|
SendEphemeralPost(ctx *request.Context, userID string, post *model.Post) *model.Post
|
||||||
|
GetPost(postID string) (*model.Post, *model.AppError)
|
||||||
|
DeletePost(ctx *request.Context, postID, productID string) (*model.Post, *model.AppError)
|
||||||
|
UpdatePost(c *request.Context, post *model.Post, safeUpdate bool) (*model.Post, *model.AppError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionService provides permissions related utilities. For now, the service implementation
|
// PermissionService provides permissions related utilities. For now, the service implementation
|
||||||
@@ -44,6 +49,7 @@ type PermissionService interface {
|
|||||||
HasPermissionTo(userID string, permission *model.Permission) bool
|
HasPermissionTo(userID string, permission *model.Permission) bool
|
||||||
HasPermissionToTeam(userID, teamID string, permission *model.Permission) bool
|
HasPermissionToTeam(userID, teamID string, permission *model.Permission) bool
|
||||||
HasPermissionToChannel(askingUserID string, channelID string, permission *model.Permission) bool
|
HasPermissionToChannel(askingUserID string, channelID string, permission *model.Permission) bool
|
||||||
|
RolesGrantPermission(roleNames []string, permissionID string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterService enables to publish cluster events. In addition to that, It's being used for
|
// ClusterService enables to publish cluster events. In addition to that, It's being used for
|
||||||
@@ -66,6 +72,15 @@ type ChannelService interface {
|
|||||||
GetChannelByID(channelID string) (*model.Channel, *model.AppError)
|
GetChannelByID(channelID string) (*model.Channel, *model.AppError)
|
||||||
GetChannelMember(channelID string, userID string) (*model.ChannelMember, *model.AppError)
|
GetChannelMember(channelID string, userID string) (*model.ChannelMember, *model.AppError)
|
||||||
GetChannelsForTeamForUser(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError)
|
GetChannelsForTeamForUser(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError)
|
||||||
|
GetChannelSidebarCategories(userID, teamID string) (*model.OrderedSidebarCategories, *model.AppError)
|
||||||
|
GetChannelMembers(channelID string, page, perPage int) (model.ChannelMembers, *model.AppError)
|
||||||
|
CreateChannelSidebarCategory(userID, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError)
|
||||||
|
UpdateChannelSidebarCategories(userID, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError)
|
||||||
|
CreateChannel(channel *model.Channel) (*model.Channel, *model.AppError)
|
||||||
|
AddUserToChannel(channelID, userID, asUserID string) (*model.ChannelMember, *model.AppError)
|
||||||
|
UpdateChannelMemberRoles(channelID, userID, newRoles string) (*model.ChannelMember, *model.AppError)
|
||||||
|
DeleteChannelMember(channelID, userID string) *model.AppError
|
||||||
|
AddChannelMember(channelID, userID string) (*model.ChannelMember, *model.AppError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LicenseService provides license related utilities.
|
// LicenseService provides license related utilities.
|
||||||
@@ -96,6 +111,9 @@ type UserService interface {
|
|||||||
type TeamService interface {
|
type TeamService interface {
|
||||||
GetMember(teamID, userID string) (*model.TeamMember, *model.AppError)
|
GetMember(teamID, userID string) (*model.TeamMember, *model.AppError)
|
||||||
CreateMember(ctx *request.Context, teamID, userID string) (*model.TeamMember, *model.AppError)
|
CreateMember(ctx *request.Context, teamID, userID string) (*model.TeamMember, *model.AppError)
|
||||||
|
GetGroup(groupId string) (*model.Group, *model.AppError)
|
||||||
|
GetTeam(teamID string) (*model.Team, *model.AppError)
|
||||||
|
GetGroupMemberUsers(groupID string, page, perPage int) ([]*model.User, *model.AppError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BotService is just a copy implementation of mattermost-plugin-api EnsureBot method.
|
// BotService is just a copy implementation of mattermost-plugin-api EnsureBot method.
|
||||||
@@ -161,6 +179,9 @@ type CloudService interface {
|
|||||||
// The service shall be registered via app.KVStoreKey service key.
|
// The service shall be registered via app.KVStoreKey service key.
|
||||||
type KVStoreService interface {
|
type KVStoreService interface {
|
||||||
SetPluginKeyWithOptions(pluginID string, key string, value []byte, options model.PluginKVSetOptions) (bool, *model.AppError)
|
SetPluginKeyWithOptions(pluginID string, key string, value []byte, options model.PluginKVSetOptions) (bool, *model.AppError)
|
||||||
|
KVGet(productID, key string) ([]byte, *model.AppError)
|
||||||
|
KVDelete(productID, key string) *model.AppError
|
||||||
|
KVList(productID string, page, perPage int) ([]string, *model.AppError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogService is the API for accessing the log service APIs.
|
// LogService is the API for accessing the log service APIs.
|
||||||
@@ -212,3 +233,32 @@ type BoardsService interface {
|
|||||||
HasPermissionToBoard(userID, boardID string, permission *model.Permission) bool
|
HasPermissionToBoard(userID, boardID string, permission *model.Permission) bool
|
||||||
DuplicateBoard(boardID string, userID string, toTeam string, asTemplate bool) (*fb_model.BoardsAndBlocks, []*fb_model.BoardMember, error)
|
DuplicateBoard(boardID string, userID string, toTeam string, asTemplate bool) (*fb_model.BoardsAndBlocks, []*fb_model.BoardMember, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SessionService is the API for accessing the session.
|
||||||
|
//
|
||||||
|
// The service shall be registered via app.SessionKey service key.
|
||||||
|
type SessionService interface {
|
||||||
|
GetSessionById(sessionID string) (*model.Session, *model.AppError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FrontendService is the API for interacting with front end.
|
||||||
|
//
|
||||||
|
// The service shall be registered via app.FrontendKey service key.
|
||||||
|
type FrontendService interface {
|
||||||
|
OpenInteractiveDialog(dialog model.OpenDialogRequest) *model.AppError
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandService is the API for interacting with front end.
|
||||||
|
//
|
||||||
|
// The service shall be registered via app.CommandKey service key.
|
||||||
|
type CommandService interface {
|
||||||
|
ExecuteCommand(c request.CTX, args *model.CommandArgs) (*model.CommandResponse, *model.AppError)
|
||||||
|
RegisterPluginCommand(pluginID string, command *model.Command) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThreadsService is the API for interacting with threads anywhere.
|
||||||
|
//
|
||||||
|
// The service shall be registered via app.ThreadsKey service key.
|
||||||
|
type ThreadsService interface {
|
||||||
|
RegisterCollectionAndTopic(productID string, collectionType, topicType string) error
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,4 +26,8 @@ const (
|
|||||||
SystemKey ServiceKey = "systemkey"
|
SystemKey ServiceKey = "systemkey"
|
||||||
PreferencesKey ServiceKey = "preferenceskey"
|
PreferencesKey ServiceKey = "preferenceskey"
|
||||||
BoardsKey ServiceKey = "boards"
|
BoardsKey ServiceKey = "boards"
|
||||||
|
SessionKey ServiceKey = "sessionkey"
|
||||||
|
FrontendKey ServiceKey = "frontendkey"
|
||||||
|
CommandKey ServiceKey = "commandkey"
|
||||||
|
ThreadsKey ServiceKey = "threadskey"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,5 +16,10 @@ then
|
|||||||
txt="${txt}use ../focalboard/server\nuse ../focalboard/mattermost-plugin\n"
|
txt="${txt}use ../focalboard/server\nuse ../focalboard/mattermost-plugin\n"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$BUILD_PLAYBOOKS" == "true" ]
|
||||||
|
then
|
||||||
|
txt="${txt}use ../mattermost-plugin-playbooks\n"
|
||||||
|
fi
|
||||||
|
|
||||||
printf "$txt" > "go.work"
|
printf "$txt" > "go.work"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mattermost/go-i18n/i18n"
|
"github.com/mattermost/go-i18n/i18n"
|
||||||
|
"github.com/mattermost/go-i18n/i18n/bundle"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||||
)
|
)
|
||||||
@@ -22,6 +23,9 @@ const defaultLocale = "en"
|
|||||||
// TranslateFunc is the type of the translate functions
|
// TranslateFunc is the type of the translate functions
|
||||||
type TranslateFunc func(translationID string, args ...any) string
|
type TranslateFunc func(translationID string, args ...any) string
|
||||||
|
|
||||||
|
// TranslationFuncByLocal is the type of function that takes local as a string and returns the translation function
|
||||||
|
type TranslationFuncByLocal func(locale string) TranslateFunc
|
||||||
|
|
||||||
// T is the translate function using the default server language as fallback language
|
// T is the translate function using the default server language as fallback language
|
||||||
var T TranslateFunc
|
var T TranslateFunc
|
||||||
|
|
||||||
@@ -74,6 +78,41 @@ func initTranslationsWithDir(dir string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTranslationFuncForDir loads translations from the filesystem into a new instance of the bundle.
|
||||||
|
// It returns a function to access loaded translations.
|
||||||
|
func GetTranslationFuncForDir(dir string) (TranslationFuncByLocal, error) {
|
||||||
|
var availableLocals map[string]string = make(map[string]string)
|
||||||
|
bundle := bundle.New()
|
||||||
|
files, _ := os.ReadDir(dir)
|
||||||
|
for _, f := range files {
|
||||||
|
if filepath.Ext(f.Name()) != ".json" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := f.Name()
|
||||||
|
availableLocals[strings.Split(filename, ".")[0]] = filepath.Join(dir, filename)
|
||||||
|
if err := bundle.LoadTranslationFile(filepath.Join(dir, filename)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(locale string) TranslateFunc {
|
||||||
|
if _, ok := availableLocals[locale]; !ok {
|
||||||
|
locale = defaultLocale
|
||||||
|
}
|
||||||
|
|
||||||
|
t, _ := bundle.Tfunc(locale)
|
||||||
|
return func(translationID string, args ...any) string {
|
||||||
|
if translated := t(translationID, args...); translated != translationID {
|
||||||
|
return translated
|
||||||
|
}
|
||||||
|
|
||||||
|
t, _ := bundle.Tfunc(defaultLocale)
|
||||||
|
return t(translationID, args...)
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func getTranslationsBySystemLocale() (TranslateFunc, error) {
|
func getTranslationsBySystemLocale() (TranslateFunc, error) {
|
||||||
locale := defaultServerLocale
|
locale := defaultServerLocale
|
||||||
if _, ok := locales[locale]; !ok {
|
if _, ok := locales[locale]; !ok {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user