[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
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
287cbad2d5
Коммит
81a1d725a0
@@ -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))
|
||||
|
||||
|
||||
140
server/channels/api4/outgoing_oauth_connection.go
Обычный файл
140
server/channels/api4/outgoing_oauth_connection.go
Обычный файл
@@ -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
|
||||
}
|
||||
}
|
||||
337
server/channels/api4/outgoing_oauth_connection_test.go
Обычный файл
337
server/channels/api4/outgoing_oauth_connection_test.go
Обычный файл
@@ -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 {
|
||||
|
||||
Ссылка в новой задаче
Block a user