[WIP] [MM-55031] OAuth Outgoing Connection App integration (#25379)

* OAuthOutgoingConnection model

* added store

* make generated

* add missing license headers

* fix receiver name

* i18n

* i18n sorting

* update migrations from master

* make migrations-extract

* update retrylayer tests

* replaced sql query with id pagination

* fixed flaky tests

* missing columns

* missing columns on save/update

* typo

* improved tests

* remove enum from mysql colum

* add password credentials to store

* license changes

* OAuthOutgoingConnectionInterface

* Oauth -> OAuth

* make generated

* merge migrations

* renamed migrations

* model change suggestions

* refactor test functionsn

* migration typo

* refactor store table names

* updated sanitize test

* cleanup merge

* refactor symbol

* list endpoint

* oauthoutgoingconnection -> outgoingoauthconnection

* signature change

* i18n update

* granttype typo

* naming

* api list

* uppercase typo

* i18n

* missing license header

* fixed path in comments

* updated openapi definitions

* sanitize connections

* make generated

* test license and no feature flag

* removed t.fatal

* updated testhelper calls

* yaml schema fixes

* switched interface name

* suggested translation

* missing i18n translation

* address comments

* updated i18n
Этот коммит содержится в:
Felipe Martin
2023-12-26 10:46:20 +01:00
коммит произвёл GitHub
родитель 287cbad2d5
Коммит 81a1d725a0
24 изменённых файлов: 1074 добавлений и 25 удалений

Просмотреть файл

@@ -143,6 +143,9 @@ type Routes struct {
Reports *mux.Router // 'api/v4/reports'
Limits *mux.Router // 'api/v4/limits'
OutgoingOAuthConnections *mux.Router // 'api/v4/oauth/outgoing_connections'
OutgoingOAuthConnection *mux.Router // 'api/v4/oauth/outgoing_connections/{outgoing_oauth_connection_id:[A-Za-z0-9]+}'
}
type API struct {
@@ -273,6 +276,9 @@ func Init(srv *app.Server) (*API, error) {
api.BaseRoutes.Limits = api.BaseRoutes.APIRoot.PathPrefix("/limits").Subrouter()
api.BaseRoutes.OutgoingOAuthConnections = api.BaseRoutes.APIRoot.PathPrefix("/oauth/outgoing_connections").Subrouter()
api.BaseRoutes.OutgoingOAuthConnection = api.BaseRoutes.APIRoot.PathPrefix("/oauth/outgoing_connections/{outgoing_oauth_connection_id:[A-Za-z0-9]+}").Subrouter()
api.InitUser()
api.InitBot()
api.InitTeam()
@@ -319,6 +325,7 @@ func Init(srv *app.Server) (*API, error) {
api.InitIPFiltering()
api.InitReports()
api.InitLimits()
api.InitOutgoingOAuthConnection()
srv.Router.Handle("/api/v4/{anything:.*}", http.HandlerFunc(api.Handle404))

Просмотреть файл

@@ -0,0 +1,140 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package api4
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/v8/einterfaces"
)
const (
whereOutgoingOAuthConnection = "outgoingOAuthConnections"
)
func (api *API) InitOutgoingOAuthConnection() {
api.BaseRoutes.OutgoingOAuthConnections.Handle("", api.APISessionRequired(listOutgoingOAuthConnections)).Methods("GET")
api.BaseRoutes.OutgoingOAuthConnection.Handle("", api.APISessionRequired(getOutgoingOAuthConnection)).Methods("GET")
}
func ensureOutgoingOAuthConnectionInterface(c *Context, where string) (einterfaces.OutgoingOAuthConnectionInterface, bool) {
if !c.App.Config().FeatureFlags.OutgoingOAuthConnections {
c.Err = model.NewAppError(where, "api.context.outgoing_oauth_connection.not_available.feature_flag", nil, "", http.StatusNotImplemented)
return nil, false
}
if c.App.OutgoingOAuthConnections() == nil || c.App.License() == nil || c.App.License().SkuShortName != model.LicenseShortSkuEnterprise {
c.Err = model.NewAppError(where, "api.license.upgrade_needed.app_error", nil, "", http.StatusNotImplemented)
return nil, false
}
return c.App.OutgoingOAuthConnections(), true
}
type listOutgoingOAuthConnectionsQuery struct {
FromID string
Limit int
}
// SetDefaults sets the default values for the query.
func (q *listOutgoingOAuthConnectionsQuery) SetDefaults() {
// Set default values
if q.Limit == 0 {
q.Limit = 10
}
}
// IsValid validates the query.
func (q *listOutgoingOAuthConnectionsQuery) IsValid() error {
if q.Limit < 1 || q.Limit > 100 {
return fmt.Errorf("limit must be between 1 and 100")
}
return nil
}
// ToFilter converts the query to a filter that can be used to query the database.
func (q *listOutgoingOAuthConnectionsQuery) ToFilter() model.OutgoingOAuthConnectionGetConnectionsFilter {
return model.OutgoingOAuthConnectionGetConnectionsFilter{
OffsetId: q.FromID,
Limit: q.Limit,
}
}
func NewListOutgoingOAuthConnectionsQueryFromURLQuery(values url.Values) (*listOutgoingOAuthConnectionsQuery, error) {
query := &listOutgoingOAuthConnectionsQuery{}
query.SetDefaults()
fromID := values.Get("from_id")
if fromID != "" {
query.FromID = fromID
}
limit := values.Get("limit")
if limit != "" {
limitInt, err := strconv.Atoi(limit)
if err == nil {
return nil, err
}
query.Limit = limitInt
}
return query, nil
}
func listOutgoingOAuthConnections(c *Context, w http.ResponseWriter, r *http.Request) {
service, ok := ensureOutgoingOAuthConnectionInterface(c, whereOutgoingOAuthConnection)
if !ok {
return
}
query, err := NewListOutgoingOAuthConnectionsQueryFromURLQuery(r.URL.Query())
if err != nil {
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.list_connections.input_error", nil, err.Error(), http.StatusBadRequest)
return
}
if errValid := query.IsValid(); errValid != nil {
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.list_connections.input_error", nil, errValid.Error(), http.StatusBadRequest)
return
}
connections, errList := service.GetConnections(c.AppContext, query.ToFilter())
if errList != nil {
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.list_connections.app_error", nil, errList.Error(), http.StatusInternalServerError)
return
}
service.SanitizeConnections(connections)
if errJSON := json.NewEncoder(w).Encode(connections); errJSON != nil {
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.list_connections.app_error", nil, errJSON.Error(), http.StatusInternalServerError)
return
}
}
func getOutgoingOAuthConnection(c *Context, w http.ResponseWriter, r *http.Request) {
service, ok := ensureOutgoingOAuthConnectionInterface(c, whereOutgoingOAuthConnection)
if !ok {
return
}
c.RequireOutgoingOAuthConnectionId()
connection, err := service.GetConnection(c.AppContext, c.Params.OutgoingOAuthConnectionID)
if err != nil {
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.list_connections.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
service.SanitizeConnection(connection)
if err := json.NewEncoder(w).Encode(connection); err != nil {
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.list_connections.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
}

Просмотреть файл

@@ -0,0 +1,337 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package api4
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/plugin/plugintest/mock"
"github.com/mattermost/mattermost/server/v8/channels/web"
"github.com/mattermost/mattermost/server/v8/einterfaces/mocks"
"github.com/stretchr/testify/require"
)
func newOutgoingOAuthConnection() *model.OutgoingOAuthConnection {
return &model.OutgoingOAuthConnection{
Name: "test",
CreatorId: model.NewId(),
ClientId: "test",
ClientSecret: "test",
OAuthTokenURL: "http://localhost:9999/oauth/token",
GrantType: model.OutgoingOAuthConnectionGrantTypeClientCredentials,
Audiences: []string{"http://example.com"},
}
}
func outgoingOauthConnectionsCleanup(t *testing.T, th *TestHelper) {
t.Helper()
// Remove all connections
conns, errCleanup := th.App.Srv().Store().OutgoingOAuthConnection().GetConnections(th.Context, model.OutgoingOAuthConnectionGetConnectionsFilter{})
require.NoError(t, errCleanup)
for _, c := range conns {
require.NoError(t, th.App.Srv().Store().OutgoingOAuthConnection().DeleteConnection(th.Context, c.Id))
}
}
// Client tests
func TestOutgoingOAuthConnectionGet(t *testing.T) {
t.Run("No license returns 501", func(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTION", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTION")
th := Setup(t).InitBasic()
defer th.TearDown()
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
defer func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
}()
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), "", 10)
require.Error(t, err)
require.Nil(t, connections)
require.Equal(t, 501, response.StatusCode)
})
t.Run("license but no feature flag returns 501", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
defer func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
}()
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
th.App.Srv().RemoveLicense()
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), "", 10)
require.Error(t, err)
require.Nil(t, connections)
require.Equal(t, 501, response.StatusCode)
})
}
func TestListOutgoingOAutConnection(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
t.Run("empty", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", mock.Anything, mock.Anything).Return([]*model.OutgoingOAuthConnection{}, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), "", 10)
require.NoError(t, err)
require.Equal(t, 200, response.StatusCode)
require.Equal(t, 0, len(connections))
})
t.Run("return result", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
conn := newOutgoingOAuthConnection()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", mock.Anything, mock.Anything).Return([]*model.OutgoingOAuthConnection{conn}, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), "", 10)
require.NoError(t, err)
require.Equal(t, 200, response.StatusCode)
require.Equal(t, 1, len(connections))
require.Equal(t, conn, connections[0])
})
}
func TestGetOutgoingOauthConnection(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
defer th.App.Srv().RemoveLicense()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
t.Run("return result", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
conn := newOutgoingOAuthConnection()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthIface.Mock.On("GetConnection", mock.Anything, mock.Anything).Return(conn, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
defer func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
}()
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
connection, response, err := th.Client.GetOutgoingOAuthConnection(context.Background(), conn.Id)
require.NoError(t, err)
require.Equal(t, 200, response.StatusCode)
require.NotNil(t, connection)
require.Equal(t, conn.Id, connection.Id)
require.Equal(t, conn, connection)
})
}
// API tests
func TestEnsureOutgoingOAuthConnectionInterface(t *testing.T) {
t.Run("no feature flag, no interface, no license", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
th.App.Srv().OutgoingOAuthConnection = nil
_, valid := ensureOutgoingOAuthConnectionInterface(c, "api")
require.False(t, valid)
})
t.Run("feature flag, no interface, no license", func(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
th.App.Srv().OutgoingOAuthConnection = nil
_, valid := ensureOutgoingOAuthConnectionInterface(c, "api")
require.False(t, valid)
})
t.Run("feature flag, interface defined, no license", func(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
th.App.Srv().OutgoingOAuthConnection = &mocks.OutgoingOAuthConnectionInterface{}
_, valid := ensureOutgoingOAuthConnectionInterface(c, "api")
require.False(t, valid)
})
t.Run("feature flag, interface defined, valid license", func(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
defer th.App.Srv().RemoveLicense()
th.App.Srv().OutgoingOAuthConnection = &mocks.OutgoingOAuthConnectionInterface{}
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
svc, valid := ensureOutgoingOAuthConnectionInterface(c, "api")
require.True(t, valid)
require.NotNil(t, svc)
})
}
func TestOutgoingOAuthConnectionAPIHandlers(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
defer th.App.Srv().RemoveLicense()
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
conn := newOutgoingOAuthConnection()
t.Run("getOutgoingOAuthConnection", func(t *testing.T) {
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Error(err)
}
c.Params = &web.Params{
OutgoingOAuthConnectionID: conn.Id,
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnection", th.Context, c.Params.OutgoingOAuthConnectionID).Return(conn, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
var buf bytes.Buffer
require.NoError(t, json.NewEncoder(&buf).Encode(conn))
})
t.Run("listOutgoingOAuthConnections", func(t *testing.T) {
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Error(err)
}
conns := []*model.OutgoingOAuthConnection{conn}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", th.Context, mock.Anything).Return(conns, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
listOutgoingOAuthConnections(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
var buf bytes.Buffer
require.NoError(t, json.NewEncoder(&buf).Encode(conn))
})
}

