Webapp - Outgoing OAuth Connections (#25507)
* 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 * copied over installed_oauth_apps component and renamed things to installed_outgoing_oauth_connections * merge migrations * renamed migrations * model change suggestions * refactor test functionsn * migration typo * refactor store table names * updated sanitize test * cleanup merge * refactor symbol * "installed outgoing oauth connections" page works * move things into a nested folder * add and edit page stubs work * 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 * changes to support selecting command request url * 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 * management permission * moved permission initalization to proper place * endpoints * put tests * error check typo * fixed specific enttity urls * tests * read permission check * updated openapi definitions * i18n * GetConnectionByAudience method * notes * replaced GetConnectionsByAudience with a filter * added custom oauth token object * updated interface and usage * properly set enterprise interface * move retrieval logic to impl * webhook tests * translations * i18n: updates * address comments * endpoint and tests * i18n * api docs * fixed endpoint path * sq.like * use filter object instead of parameters * set url values if not empty * typos * converted some components to function components, and move around files * correctly check token url * restore flag to previous value * added command oauth handler * update enterprise imports * migrate last component to function component * Added enterprise import * refactor permissions and add necessary webapp code * Check correct flag in permission tree * allow partial updates * sort i18n webapp * missing test modification * fixed webapp i18n sorting * allow validating stored connections * added missing translation * fix finished adding connection link and text on result page * added missing permission to smoke tests * missing role in smoke test * updated translations * updated translations * support editing client secret on existing connection * fix some i18n strings * updated translations * better error messages * progress on using react select for command request url while maintaining typed in value * remove writeheader, test * HasValidGrantType * end early to avoid nil pointer errors * move slash command request url input box into its own component * wrap components related to oauth connections in config check * fix tests * i18n-extract * change some i18n strings to say "Outgoing OAuth 2.0 Connections" * remove debug code * fixed i18n * updated i18n file * feature configuration backend * typo * add system console setting * Revert "typo" This reverts commit 669da23e8ee47525ccaa6f59cbbd20bf8a121191. * Revert "updated i18n file" This reverts commit d0882c0dd7587533f0d0f7a7b7b190684186158a. * Revert "fixed i18n" This reverts commit 3108866bc19139182dfd094921c56cdefc4695ea. * fixed i18n * updated i18n file * typo * updated i18n * updated i18n * updated i18n * updated version to 9.6 * replace feature flag with system console configuration * i18n * updated tests * pr feedback * fix styling of disabled text box * fix styling of action links in integration console * server changes for validation feature * webapp changes for validation feature * pencil icon styling * styling fixes for oauth audience correct configuration message * fix sanitize test * remove max lengths from outgoing oauth connection form * use config var in webapp instead of feature flag * change asterisks to bullets * update api docs for validate endpoint * feedback from ux review * fix lint, types, tests * fix stylelint * implement validation button under the token url input * support wildcard for matching audience urls * updates for styling * update snapshots * add doc links for the outgoing oauth connections feature * change doc links to use permalink * add docs link to system console * fix: use limitedreader in json decoding * fix: form error in validation * management permission can read now * updated api documentation * doc typo * require one permission to read only * fix api connection list audience filter * fix audience matching and add loading indicator * fix team permissions on outgoing oauth connection api calls * fix api doc and test, for adding team id to query params * handle read permissions by adding a team in the payload * missing teamid query parameter in test * change validate button logic to not require audience urls to be filled out * fix redux type --------- Co-authored-by: Felipe Martin <me@fmartingr.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
3f6c94cfc3
Коммит
4e071e861c
@@ -277,7 +277,7 @@ 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.BaseRoutes.OutgoingOAuthConnection = api.BaseRoutes.OutgoingOAuthConnections.PathPrefix("/{outgoing_oauth_connection_id:[A-Za-z0-9]+}").Subrouter()
|
||||
|
||||
api.InitUser()
|
||||
api.InitBot()
|
||||
|
||||
@@ -6,11 +6,14 @@ package api4
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/mattermost/logr/v2"
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/audit"
|
||||
"github.com/mattermost/mattermost/server/v8/einterfaces"
|
||||
)
|
||||
|
||||
@@ -20,12 +23,44 @@ const (
|
||||
|
||||
func (api *API) InitOutgoingOAuthConnection() {
|
||||
api.BaseRoutes.OutgoingOAuthConnections.Handle("", api.APISessionRequired(listOutgoingOAuthConnections)).Methods("GET")
|
||||
api.BaseRoutes.OutgoingOAuthConnections.Handle("", api.APISessionRequired(createOutgoingOAuthConnection)).Methods("POST")
|
||||
api.BaseRoutes.OutgoingOAuthConnection.Handle("", api.APISessionRequired(getOutgoingOAuthConnection)).Methods("GET")
|
||||
api.BaseRoutes.OutgoingOAuthConnection.Handle("", api.APISessionRequired(updateOutgoingOAuthConnection)).Methods("PUT")
|
||||
api.BaseRoutes.OutgoingOAuthConnection.Handle("", api.APISessionRequired(deleteOutgoingOAuthConnection)).Methods("DELETE")
|
||||
api.BaseRoutes.OutgoingOAuthConnections.Handle("/validate", api.APISessionRequired(validateOutgoingOAuthConnectionCredentials)).Methods("POST")
|
||||
}
|
||||
|
||||
// checkOutgoingOAuthConnectionReadPermissions checks if the user has the permissions to read outgoing oauth connections.
|
||||
// An user with the permissions to manage outgoing oauth connections can read outgoing oauth connections.
|
||||
// Otherwise the user needs to have the permissions to manage outgoing webhooks or slash commands in order to read outgoing
|
||||
// oauth connections so that they can use them.
|
||||
// This is made in this way so only users with the management permission can setup the outgoing oauth connections and then
|
||||
// other users can use them in their outgoing webhooks and slash commands if they have permissions to manage those.
|
||||
func checkOutgoingOAuthConnectionReadPermissions(c *Context, teamId string) bool {
|
||||
if c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageOutgoingOAuthConnections) ||
|
||||
c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), teamId, model.PermissionManageOutgoingWebhooks) ||
|
||||
c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), teamId, model.PermissionManageSlashCommands) {
|
||||
return true
|
||||
}
|
||||
|
||||
c.SetPermissionError(model.PermissionManageOutgoingWebhooks, model.PermissionManageSlashCommands)
|
||||
return false
|
||||
}
|
||||
|
||||
// checkOutgoingOAuthConnectionWritePermissions checks if the user has the permissions to write outgoing oauth connections.
|
||||
// This is a more granular permissions intended for system admins to manage (setup) outgoing oauth connections.
|
||||
func checkOutgoingOAuthConnectionWritePermissions(c *Context) bool {
|
||||
if c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageOutgoingOAuthConnections) {
|
||||
return true
|
||||
}
|
||||
|
||||
c.SetPermissionError(model.PermissionManageOutgoingOAuthConnections)
|
||||
return false
|
||||
}
|
||||
|
||||
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)
|
||||
if c.App.Config().ServiceSettings.EnableOutgoingOAuthConnections != nil && !*c.App.Config().ServiceSettings.EnableOutgoingOAuthConnections {
|
||||
c.Err = model.NewAppError(where, "api.context.outgoing_oauth_connection.not_available.configuration_disabled", nil, "", http.StatusNotImplemented)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -37,8 +72,9 @@ func ensureOutgoingOAuthConnectionInterface(c *Context, where string) (einterfac
|
||||
}
|
||||
|
||||
type listOutgoingOAuthConnectionsQuery struct {
|
||||
FromID string
|
||||
Limit int
|
||||
FromID string
|
||||
Limit int
|
||||
Audience string
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values for the query.
|
||||
@@ -62,6 +98,7 @@ func (q *listOutgoingOAuthConnectionsQuery) ToFilter() model.OutgoingOAuthConnec
|
||||
return model.OutgoingOAuthConnectionGetConnectionsFilter{
|
||||
OffsetId: q.FromID,
|
||||
Limit: q.Limit,
|
||||
Audience: q.Audience,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,16 +114,26 @@ func NewListOutgoingOAuthConnectionsQueryFromURLQuery(values url.Values) (*listO
|
||||
limit := values.Get("limit")
|
||||
if limit != "" {
|
||||
limitInt, err := strconv.Atoi(limit)
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query.Limit = limitInt
|
||||
}
|
||||
|
||||
audience := values.Get("audience")
|
||||
if audience != "" {
|
||||
query.Audience = audience
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
func listOutgoingOAuthConnections(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
teamId := r.URL.Query().Get("team_id")
|
||||
if !checkOutgoingOAuthConnectionReadPermissions(c, teamId) {
|
||||
return
|
||||
}
|
||||
|
||||
service, ok := ensureOutgoingOAuthConnectionInterface(c, whereOutgoingOAuthConnection)
|
||||
if !ok {
|
||||
return
|
||||
@@ -103,10 +150,25 @@ func listOutgoingOAuthConnections(c *Context, w http.ResponseWriter, r *http.Req
|
||||
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
|
||||
var connections []*model.OutgoingOAuthConnection
|
||||
if query.Audience != "" {
|
||||
// If the consumer expects an audience match, use the `GetConnectionByAudience` method to
|
||||
// retrieve a single connection.
|
||||
connection, err := service.GetConnectionForAudience(c.AppContext, query.Audience)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.list_connections.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
connections = append(connections, connection)
|
||||
} else {
|
||||
// If the consumer does not expect an audience match, use the `GetConnections` method to
|
||||
// retrieve a list of connections that potentially matches the provided audience.
|
||||
var errList *model.AppError
|
||||
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)
|
||||
@@ -118,6 +180,10 @@ func listOutgoingOAuthConnections(c *Context, w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
func getOutgoingOAuthConnection(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if !checkOutgoingOAuthConnectionWritePermissions(c) {
|
||||
return
|
||||
}
|
||||
|
||||
service, ok := ensureOutgoingOAuthConnectionInterface(c, whereOutgoingOAuthConnection)
|
||||
if !ok {
|
||||
return
|
||||
@@ -138,3 +204,216 @@ func getOutgoingOAuthConnection(c *Context, w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func createOutgoingOAuthConnection(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
auditRec := c.MakeAuditRecord("createOutgoingOauthConnection", audit.Fail)
|
||||
defer c.LogAuditRec(auditRec)
|
||||
c.LogAudit("attempt")
|
||||
|
||||
if !checkOutgoingOAuthConnectionWritePermissions(c) {
|
||||
return
|
||||
}
|
||||
|
||||
service, ok := ensureOutgoingOAuthConnectionInterface(c, whereOutgoingOAuthConnection)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var inputConnection model.OutgoingOAuthConnection
|
||||
bodyReader := io.LimitReader(r.Body, *c.App.Config().ServiceSettings.MaximumPayloadSizeBytes)
|
||||
if err := json.NewDecoder(bodyReader).Decode(&inputConnection); err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.create_connection.input_error", nil, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
audit.AddEventParameterAuditable(auditRec, "outgoing_oauth_connection", &inputConnection)
|
||||
|
||||
inputConnection.CreatorId = c.AppContext.Session().UserId
|
||||
|
||||
connection, err := service.SaveConnection(c.AppContext, &inputConnection)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.create_connection.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
auditRec.Success()
|
||||
auditRec.AddEventResultState(connection)
|
||||
auditRec.AddEventObjectType("outgoing_oauth_connection")
|
||||
c.LogAudit("client_id=" + connection.ClientId)
|
||||
|
||||
service.SanitizeConnection(connection)
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
if err := json.NewEncoder(w).Encode(connection); err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.create_connection.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func updateOutgoingOAuthConnection(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
auditRec := c.MakeAuditRecord("updateOutgoingOAuthConnection", audit.Fail)
|
||||
defer c.LogAuditRec(auditRec)
|
||||
audit.AddEventParameter(auditRec, "outgoing_oauth_connection_id", c.Params.OutgoingOAuthConnectionID)
|
||||
c.LogAudit("attempt")
|
||||
|
||||
if !checkOutgoingOAuthConnectionWritePermissions(c) {
|
||||
return
|
||||
}
|
||||
|
||||
service, ok := ensureOutgoingOAuthConnectionInterface(c, whereOutgoingOAuthConnection)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
c.RequireOutgoingOAuthConnectionId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var inputConnection model.OutgoingOAuthConnection
|
||||
bodyReader := io.LimitReader(r.Body, *c.App.Config().ServiceSettings.MaximumPayloadSizeBytes)
|
||||
if err := json.NewDecoder(bodyReader).Decode(&inputConnection); err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.update_connection.input_error", nil, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if inputConnection.Id != c.Params.OutgoingOAuthConnectionID {
|
||||
c.SetInvalidParam("id")
|
||||
return
|
||||
}
|
||||
|
||||
currentConnection, err := service.GetConnection(c.AppContext, c.Params.OutgoingOAuthConnectionID)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.update_connection.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
auditRec.AddEventPriorState(currentConnection)
|
||||
|
||||
currentConnection.Patch(&inputConnection)
|
||||
|
||||
connection, err := service.UpdateConnection(c.AppContext, currentConnection)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.update_connection.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
auditRec.AddEventObjectType("outgoing_oauth_connection")
|
||||
auditRec.AddEventResultState(connection)
|
||||
auditRec.Success()
|
||||
auditLogExtraInfo := "success"
|
||||
// Audit log changes to clientID/Client Secret
|
||||
if connection.ClientId != currentConnection.ClientId {
|
||||
auditLogExtraInfo += " new_client_id=" + connection.ClientId
|
||||
}
|
||||
if connection.ClientSecret != currentConnection.ClientSecret {
|
||||
auditLogExtraInfo += " new_client_secret"
|
||||
}
|
||||
c.LogAudit(auditLogExtraInfo)
|
||||
service.SanitizeConnection(connection)
|
||||
|
||||
if err := json.NewEncoder(w).Encode(connection); err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.update_connection.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func deleteOutgoingOAuthConnection(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
auditRec := c.MakeAuditRecord("deleteOutgoingOAuthConnection", audit.Fail)
|
||||
defer c.LogAuditRec(auditRec)
|
||||
audit.AddEventParameter(auditRec, "outgoing_oauth_connection_id", c.Params.OutgoingOAuthConnectionID)
|
||||
c.LogAudit("attempt")
|
||||
|
||||
if !checkOutgoingOAuthConnectionWritePermissions(c) {
|
||||
return
|
||||
}
|
||||
|
||||
service, ok := ensureOutgoingOAuthConnectionInterface(c, whereOutgoingOAuthConnection)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
c.RequireOutgoingOAuthConnectionId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
connection, err := service.GetConnection(c.AppContext, c.Params.OutgoingOAuthConnectionID)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.delete_connection.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
auditRec.AddEventPriorState(connection)
|
||||
|
||||
if err := service.DeleteConnection(c.AppContext, c.Params.OutgoingOAuthConnectionID); err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.delete_connection.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
auditRec.AddEventObjectType("outgoing_oauth_connection")
|
||||
auditRec.Success()
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
// validateOutgoingOAuthConnectionCredentials validates the credentials of an outgoing oauth connection by requesting a token
|
||||
// with the provided connection configuration. If the credentials are valid, the request will return a 200 status code and
|
||||
// if the credentials are invalid, the request will return a 400 status code.
|
||||
func validateOutgoingOAuthConnectionCredentials(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
auditRec := c.MakeAuditRecord("validateOutgoingOAuthConnectionCredentials", audit.Fail)
|
||||
defer c.LogAuditRec(auditRec)
|
||||
c.LogAudit("attempt")
|
||||
|
||||
if !checkOutgoingOAuthConnectionWritePermissions(c) {
|
||||
return
|
||||
}
|
||||
|
||||
service, ok := ensureOutgoingOAuthConnectionInterface(c, whereOutgoingOAuthConnection)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Allow checking connections sent in the body or by id if coming from an already existing
|
||||
// connection url.
|
||||
var inputConnection *model.OutgoingOAuthConnection
|
||||
|
||||
bodyReader := io.LimitReader(r.Body, *c.App.Config().ServiceSettings.MaximumPayloadSizeBytes)
|
||||
if err := json.NewDecoder(bodyReader).Decode(&inputConnection); err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.validate_connection_credentials.input_error", nil, err.Error(), http.StatusBadRequest)
|
||||
w.WriteHeader(c.Err.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
if inputConnection.Id != "" && inputConnection.ClientSecret == "" {
|
||||
var err *model.AppError
|
||||
var storedConnection *model.OutgoingOAuthConnection
|
||||
storedConnection, err = service.GetConnection(c.AppContext, inputConnection.Id)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.validate_connection_credentials.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
w.WriteHeader(c.Err.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
inputConnection.ClientSecret = storedConnection.ClientSecret
|
||||
}
|
||||
|
||||
audit.AddEventParameterAuditable(auditRec, "outgoing_oauth_connection", inputConnection)
|
||||
|
||||
resultStatusCode := http.StatusOK
|
||||
|
||||
// Try to retrieve a token with the provided credentials
|
||||
// do not store the token, just check if the credentials are valid and the request can be made
|
||||
_, err := service.RetrieveTokenForConnection(c.AppContext, inputConnection)
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.validate_connection_credentials.app_error", nil, err.Error(), err.StatusCode)
|
||||
c.Logger.Error("Failed to retrieve token while validating outgoing oauth connection", logr.Err(err))
|
||||
resultStatusCode = err.StatusCode
|
||||
} else {
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
auditRec.Success()
|
||||
auditRec.AddEventResultState(inputConnection)
|
||||
auditRec.AddEventObjectType("outgoing_oauth_connection")
|
||||
|
||||
w.WriteHeader(resultStatusCode)
|
||||
}
|
||||
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Ссылка в новой задаче
Block a user