Merge branch 'master' into post-metadata
Этот коммит содержится в:
@@ -231,6 +231,7 @@ func Init(a *app.App, root *mux.Router) *API {
|
||||
api.InitScheme()
|
||||
api.InitImage()
|
||||
api.InitTermsOfService()
|
||||
api.InitAction()
|
||||
|
||||
root.Handle("/api/v4/{anything:.*}", http.HandlerFunc(api.Handle404))
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
@@ -508,7 +509,9 @@ func TestExecuteGetCommand(t *testing.T) {
|
||||
|
||||
commandResponse, resp := Client.ExecuteCommand(channel.Id, "/getcommand")
|
||||
CheckNoError(t, resp)
|
||||
assert.True(t, len(commandResponse.TriggerId) == 26)
|
||||
|
||||
expectedCommandResponse.TriggerId = commandResponse.TriggerId
|
||||
expectedCommandResponse.Props["from_webhook"] = "true"
|
||||
require.Equal(t, expectedCommandResponse, commandResponse)
|
||||
}
|
||||
@@ -566,7 +569,9 @@ func TestExecutePostCommand(t *testing.T) {
|
||||
|
||||
commandResponse, resp := Client.ExecuteCommand(channel.Id, "/postcommand")
|
||||
CheckNoError(t, resp)
|
||||
assert.True(t, len(commandResponse.TriggerId) == 26)
|
||||
|
||||
expectedCommandResponse.TriggerId = commandResponse.TriggerId
|
||||
expectedCommandResponse.Props["from_webhook"] = "true"
|
||||
require.Equal(t, expectedCommandResponse, commandResponse)
|
||||
|
||||
|
||||
105
api4/integration_action.go
Обычный файл
105
api4/integration_action.go
Обычный файл
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package api4
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
)
|
||||
|
||||
func (api *API) InitAction() {
|
||||
api.BaseRoutes.Post.Handle("/actions/{action_id:[A-Za-z0-9]+}", api.ApiSessionRequired(doPostAction)).Methods("POST")
|
||||
|
||||
api.BaseRoutes.ApiRoot.Handle("/actions/dialogs/open", api.ApiHandler(openDialog)).Methods("POST")
|
||||
api.BaseRoutes.ApiRoot.Handle("/actions/dialogs/submit", api.ApiSessionRequired(submitDialog)).Methods("POST")
|
||||
}
|
||||
|
||||
func doPostAction(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.RequirePostId().RequireActionId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_READ_CHANNEL) {
|
||||
c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
|
||||
return
|
||||
}
|
||||
|
||||
actionRequest := model.DoPostActionRequestFromJson(r.Body)
|
||||
if actionRequest == nil {
|
||||
actionRequest = &model.DoPostActionRequest{}
|
||||
}
|
||||
|
||||
var err *model.AppError
|
||||
resp := &model.PostActionAPIResponse{Status: "OK"}
|
||||
|
||||
if resp.TriggerId, err = c.App.DoPostAction(c.Params.PostId, c.Params.ActionId, c.Session.UserId, actionRequest.SelectedOption); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(resp)
|
||||
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
func openDialog(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
var dialog model.OpenDialogRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&dialog)
|
||||
if err != nil {
|
||||
c.SetInvalidParam("dialog")
|
||||
return
|
||||
}
|
||||
|
||||
if dialog.URL == "" {
|
||||
c.SetInvalidParam("url")
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.App.OpenInteractiveDialog(dialog); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
func submitDialog(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
var submit model.SubmitDialogRequest
|
||||
|
||||
jsonErr := json.NewDecoder(r.Body).Decode(&submit)
|
||||
if jsonErr != nil {
|
||||
c.SetInvalidParam("dialog")
|
||||
return
|
||||
}
|
||||
|
||||
if submit.URL == "" {
|
||||
c.SetInvalidParam("url")
|
||||
return
|
||||
}
|
||||
|
||||
submit.UserId = c.Session.UserId
|
||||
|
||||
if !c.App.SessionHasPermissionToChannel(c.Session, submit.ChannelId, model.PERMISSION_READ_CHANNEL) {
|
||||
c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToTeam(c.Session, submit.TeamId, model.PERMISSION_VIEW_TEAM) {
|
||||
c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := c.App.SubmitInteractiveDialog(submit)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(resp)
|
||||
|
||||
w.Write(b)
|
||||
}
|
||||
148
api4/integration_action_test.go
Обычный файл
148
api4/integration_action_test.go
Обычный файл
@@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package api4
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestOpenDialog(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
Client := th.Client
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
|
||||
})
|
||||
|
||||
WebSocketClient, err := th.CreateWebSocketClient()
|
||||
require.Nil(t, err)
|
||||
|
||||
WebSocketClient.Listen()
|
||||
|
||||
_, triggerId, err := model.GenerateTriggerId(th.BasicUser.Id, th.App.AsymmetricSigningKey())
|
||||
require.Nil(t, err)
|
||||
|
||||
request := model.OpenDialogRequest{
|
||||
TriggerId: triggerId,
|
||||
URL: "http://localhost:8065",
|
||||
Dialog: model.Dialog{
|
||||
CallbackId: "callbackid",
|
||||
Title: "Some Title",
|
||||
Elements: []model.DialogElement{
|
||||
model.DialogElement{
|
||||
DisplayName: "Element Name",
|
||||
Name: "element_name",
|
||||
Type: "text",
|
||||
Placeholder: "Enter a value",
|
||||
},
|
||||
},
|
||||
SubmitLabel: "Submit",
|
||||
NotifyOnCancel: false,
|
||||
State: "somestate",
|
||||
},
|
||||
}
|
||||
|
||||
pass, resp := Client.OpenInteractiveDialog(request)
|
||||
CheckNoError(t, resp)
|
||||
assert.True(t, pass)
|
||||
|
||||
timeout := time.After(300 * time.Millisecond)
|
||||
waiting := true
|
||||
for waiting {
|
||||
select {
|
||||
case event := <-WebSocketClient.EventChannel:
|
||||
if event.Event == model.WEBSOCKET_EVENT_OPEN_DIALOG {
|
||||
waiting = false
|
||||
}
|
||||
|
||||
case <-timeout:
|
||||
waiting = false
|
||||
t.Fatal("should have received open_dialog event")
|
||||
}
|
||||
}
|
||||
|
||||
// Should fail on bad trigger ID
|
||||
request.TriggerId = "junk"
|
||||
pass, resp = Client.OpenInteractiveDialog(request)
|
||||
CheckBadRequestStatus(t, resp)
|
||||
assert.False(t, pass)
|
||||
|
||||
// URL is required
|
||||
request.TriggerId = triggerId
|
||||
request.URL = ""
|
||||
pass, resp = Client.OpenInteractiveDialog(request)
|
||||
CheckBadRequestStatus(t, resp)
|
||||
assert.False(t, pass)
|
||||
}
|
||||
|
||||
func TestSubmitDialog(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
Client := th.Client
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
|
||||
})
|
||||
|
||||
submit := model.SubmitDialogRequest{
|
||||
CallbackId: "callbackid",
|
||||
State: "somestate",
|
||||
UserId: th.BasicUser.Id,
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
TeamId: th.BasicTeam.Id,
|
||||
Submission: map[string]interface{}{"somename": "somevalue"},
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var request model.SubmitDialogRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&request)
|
||||
require.Nil(t, err)
|
||||
assert.NotNil(t, request)
|
||||
|
||||
assert.Equal(t, request.URL, "")
|
||||
assert.Equal(t, request.UserId, submit.UserId)
|
||||
assert.Equal(t, request.ChannelId, submit.ChannelId)
|
||||
assert.Equal(t, request.TeamId, submit.TeamId)
|
||||
assert.Equal(t, request.CallbackId, submit.CallbackId)
|
||||
assert.Equal(t, request.State, submit.State)
|
||||
val, ok := request.Submission["somename"].(string)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "somevalue", val)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
submit.URL = ts.URL
|
||||
|
||||
submitResp, resp := Client.SubmitInteractiveDialog(submit)
|
||||
CheckNoError(t, resp)
|
||||
assert.NotNil(t, submitResp)
|
||||
|
||||
submit.URL = ""
|
||||
submitResp, resp = Client.SubmitInteractiveDialog(submit)
|
||||
CheckBadRequestStatus(t, resp)
|
||||
assert.Nil(t, submitResp)
|
||||
|
||||
submit.URL = ts.URL
|
||||
submit.ChannelId = model.NewId()
|
||||
submitResp, resp = Client.SubmitInteractiveDialog(submit)
|
||||
CheckForbiddenStatus(t, resp)
|
||||
assert.Nil(t, submitResp)
|
||||
|
||||
submit.URL = ts.URL
|
||||
submit.ChannelId = th.BasicChannel.Id
|
||||
submit.TeamId = model.NewId()
|
||||
submitResp, resp = Client.SubmitInteractiveDialog(submit)
|
||||
CheckForbiddenStatus(t, resp)
|
||||
assert.Nil(t, submitResp)
|
||||
}
|
||||
25
api4/post.go
25
api4/post.go
@@ -25,7 +25,6 @@ func (api *API) InitPost() {
|
||||
api.BaseRoutes.Team.Handle("/posts/search", api.ApiSessionRequired(searchPosts)).Methods("POST")
|
||||
api.BaseRoutes.Post.Handle("", api.ApiSessionRequired(updatePost)).Methods("PUT")
|
||||
api.BaseRoutes.Post.Handle("/patch", api.ApiSessionRequired(patchPost)).Methods("PUT")
|
||||
api.BaseRoutes.Post.Handle("/actions/{action_id:[A-Za-z0-9]+}", api.ApiSessionRequired(doPostAction)).Methods("POST")
|
||||
api.BaseRoutes.Post.Handle("/pin", api.ApiSessionRequired(pinPost)).Methods("POST")
|
||||
api.BaseRoutes.Post.Handle("/unpin", api.ApiSessionRequired(unpinPost)).Methods("POST")
|
||||
}
|
||||
@@ -541,27 +540,3 @@ func getFileInfosForPost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(model.HEADER_ETAG_SERVER, model.GetEtagForFileInfos(infos))
|
||||
w.Write([]byte(model.FileInfosToJson(infos)))
|
||||
}
|
||||
|
||||
func doPostAction(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.RequirePostId().RequireActionId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_READ_CHANNEL) {
|
||||
c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
|
||||
return
|
||||
}
|
||||
|
||||
actionRequest := model.DoPostActionRequestFromJson(r.Body)
|
||||
if actionRequest == nil {
|
||||
actionRequest = &model.DoPostActionRequest{}
|
||||
}
|
||||
|
||||
if err := c.App.DoPostAction(c.Params.PostId, c.Params.ActionId, c.Session.UserId, actionRequest.SelectedOption); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user