[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
@@ -52,6 +52,7 @@ build-v4: node_modules playbooks
|
|||||||
@cat $(V4_SRC)/ip_filters.yaml >> $(V4_YAML)
|
@cat $(V4_SRC)/ip_filters.yaml >> $(V4_YAML)
|
||||||
@cat $(V4_SRC)/reports.yaml >> $(V4_YAML)
|
@cat $(V4_SRC)/reports.yaml >> $(V4_YAML)
|
||||||
@cat $(V4_SRC)/limits.yaml >> $(V4_YAML)
|
@cat $(V4_SRC)/limits.yaml >> $(V4_YAML)
|
||||||
|
@cat $(V4_SRC)/outgoing_oauth_connections.yaml >> $(V4_YAML)
|
||||||
@if [ -r $(PLAYBOOKS_SRC)/paths.yaml ]; then cat $(PLAYBOOKS_SRC)/paths.yaml >> $(V4_YAML); fi
|
@if [ -r $(PLAYBOOKS_SRC)/paths.yaml ]; then cat $(PLAYBOOKS_SRC)/paths.yaml >> $(V4_YAML); fi
|
||||||
@if [ -r $(PLAYBOOKS_SRC)/merged-definitions.yaml ]; then cat $(PLAYBOOKS_SRC)/merged-definitions.yaml >> $(V4_YAML); else cat $(V4_SRC)/definitions.yaml >> $(V4_YAML); fi
|
@if [ -r $(PLAYBOOKS_SRC)/merged-definitions.yaml ]; then cat $(PLAYBOOKS_SRC)/merged-definitions.yaml >> $(V4_YAML); else cat $(V4_SRC)/definitions.yaml >> $(V4_YAML); fi
|
||||||
@echo Extracting code samples
|
@echo Extracting code samples
|
||||||
|
|||||||
@@ -3580,6 +3580,30 @@ components:
|
|||||||
description: The number of active users in the server
|
description: The number of active users in the server
|
||||||
type: integer
|
type: integer
|
||||||
format: int64
|
format: int64
|
||||||
|
# Outgoing OAuth Connections
|
||||||
|
OutgoingOAuthConnectionGetItem:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
description: The unique identifier for the outgoing OAuth connection.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: The name of the outgoing OAuth connection.
|
||||||
|
type: string
|
||||||
|
create_at:
|
||||||
|
description: The time in milliseconds the outgoing OAuth connection was created.
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
update_at:
|
||||||
|
description: The time in milliseconds the outgoing OAuth connection was last updated.
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
grant_type:
|
||||||
|
description: The grant type of the outgoing OAuth connection.
|
||||||
|
type: string
|
||||||
|
audiences:
|
||||||
|
description: The audiences of the outgoing OAuth connection.
|
||||||
|
type: string
|
||||||
externalDocs:
|
externalDocs:
|
||||||
description: Find out more about Mattermost
|
description: Find out more about Mattermost
|
||||||
url: 'https://about.mattermost.com'
|
url: 'https://about.mattermost.com'
|
||||||
|
|||||||
52
api/v4/source/outgoing_oauth_connections.yaml
Обычный файл
52
api/v4/source/outgoing_oauth_connections.yaml
Обычный файл
@@ -0,0 +1,52 @@
|
|||||||
|
/api/v4/oauth/outgoing_connections:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- oauth
|
||||||
|
- outgoing_connections
|
||||||
|
- outgoing_oauth_connections
|
||||||
|
summary: List all connections
|
||||||
|
description: >
|
||||||
|
List all outgoing OAuth connections.
|
||||||
|
|
||||||
|
__Minimum server version__: 9.5
|
||||||
|
operationId: ListOutgoingOAuthConnections
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successfully fetched outgoing OAuth connections
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/OutgoingOAuthConnectionGetItem"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/InternalServerError"
|
||||||
|
"501":
|
||||||
|
$ref: "#/components/responses/NotImplemented"
|
||||||
|
/api/v4/oauth/outgoing_connections/{connection_id}:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- oauth
|
||||||
|
- outgoing_connections
|
||||||
|
- outgoing_oauth_connections
|
||||||
|
summary: Get a connection
|
||||||
|
description: >
|
||||||
|
Retrieve an outgoing OAuth connection.
|
||||||
|
|
||||||
|
__Minimum server version__: 9.5
|
||||||
|
operationId: GetOutgoingOAuthConnection
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successfully fetched outgoing OAuth connection
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/OutgoingOAuthConnectionGetItem"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/InternalServerError"
|
||||||
|
"501":
|
||||||
|
$ref: "#/components/responses/NotImplemented"
|
||||||
@@ -143,6 +143,9 @@ type Routes struct {
|
|||||||
Reports *mux.Router // 'api/v4/reports'
|
Reports *mux.Router // 'api/v4/reports'
|
||||||
|
|
||||||
Limits *mux.Router // 'api/v4/limits'
|
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 {
|
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.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.InitUser()
|
||||||
api.InitBot()
|
api.InitBot()
|
||||||
api.InitTeam()
|
api.InitTeam()
|
||||||
@@ -319,6 +325,7 @@ func Init(srv *app.Server) (*API, error) {
|
|||||||
api.InitIPFiltering()
|
api.InitIPFiltering()
|
||||||
api.InitReports()
|
api.InitReports()
|
||||||
api.InitLimits()
|
api.InitLimits()
|
||||||
|
api.InitOutgoingOAuthConnection()
|
||||||
|
|
||||||
srv.Router.Handle("/api/v4/{anything:.*}", http.HandlerFunc(api.Handle404))
|
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 {
|
func (a *App) Cloud() einterfaces.CloudInterface {
|
||||||
return a.ch.srv.Cloud
|
return a.ch.srv.Cloud
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) IPFiltering() einterfaces.IPFilteringInterface {
|
func (a *App) IPFiltering() einterfaces.IPFilteringInterface {
|
||||||
return a.ch.srv.IPFiltering
|
return a.ch.srv.IPFiltering
|
||||||
}
|
}
|
||||||
|
func (a *App) OutgoingOAuthConnections() einterfaces.OutgoingOAuthConnectionInterface {
|
||||||
|
return a.ch.srv.OutgoingOAuthConnection
|
||||||
|
}
|
||||||
func (a *App) HTTPService() httpservice.HTTPService {
|
func (a *App) HTTPService() httpservice.HTTPService {
|
||||||
return a.ch.srv.httpService
|
return a.ch.srv.httpService
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -946,6 +946,7 @@ type AppIface interface {
|
|||||||
NotifySharedChannelUserUpdate(user *model.User)
|
NotifySharedChannelUserUpdate(user *model.User)
|
||||||
OpenInteractiveDialog(request model.OpenDialogRequest) *model.AppError
|
OpenInteractiveDialog(request model.OpenDialogRequest) *model.AppError
|
||||||
OriginChecker() func(*http.Request) bool
|
OriginChecker() func(*http.Request) bool
|
||||||
|
OutgoingOAuthConnections() einterfaces.OutgoingOAuthConnectionInterface
|
||||||
PatchChannel(c request.CTX, channel *model.Channel, patch *model.ChannelPatch, userID string) (*model.Channel, *model.AppError)
|
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)
|
PatchPost(c request.CTX, postID string, patch *model.PostPatch) (*model.Post, *model.AppError)
|
||||||
PatchRetentionPolicy(patch *model.RetentionPolicyWithTeamAndChannelIDs) (*model.RetentionPolicyWithTeamAndChannelCounts, *model.AppError)
|
PatchRetentionPolicy(patch *model.RetentionPolicyWithTeamAndChannelIDs) (*model.RetentionPolicyWithTeamAndChannelCounts, *model.AppError)
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ type Channels struct {
|
|||||||
MessageExport einterfaces.MessageExportInterface
|
MessageExport einterfaces.MessageExportInterface
|
||||||
Saml einterfaces.SamlInterface
|
Saml einterfaces.SamlInterface
|
||||||
Notification einterfaces.NotificationInterface
|
Notification einterfaces.NotificationInterface
|
||||||
|
OutgoingOAuthConnection einterfaces.OutgoingOAuthConnectionInterface
|
||||||
Ldap einterfaces.LdapInterface
|
Ldap einterfaces.LdapInterface
|
||||||
|
|
||||||
// These are used to prevent concurrent upload requests
|
// These are used to prevent concurrent upload requests
|
||||||
@@ -176,6 +177,9 @@ func NewChannels(services map[product.ServiceKey]any) (*Channels, error) {
|
|||||||
if notificationInterface != nil {
|
if notificationInterface != nil {
|
||||||
ch.Notification = notificationInterface(New(ServerConnector(ch)))
|
ch.Notification = notificationInterface(New(ServerConnector(ch)))
|
||||||
}
|
}
|
||||||
|
if outgoingOauthConnectionInterface != nil {
|
||||||
|
ch.OutgoingOAuthConnection = outgoingOauthConnectionInterface(New(ServerConnector(ch)))
|
||||||
|
}
|
||||||
if samlInterfaceNew != nil {
|
if samlInterfaceNew != nil {
|
||||||
ch.Saml = samlInterfaceNew(New(ServerConnector(ch)))
|
ch.Saml = samlInterfaceNew(New(ServerConnector(ch)))
|
||||||
if err := ch.Saml.ConfigureSP(request.EmptyContext(s.Log())); err != nil {
|
if err := ch.Saml.ConfigureSP(request.EmptyContext(s.Log())); err != nil {
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ func RegisterNotificationInterface(f func(*App) einterfaces.NotificationInterfac
|
|||||||
notificationInterface = f
|
notificationInterface = f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var outgoingOauthConnectionInterface func(*App) einterfaces.OutgoingOAuthConnectionInterface
|
||||||
|
|
||||||
|
func RegisterOutgoingOAuthConnectionInterface(f func(*App) einterfaces.OutgoingOAuthConnectionInterface) {
|
||||||
|
outgoingOauthConnectionInterface = f
|
||||||
|
}
|
||||||
|
|
||||||
var ipFilteringInterface func(*App) einterfaces.IPFilteringInterface
|
var ipFilteringInterface func(*App) einterfaces.IPFilteringInterface
|
||||||
|
|
||||||
func RegisterIPFilteringInterface(f 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
|
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) {
|
func (a *OpenTracingAppLayer) OverrideIconURLIfEmoji(c request.CTX, post *model.Post) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.OverrideIconURLIfEmoji")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.OverrideIconURLIfEmoji")
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ type Server struct {
|
|||||||
|
|
||||||
Cloud einterfaces.CloudInterface
|
Cloud einterfaces.CloudInterface
|
||||||
IPFiltering einterfaces.IPFilteringInterface
|
IPFiltering einterfaces.IPFilteringInterface
|
||||||
|
OutgoingOAuthConnection einterfaces.OutgoingOAuthConnectionInterface
|
||||||
|
|
||||||
tracer *tracing.Tracer
|
tracer *tracing.Tracer
|
||||||
|
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ func GetClientLicense(l *model.License) map[string]string {
|
|||||||
props["Cloud"] = strconv.FormatBool(*l.Features.Cloud)
|
props["Cloud"] = strconv.FormatBool(*l.Features.Cloud)
|
||||||
props["SharedChannels"] = strconv.FormatBool(*l.Features.SharedChannels)
|
props["SharedChannels"] = strconv.FormatBool(*l.Features.SharedChannels)
|
||||||
props["RemoteClusterService"] = strconv.FormatBool(*l.Features.RemoteClusterService)
|
props["RemoteClusterService"] = strconv.FormatBool(*l.Features.RemoteClusterService)
|
||||||
|
props["OutgoingOAuthConnections"] = strconv.FormatBool(*l.Features.OutgoingOAuthConnections)
|
||||||
props["IsTrial"] = strconv.FormatBool(l.IsTrial)
|
props["IsTrial"] = strconv.FormatBool(l.IsTrial)
|
||||||
props["IsGovSku"] = strconv.FormatBool(l.IsGovSku)
|
props["IsGovSku"] = strconv.FormatBool(l.IsGovSku)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -453,6 +453,17 @@ func (c *Context) RequireAppId() *Context {
|
|||||||
return c
|
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 {
|
func (c *Context) RequireFileId() *Context {
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return c
|
return c
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ type Params struct {
|
|||||||
GroupSource model.GroupSource
|
GroupSource model.GroupSource
|
||||||
FilterHasMember string
|
FilterHasMember string
|
||||||
IncludeChannelMemberCount string
|
IncludeChannelMemberCount string
|
||||||
|
OutgoingOAuthConnectionID string
|
||||||
|
|
||||||
// Cloud
|
// Cloud
|
||||||
InvoiceId string
|
InvoiceId string
|
||||||
@@ -145,6 +146,7 @@ func ParamsFromRequest(r *http.Request) *Params {
|
|||||||
params.GroupId = props["group_id"]
|
params.GroupId = props["group_id"]
|
||||||
params.RemoteId = props["remote_id"]
|
params.RemoteId = props["remote_id"]
|
||||||
params.InvoiceId = props["invoice_id"]
|
params.InvoiceId = props["invoice_id"]
|
||||||
|
params.OutgoingOAuthConnectionID = props["outgoing_oauth_connection_id"]
|
||||||
params.Scope = query.Get("scope")
|
params.Scope = query.Get("scope")
|
||||||
|
|
||||||
if val, err := strconv.Atoi(query.Get("page")); err != nil || val < 0 {
|
if val, err := strconv.Atoi(query.Get("page")); err != nil || val < 0 {
|
||||||
|
|||||||
159
server/einterfaces/mocks/OAuthOutgoingConnectionInterface.go
Обычный файл
159
server/einterfaces/mocks/OAuthOutgoingConnectionInterface.go
Обычный файл
@@ -0,0 +1,159 @@
|
|||||||
|
// Code generated by mockery v2.23.2. DO NOT EDIT.
|
||||||
|
|
||||||
|
// Regenerate this file using `make einterfaces-mocks`.
|
||||||
|
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
model "github.com/mattermost/mattermost/server/public/model"
|
||||||
|
request "github.com/mattermost/mattermost/server/public/shared/request"
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuthOutgoingConnectionInterface is an autogenerated mock type for the OAuthOutgoingConnectionInterface type
|
||||||
|
type OAuthOutgoingConnectionInterface struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteConnection provides a mock function with given fields: rctx, id
|
||||||
|
func (_m *OAuthOutgoingConnectionInterface) DeleteConnection(rctx request.CTX, id string) *model.AppError {
|
||||||
|
ret := _m.Called(rctx, id)
|
||||||
|
|
||||||
|
var r0 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.AppError); ok {
|
||||||
|
r0 = rf(rctx, id)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConnection provides a mock function with given fields: rctx, id
|
||||||
|
func (_m *OAuthOutgoingConnectionInterface) GetConnection(rctx request.CTX, id string) (*model.OutgoingOAuthConnectionGrantType, *model.AppError) {
|
||||||
|
ret := _m.Called(rctx, id)
|
||||||
|
|
||||||
|
var r0 *model.OutgoingOAuthConnectionGrantType
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, string) (*model.OutgoingOAuthConnectionGrantType, *model.AppError)); ok {
|
||||||
|
return rf(rctx, id)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.OutgoingOAuthConnectionGrantType); ok {
|
||||||
|
r0 = rf(rctx, id)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.OutgoingOAuthConnectionGrantType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
|
||||||
|
r1 = rf(rctx, id)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConnections provides a mock function with given fields: rctx, filters
|
||||||
|
func (_m *OAuthOutgoingConnectionInterface) GetConnections(rctx request.CTX, filters model.OutgoingOAuthConnectionGetConnectionsFilter) ([]*model.OutgoingOAuthConnectionGrantType, *model.AppError) {
|
||||||
|
ret := _m.Called(rctx, filters)
|
||||||
|
|
||||||
|
var r0 []*model.OutgoingOAuthConnectionGrantType
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, model.OutgoingOAuthConnectionGetConnectionsFilter) ([]*model.OutgoingOAuthConnectionGrantType, *model.AppError)); ok {
|
||||||
|
return rf(rctx, filters)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, model.OutgoingOAuthConnectionGetConnectionsFilter) []*model.OutgoingOAuthConnectionGrantType); ok {
|
||||||
|
r0 = rf(rctx, filters)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.OutgoingOAuthConnectionGrantType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, model.OutgoingOAuthConnectionGetConnectionsFilter) *model.AppError); ok {
|
||||||
|
r1 = rf(rctx, filters)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveConnection provides a mock function with given fields: rctx, conn
|
||||||
|
func (_m *OAuthOutgoingConnectionInterface) SaveConnection(rctx request.CTX, conn *model.OutgoingOAuthConnectionGrantType) (*model.OutgoingOAuthConnectionGrantType, *model.AppError) {
|
||||||
|
ret := _m.Called(rctx, conn)
|
||||||
|
|
||||||
|
var r0 *model.OutgoingOAuthConnectionGrantType
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, *model.OutgoingOAuthConnectionGrantType) (*model.OutgoingOAuthConnectionGrantType, *model.AppError)); ok {
|
||||||
|
return rf(rctx, conn)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, *model.OutgoingOAuthConnectionGrantType) *model.OutgoingOAuthConnectionGrantType); ok {
|
||||||
|
r0 = rf(rctx, conn)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.OutgoingOAuthConnectionGrantType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, *model.OutgoingOAuthConnectionGrantType) *model.AppError); ok {
|
||||||
|
r1 = rf(rctx, conn)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateConnection provides a mock function with given fields: rctx, conn
|
||||||
|
func (_m *OAuthOutgoingConnectionInterface) UpdateConnection(rctx request.CTX, conn *model.OutgoingOAuthConnectionGrantType) (*model.OutgoingOAuthConnectionGrantType, *model.AppError) {
|
||||||
|
ret := _m.Called(rctx, conn)
|
||||||
|
|
||||||
|
var r0 *model.OutgoingOAuthConnectionGrantType
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, *model.OutgoingOAuthConnectionGrantType) (*model.OutgoingOAuthConnectionGrantType, *model.AppError)); ok {
|
||||||
|
return rf(rctx, conn)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, *model.OutgoingOAuthConnectionGrantType) *model.OutgoingOAuthConnectionGrantType); ok {
|
||||||
|
r0 = rf(rctx, conn)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.OutgoingOAuthConnectionGrantType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, *model.OutgoingOAuthConnectionGrantType) *model.AppError); ok {
|
||||||
|
r1 = rf(rctx, conn)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockConstructorTestingTNewOAuthOutgoingConnectionInterface interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOAuthOutgoingConnectionInterface creates a new instance of OAuthOutgoingConnectionInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
|
func NewOAuthOutgoingConnectionInterface(t mockConstructorTestingTNewOAuthOutgoingConnectionInterface) *OAuthOutgoingConnectionInterface {
|
||||||
|
mock := &OAuthOutgoingConnectionInterface{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
||||||
169
server/einterfaces/mocks/OutgoingOAuthConnectionInterface.go
Обычный файл
169
server/einterfaces/mocks/OutgoingOAuthConnectionInterface.go
Обычный файл
@@ -0,0 +1,169 @@
|
|||||||
|
// Code generated by mockery v2.23.2. DO NOT EDIT.
|
||||||
|
|
||||||
|
// Regenerate this file using `make einterfaces-mocks`.
|
||||||
|
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
model "github.com/mattermost/mattermost/server/public/model"
|
||||||
|
request "github.com/mattermost/mattermost/server/public/shared/request"
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OutgoingOAuthConnectionInterface is an autogenerated mock type for the OutgoingOAuthConnectionInterface type
|
||||||
|
type OutgoingOAuthConnectionInterface struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteConnection provides a mock function with given fields: rctx, id
|
||||||
|
func (_m *OutgoingOAuthConnectionInterface) DeleteConnection(rctx request.CTX, id string) *model.AppError {
|
||||||
|
ret := _m.Called(rctx, id)
|
||||||
|
|
||||||
|
var r0 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.AppError); ok {
|
||||||
|
r0 = rf(rctx, id)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConnection provides a mock function with given fields: rctx, id
|
||||||
|
func (_m *OutgoingOAuthConnectionInterface) GetConnection(rctx request.CTX, id string) (*model.OutgoingOAuthConnection, *model.AppError) {
|
||||||
|
ret := _m.Called(rctx, id)
|
||||||
|
|
||||||
|
var r0 *model.OutgoingOAuthConnection
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, string) (*model.OutgoingOAuthConnection, *model.AppError)); ok {
|
||||||
|
return rf(rctx, id)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.OutgoingOAuthConnection); ok {
|
||||||
|
r0 = rf(rctx, id)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.OutgoingOAuthConnection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
|
||||||
|
r1 = rf(rctx, id)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConnections provides a mock function with given fields: rctx, filters
|
||||||
|
func (_m *OutgoingOAuthConnectionInterface) GetConnections(rctx request.CTX, filters model.OutgoingOAuthConnectionGetConnectionsFilter) ([]*model.OutgoingOAuthConnection, *model.AppError) {
|
||||||
|
ret := _m.Called(rctx, filters)
|
||||||
|
|
||||||
|
var r0 []*model.OutgoingOAuthConnection
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, model.OutgoingOAuthConnectionGetConnectionsFilter) ([]*model.OutgoingOAuthConnection, *model.AppError)); ok {
|
||||||
|
return rf(rctx, filters)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, model.OutgoingOAuthConnectionGetConnectionsFilter) []*model.OutgoingOAuthConnection); ok {
|
||||||
|
r0 = rf(rctx, filters)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.OutgoingOAuthConnection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, model.OutgoingOAuthConnectionGetConnectionsFilter) *model.AppError); ok {
|
||||||
|
r1 = rf(rctx, filters)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SanitizeConnection provides a mock function with given fields: conn
|
||||||
|
func (_m *OutgoingOAuthConnectionInterface) SanitizeConnection(conn *model.OutgoingOAuthConnection) {
|
||||||
|
_m.Called(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SanitizeConnections provides a mock function with given fields: conns
|
||||||
|
func (_m *OutgoingOAuthConnectionInterface) SanitizeConnections(conns []*model.OutgoingOAuthConnection) {
|
||||||
|
_m.Called(conns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveConnection provides a mock function with given fields: rctx, conn
|
||||||
|
func (_m *OutgoingOAuthConnectionInterface) SaveConnection(rctx request.CTX, conn *model.OutgoingOAuthConnection) (*model.OutgoingOAuthConnection, *model.AppError) {
|
||||||
|
ret := _m.Called(rctx, conn)
|
||||||
|
|
||||||
|
var r0 *model.OutgoingOAuthConnection
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, *model.OutgoingOAuthConnection) (*model.OutgoingOAuthConnection, *model.AppError)); ok {
|
||||||
|
return rf(rctx, conn)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, *model.OutgoingOAuthConnection) *model.OutgoingOAuthConnection); ok {
|
||||||
|
r0 = rf(rctx, conn)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.OutgoingOAuthConnection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, *model.OutgoingOAuthConnection) *model.AppError); ok {
|
||||||
|
r1 = rf(rctx, conn)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateConnection provides a mock function with given fields: rctx, conn
|
||||||
|
func (_m *OutgoingOAuthConnectionInterface) UpdateConnection(rctx request.CTX, conn *model.OutgoingOAuthConnection) (*model.OutgoingOAuthConnection, *model.AppError) {
|
||||||
|
ret := _m.Called(rctx, conn)
|
||||||
|
|
||||||
|
var r0 *model.OutgoingOAuthConnection
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, *model.OutgoingOAuthConnection) (*model.OutgoingOAuthConnection, *model.AppError)); ok {
|
||||||
|
return rf(rctx, conn)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(request.CTX, *model.OutgoingOAuthConnection) *model.OutgoingOAuthConnection); ok {
|
||||||
|
r0 = rf(rctx, conn)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.OutgoingOAuthConnection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(request.CTX, *model.OutgoingOAuthConnection) *model.AppError); ok {
|
||||||
|
r1 = rf(rctx, conn)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockConstructorTestingTNewOutgoingOAuthConnectionInterface interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOutgoingOAuthConnectionInterface creates a new instance of OutgoingOAuthConnectionInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
|
func NewOutgoingOAuthConnectionInterface(t mockConstructorTestingTNewOutgoingOAuthConnectionInterface) *OutgoingOAuthConnectionInterface {
|
||||||
|
mock := &OutgoingOAuthConnectionInterface{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
||||||
20
server/einterfaces/outgoing_oauth_connection.go
Обычный файл
20
server/einterfaces/outgoing_oauth_connection.go
Обычный файл
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package einterfaces
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
|
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OutgoingOAuthConnectionInterface interface {
|
||||||
|
DeleteConnection(rctx request.CTX, id string) *model.AppError
|
||||||
|
GetConnection(rctx request.CTX, id string) (*model.OutgoingOAuthConnection, *model.AppError)
|
||||||
|
GetConnections(rctx request.CTX, filters model.OutgoingOAuthConnectionGetConnectionsFilter) ([]*model.OutgoingOAuthConnection, *model.AppError)
|
||||||
|
SaveConnection(rctx request.CTX, conn *model.OutgoingOAuthConnection) (*model.OutgoingOAuthConnection, *model.AppError)
|
||||||
|
UpdateConnection(rctx request.CTX, conn *model.OutgoingOAuthConnection) (*model.OutgoingOAuthConnection, *model.AppError)
|
||||||
|
|
||||||
|
SanitizeConnection(conn *model.OutgoingOAuthConnection)
|
||||||
|
SanitizeConnections(conns []*model.OutgoingOAuthConnection)
|
||||||
|
}
|
||||||
@@ -1657,6 +1657,18 @@
|
|||||||
"id": "api.context.mfa_required.app_error",
|
"id": "api.context.mfa_required.app_error",
|
||||||
"translation": "Multi-factor authentication is required on this server."
|
"translation": "Multi-factor authentication is required on this server."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.context.outgoing_oauth_connection.list_connections.app_error",
|
||||||
|
"translation": "There was an error while listing outgoing OAuth connections."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "api.context.outgoing_oauth_connection.list_connections.input_error",
|
||||||
|
"translation": "Invalid input parameters."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "api.context.outgoing_oauth_connection.not_available.feature_flag",
|
||||||
|
"translation": "This feature is restricted by a feature flag."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.context.permissions.app_error",
|
"id": "api.context.permissions.app_error",
|
||||||
"translation": "You do not have the appropriate permissions."
|
"translation": "You do not have the appropriate permissions."
|
||||||
@@ -8158,6 +8170,30 @@
|
|||||||
"id": "ent.migration.migratetosaml.username_already_used_by_other_user",
|
"id": "ent.migration.migratetosaml.username_already_used_by_other_user",
|
||||||
"translation": "Username already used by another Mattermost user."
|
"translation": "Username already used by another Mattermost user."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.outgoing_oauth_connections.delete_connection.app_error",
|
||||||
|
"translation": "There was an error while deleting the outgoing oauth connection."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.outgoing_oauth_connections.get_connection.app_error",
|
||||||
|
"translation": "There was an error retrieving the outgoing oauth connection."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.outgoing_oauth_connections.get_connection.not_found.app_error",
|
||||||
|
"translation": "The outgoing oauth connection was not found."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.outgoing_oauth_connections.get_connections.app_error",
|
||||||
|
"translation": "There was an error retrieving the outgoing oauth connections."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.outgoing_oauth_connections.save_connection.app_error",
|
||||||
|
"translation": "There was an error saving the outgoing oauth connection."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.outgoing_oauth_connections.update_connection.app_error",
|
||||||
|
"translation": "There was an error updating the outgoing oauth connection."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.saml.attribute.app_error",
|
"id": "ent.saml.attribute.app_error",
|
||||||
"translation": "SAML login was unsuccessful because one of the attributes is incorrect. Please contact your System Administrator."
|
"translation": "SAML login was unsuccessful because one of the attributes is incorrect. Please contact your System Administrator."
|
||||||
|
|||||||
@@ -471,6 +471,14 @@ func (c *Client4) oAuthAppRoute(appId string) string {
|
|||||||
return fmt.Sprintf("/oauth/apps/%v", appId)
|
return fmt.Sprintf("/oauth/apps/%v", appId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client4) outgoingOAuthConnectionsRoute() string {
|
||||||
|
return "/oauth/outgoing_connections"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client4) outgoingOAuthConnectionRoute(id string) string {
|
||||||
|
return fmt.Sprintf("/oauth/outgoing_connections/%s", id)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client4) jobsRoute() string {
|
func (c *Client4) jobsRoute() string {
|
||||||
return "/jobs"
|
return "/jobs"
|
||||||
}
|
}
|
||||||
@@ -6003,6 +6011,36 @@ func (c *Client4) GetOAuthAccessToken(ctx context.Context, data url.Values) (*Ac
|
|||||||
return ar, BuildResponse(rp), nil
|
return ar, BuildResponse(rp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OutgoingOAuthConnection section
|
||||||
|
|
||||||
|
// GetOutgoingOAuthConnections retrieves the outgoing OAuth connections.
|
||||||
|
func (c *Client4) GetOutgoingOAuthConnections(ctx context.Context, fromID string, limit int) ([]*OutgoingOAuthConnection, *Response, error) {
|
||||||
|
r, err := c.DoAPIGet(ctx, c.outgoingOAuthConnectionsRoute(), "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), err
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
var connections []*OutgoingOAuthConnection
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&connections); err != nil {
|
||||||
|
return nil, nil, NewAppError("GetOutgoingOAuthConnections", "api.unmarshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
|
}
|
||||||
|
return connections, BuildResponse(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOutgoingOAuthConnection retrieves the outgoing OAuth connection with the given ID.
|
||||||
|
func (c *Client4) GetOutgoingOAuthConnection(ctx context.Context, id string) (*OutgoingOAuthConnection, *Response, error) {
|
||||||
|
r, err := c.DoAPIGet(ctx, c.outgoingOAuthConnectionRoute(id), "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), err
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
var connection *OutgoingOAuthConnection
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&connection); err != nil {
|
||||||
|
return nil, nil, NewAppError("GetOutgoingOAuthConnection", "api.unmarshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
|
}
|
||||||
|
return connection, BuildResponse(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Elasticsearch Section
|
// Elasticsearch Section
|
||||||
|
|
||||||
// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured.
|
// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured.
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ type FeatureFlags struct {
|
|||||||
ConsumePostHook bool
|
ConsumePostHook bool
|
||||||
|
|
||||||
CloudAnnualRenewals bool
|
CloudAnnualRenewals bool
|
||||||
|
|
||||||
|
OutgoingOAuthConnections bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FeatureFlags) SetDefaults() {
|
func (f *FeatureFlags) SetDefaults() {
|
||||||
@@ -69,6 +71,7 @@ func (f *FeatureFlags) SetDefaults() {
|
|||||||
f.CloudIPFiltering = false
|
f.CloudIPFiltering = false
|
||||||
f.ConsumePostHook = false
|
f.ConsumePostHook = false
|
||||||
f.CloudAnnualRenewals = false
|
f.CloudAnnualRenewals = false
|
||||||
|
f.OutgoingOAuthConnections = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToMap returns the feature flags as a map[string]string
|
// ToMap returns the feature flags as a map[string]string
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ type Features struct {
|
|||||||
Cloud *bool `json:"cloud"`
|
Cloud *bool `json:"cloud"`
|
||||||
SharedChannels *bool `json:"shared_channels"`
|
SharedChannels *bool `json:"shared_channels"`
|
||||||
RemoteClusterService *bool `json:"remote_cluster_service"`
|
RemoteClusterService *bool `json:"remote_cluster_service"`
|
||||||
|
OutgoingOAuthConnections *bool `json:"outgoing_oauth_connections"`
|
||||||
|
|
||||||
// after we enabled more features we'll need to control them with this
|
// after we enabled more features we'll need to control them with this
|
||||||
FutureFeatures *bool `json:"future_features"`
|
FutureFeatures *bool `json:"future_features"`
|
||||||
@@ -191,6 +192,7 @@ func (f *Features) ToMap() map[string]any {
|
|||||||
"shared_channels": *f.SharedChannels,
|
"shared_channels": *f.SharedChannels,
|
||||||
"remote_cluster_service": *f.RemoteClusterService,
|
"remote_cluster_service": *f.RemoteClusterService,
|
||||||
"future": *f.FutureFeatures,
|
"future": *f.FutureFeatures,
|
||||||
|
"outgoing_oauth_connections": *f.OutgoingOAuthConnections,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,6 +316,10 @@ func (f *Features) SetDefaults() {
|
|||||||
if f.RemoteClusterService == nil {
|
if f.RemoteClusterService == nil {
|
||||||
f.RemoteClusterService = NewBool(*f.FutureFeatures)
|
f.RemoteClusterService = NewBool(*f.FutureFeatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f.OutgoingOAuthConnections == nil {
|
||||||
|
f.OutgoingOAuthConnections = NewBool(*f.FutureFeatures)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *License) IsExpired() bool {
|
func (l *License) IsExpired() bool {
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ type OutgoingOAuthConnection struct {
|
|||||||
CreateAt int64 `json:"create_at"`
|
CreateAt int64 `json:"create_at"`
|
||||||
UpdateAt int64 `json:"update_at"`
|
UpdateAt int64 `json:"update_at"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ClientId string `json:"client_id"`
|
ClientId string `json:"client_id,omitempty"`
|
||||||
ClientSecret string `json:"client_secret"`
|
ClientSecret string `json:"client_secret,omitempty"`
|
||||||
CredentialsUsername *string `json:"credentials_username,omitempty"`
|
CredentialsUsername *string `json:"credentials_username,omitempty"`
|
||||||
CredentialsPassword *string `json:"credentials_password,omitempty"`
|
CredentialsPassword *string `json:"credentials_password,omitempty"`
|
||||||
OAuthTokenURL string `json:"oauth_token_url"`
|
OAuthTokenURL string `json:"oauth_token_url"`
|
||||||
@@ -47,6 +47,14 @@ func (oa *OutgoingOAuthConnection) Auditable() map[string]interface{} {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanitize removes any sensitive fields from the OutgoingOAuthConnection object.
|
||||||
|
func (oa *OutgoingOAuthConnection) Sanitize() {
|
||||||
|
oa.ClientId = ""
|
||||||
|
oa.ClientSecret = ""
|
||||||
|
oa.CredentialsUsername = nil
|
||||||
|
oa.CredentialsPassword = nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsValid validates the object and returns an error if it isn't properly configured
|
// IsValid validates the object and returns an error if it isn't properly configured
|
||||||
func (oa *OutgoingOAuthConnection) IsValid() *AppError {
|
func (oa *OutgoingOAuthConnection) IsValid() *AppError {
|
||||||
if !IsValidId(oa.Id) {
|
if !IsValidId(oa.Id) {
|
||||||
@@ -65,19 +73,19 @@ func (oa *OutgoingOAuthConnection) IsValid() *AppError {
|
|||||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.creator_id.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.creator_id.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if utf8.RuneCountInString(oa.Name) > 64 {
|
if oa.Name == "" || utf8.RuneCountInString(oa.Name) > 64 {
|
||||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.name.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.name.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(oa.ClientId) == 0 || utf8.RuneCountInString(oa.ClientId) > 255 {
|
if oa.ClientId == "" || utf8.RuneCountInString(oa.ClientId) > 255 {
|
||||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.client_id.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.client_id.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(oa.ClientSecret) == 0 || utf8.RuneCountInString(oa.ClientSecret) > 255 {
|
if oa.ClientSecret == "" || utf8.RuneCountInString(oa.ClientSecret) > 255 {
|
||||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.client_secret.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.client_secret.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(oa.OAuthTokenURL) == 0 || utf8.RuneCountInString(oa.OAuthTokenURL) > 256 {
|
if oa.OAuthTokenURL == "" || utf8.RuneCountInString(oa.OAuthTokenURL) > 256 {
|
||||||
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.oauth_token_url.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
return NewAppError("OutgoingOAuthConnection.IsValid", "model.outgoing_oauth_connection.is_valid.oauth_token_url.error", nil, "id="+oa.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,13 +145,6 @@ func (oa *OutgoingOAuthConnection) Etag() string {
|
|||||||
return Etag(oa.Id, oa.UpdateAt)
|
return Etag(oa.Id, oa.UpdateAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize removes any sensitive fields from the OutgoingOAuthConnection object.
|
|
||||||
func (oa *OutgoingOAuthConnection) Sanitize() {
|
|
||||||
oa.ClientSecret = ""
|
|
||||||
oa.CredentialsUsername = nil
|
|
||||||
oa.CredentialsPassword = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OutgoingOAuthConnectionGetConnectionsFilter is used to filter outgoing connections
|
// OutgoingOAuthConnectionGetConnectionsFilter is used to filter outgoing connections
|
||||||
type OutgoingOAuthConnectionGetConnectionsFilter struct {
|
type OutgoingOAuthConnectionGetConnectionsFilter struct {
|
||||||
OffsetId string
|
OffsetId string
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func newValidOutgoingOAuthConnection() *OutgoingOAuthConnection {
|
|||||||
ClientId: NewId(),
|
ClientId: NewId(),
|
||||||
ClientSecret: NewId(),
|
ClientSecret: NewId(),
|
||||||
OAuthTokenURL: "https://nowhere.com/oauth/token",
|
OAuthTokenURL: "https://nowhere.com/oauth/token",
|
||||||
GrantType: "client_credentials",
|
GrantType: OutgoingOAuthConnectionGrantTypeClientCredentials,
|
||||||
CreateAt: GetMillis(),
|
CreateAt: GetMillis(),
|
||||||
UpdateAt: GetMillis(),
|
UpdateAt: GetMillis(),
|
||||||
Audiences: []string{"https://nowhere.com"},
|
Audiences: []string{"https://nowhere.com"},
|
||||||
@@ -52,6 +52,17 @@ func TestOutgoingOAuthConnectionIsValid(t *testing.T) {
|
|||||||
require.Error(t, oa.IsValid())
|
require.Error(t, oa.IsValid())
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "empty name",
|
||||||
|
item: func() *OutgoingOAuthConnection {
|
||||||
|
oa := newValidOutgoingOAuthConnection()
|
||||||
|
oa.Name = ""
|
||||||
|
return oa
|
||||||
|
},
|
||||||
|
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
|
||||||
|
require.Error(t, oa.IsValid())
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "invalid create_at",
|
name: "invalid create_at",
|
||||||
item: func() *OutgoingOAuthConnection {
|
item: func() *OutgoingOAuthConnection {
|
||||||
@@ -307,6 +318,7 @@ func TestOutgoingOAuthConnectionSanitize(t *testing.T) {
|
|||||||
oa := newValidOutgoingOAuthConnection()
|
oa := newValidOutgoingOAuthConnection()
|
||||||
oa.Sanitize()
|
oa.Sanitize()
|
||||||
|
|
||||||
|
require.Empty(t, oa.ClientId)
|
||||||
require.Empty(t, oa.ClientSecret)
|
require.Empty(t, oa.ClientSecret)
|
||||||
require.Empty(t, oa.CredentialsUsername)
|
require.Empty(t, oa.CredentialsUsername)
|
||||||
require.Empty(t, oa.CredentialsPassword)
|
require.Empty(t, oa.CredentialsPassword)
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user