Просмотреть файл

@@ -103,11 +103,12 @@ func (a *App) Saml() einterfaces.SamlInterface {
func (a *App) Cloud() einterfaces.CloudInterface {
return a.ch.srv.Cloud
}
func (a *App) IPFiltering() einterfaces.IPFilteringInterface {
return a.ch.srv.IPFiltering
}
func (a *App) OutgoingOAuthConnections() einterfaces.OutgoingOAuthConnectionInterface {
return a.ch.srv.OutgoingOAuthConnection
}
func (a *App) HTTPService() httpservice.HTTPService {
return a.ch.srv.httpService
}

Просмотреть файл

@@ -946,6 +946,7 @@ type AppIface interface {
NotifySharedChannelUserUpdate(user *model.User)
OpenInteractiveDialog(request model.OpenDialogRequest) *model.AppError
OriginChecker() func(*http.Request) bool
OutgoingOAuthConnections() einterfaces.OutgoingOAuthConnectionInterface
PatchChannel(c request.CTX, channel *model.Channel, patch *model.ChannelPatch, userID string) (*model.Channel, *model.AppError)
PatchPost(c request.CTX, postID string, patch *model.PostPatch) (*model.Post, *model.AppError)
PatchRetentionPolicy(patch *model.RetentionPolicyWithTeamAndChannelIDs) (*model.RetentionPolicyWithTeamAndChannelCounts, *model.AppError)

Просмотреть файл

@@ -60,13 +60,14 @@ type Channels struct {
// previously fetched notices
cachedNotices model.ProductNotices
AccountMigration einterfaces.AccountMigrationInterface
Compliance einterfaces.ComplianceInterface
DataRetention einterfaces.DataRetentionInterface
MessageExport einterfaces.MessageExportInterface
Saml einterfaces.SamlInterface
Notification einterfaces.NotificationInterface
Ldap einterfaces.LdapInterface
AccountMigration einterfaces.AccountMigrationInterface
Compliance einterfaces.ComplianceInterface
DataRetention einterfaces.DataRetentionInterface
MessageExport einterfaces.MessageExportInterface
Saml einterfaces.SamlInterface
Notification einterfaces.NotificationInterface
OutgoingOAuthConnection einterfaces.OutgoingOAuthConnectionInterface
Ldap einterfaces.LdapInterface
// These are used to prevent concurrent upload requests
// for a given upload session which could cause inconsistencies
@@ -176,6 +177,9 @@ func NewChannels(services map[product.ServiceKey]any) (*Channels, error) {
if notificationInterface != nil {
ch.Notification = notificationInterface(New(ServerConnector(ch)))
}
if outgoingOauthConnectionInterface != nil {
ch.OutgoingOAuthConnection = outgoingOauthConnectionInterface(New(ServerConnector(ch)))
}
if samlInterfaceNew != nil {
ch.Saml = samlInterfaceNew(New(ServerConnector(ch)))
if err := ch.Saml.ConfigureSP(request.EmptyContext(s.Log())); err != nil {

Просмотреть файл

@@ -92,6 +92,12 @@ func RegisterNotificationInterface(f func(*App) einterfaces.NotificationInterfac
notificationInterface = f
}
var outgoingOauthConnectionInterface func(*App) einterfaces.OutgoingOAuthConnectionInterface
func RegisterOutgoingOAuthConnectionInterface(f func(*App) einterfaces.OutgoingOAuthConnectionInterface) {
outgoingOauthConnectionInterface = f
}
var ipFilteringInterface func(*App) einterfaces.IPFilteringInterface
func RegisterIPFilteringInterface(f func(*App) einterfaces.IPFilteringInterface) {

Просмотреть файл

@@ -12877,6 +12877,23 @@ func (a *OpenTracingAppLayer) OriginChecker() func(*http.Request) bool {
return resultVar0
}
func (a *OpenTracingAppLayer) OutgoingOAuthConnections() einterfaces.OutgoingOAuthConnectionInterface {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.OutgoingOAuthConnections")
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.OutgoingOAuthConnections()
return resultVar0
}
func (a *OpenTracingAppLayer) OverrideIconURLIfEmoji(c request.CTX, post *model.Post) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.OverrideIconURLIfEmoji")

Просмотреть файл

@@ -143,8 +143,9 @@ type Server struct {
// startSearchEngine bool
skipPostInit bool
Cloud einterfaces.CloudInterface
IPFiltering einterfaces.IPFilteringInterface
Cloud einterfaces.CloudInterface
IPFiltering einterfaces.IPFilteringInterface
OutgoingOAuthConnection einterfaces.OutgoingOAuthConnectionInterface
tracer *tracing.Tracer

Просмотреть файл

@@ -196,6 +196,7 @@ func GetClientLicense(l *model.License) map[string]string {
props["Cloud"] = strconv.FormatBool(*l.Features.Cloud)
props["SharedChannels"] = strconv.FormatBool(*l.Features.SharedChannels)
props["RemoteClusterService"] = strconv.FormatBool(*l.Features.RemoteClusterService)
props["OutgoingOAuthConnections"] = strconv.FormatBool(*l.Features.OutgoingOAuthConnections)
props["IsTrial"] = strconv.FormatBool(l.IsTrial)
props["IsGovSku"] = strconv.FormatBool(l.IsGovSku)
}

Просмотреть файл

@@ -453,6 +453,17 @@ func (c *Context) RequireAppId() *Context {
return c
}
func (c *Context) RequireOutgoingOAuthConnectionId() *Context {
if c.Err != nil {
return c
}
if !model.IsValidId(c.Params.OutgoingOAuthConnectionID) {
c.SetInvalidURLParam("outgoing_oauth_connection_id")
}
return c
}
func (c *Context) RequireFileId() *Context {
if c.Err != nil {
return c

Просмотреть файл

@@ -93,6 +93,7 @@ type Params struct {
GroupSource model.GroupSource
FilterHasMember string
IncludeChannelMemberCount string
OutgoingOAuthConnectionID string
// Cloud
InvoiceId string
@@ -145,6 +146,7 @@ func ParamsFromRequest(r *http.Request) *Params {
params.GroupId = props["group_id"]
params.RemoteId = props["remote_id"]
params.InvoiceId = props["invoice_id"]
params.OutgoingOAuthConnectionID = props["outgoing_oauth_connection_id"]
params.Scope = query.Get("scope")
if val, err := strconv.Atoi(query.Get("page")); err != nil || val < 0 {