Support for interactive menus in message attachments (#9285)
Этот коммит содержится в:
коммит произвёл
George Goldberg
родитель
9599f1a52f
Коммит
4de2e5206e
@@ -513,7 +513,12 @@ func doPostAction(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.App.DoPostAction(c.Params.PostId, c.Params.ActionId, c.Session.UserId); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -852,7 +852,7 @@ func makeOpenGraphURLsAbsolute(og *opengraph.OpenGraph, requestURL string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) DoPostAction(postId string, actionId string, userId string) *model.AppError {
|
||||
func (a *App) DoPostAction(postId, actionId, userId, selectedOption string) *model.AppError {
|
||||
pchan := a.Srv.Store.Post().GetSingle(postId)
|
||||
|
||||
var post *model.Post
|
||||
@@ -870,9 +870,15 @@ func (a *App) DoPostAction(postId string, actionId string, userId string) *model
|
||||
request := &model.PostActionIntegrationRequest{
|
||||
UserId: userId,
|
||||
PostId: postId,
|
||||
Type: action.Type,
|
||||
Context: action.Integration.Context,
|
||||
}
|
||||
|
||||
if action.Type == model.POST_ACTION_TYPE_SELECT {
|
||||
request.DataSource = action.DataSource
|
||||
request.Context["selected_option"] = selectedOption
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("POST", action.Integration.URL, strings.NewReader(request.ToJson()))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
@@ -134,6 +134,12 @@ func TestPostAction(t *testing.T) {
|
||||
err := json.NewDecoder(r.Body).Decode(&request)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, request.UserId, th.BasicUser.Id)
|
||||
if request.Type == model.POST_ACTION_TYPE_SELECT {
|
||||
assert.Equal(t, request.DataSource, "some_source")
|
||||
assert.Equal(t, request.Context["selected_option"], "selected")
|
||||
} else {
|
||||
assert.Equal(t, request.DataSource, "")
|
||||
}
|
||||
assert.Equal(t, "foo", request.Context["s"])
|
||||
assert.EqualValues(t, 3, request.Context["n"])
|
||||
fmt.Fprintf(w, `{"update": {"message": "updated"}, "ephemeral_text": "foo"}`)
|
||||
@@ -158,7 +164,9 @@ func TestPostAction(t *testing.T) {
|
||||
},
|
||||
URL: ts.URL,
|
||||
},
|
||||
Name: "action",
|
||||
Name: "action",
|
||||
Type: "some_type",
|
||||
DataSource: "some_source",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -175,11 +183,51 @@ func TestPostAction(t *testing.T) {
|
||||
require.NotEmpty(t, attachments[0].Actions)
|
||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||
|
||||
err = th.App.DoPostAction(post.Id, "notavalidid", th.BasicUser.Id)
|
||||
menuPost := model.Post{
|
||||
Message: "Interactive post",
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
|
||||
UserId: th.BasicUser.Id,
|
||||
Props: model.StringInterface{
|
||||
"attachments": []*model.SlackAttachment{
|
||||
{
|
||||
Text: "hello",
|
||||
Actions: []*model.PostAction{
|
||||
{
|
||||
Integration: &model.PostActionIntegration{
|
||||
Context: model.StringInterface{
|
||||
"s": "foo",
|
||||
"n": 3,
|
||||
},
|
||||
URL: ts.URL,
|
||||
},
|
||||
Name: "action",
|
||||
Type: model.POST_ACTION_TYPE_SELECT,
|
||||
DataSource: "some_source",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
post2, err := th.App.CreatePostAsUser(&menuPost)
|
||||
require.Nil(t, err)
|
||||
|
||||
attachments2, ok := post2.Props["attachments"].([]*model.SlackAttachment)
|
||||
require.True(t, ok)
|
||||
|
||||
require.NotEmpty(t, attachments2[0].Actions)
|
||||
require.NotEmpty(t, attachments2[0].Actions[0].Id)
|
||||
|
||||
err = th.App.DoPostAction(post.Id, "notavalidid", th.BasicUser.Id, "")
|
||||
require.NotNil(t, err)
|
||||
assert.Equal(t, http.StatusNotFound, err.StatusCode)
|
||||
|
||||
err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id)
|
||||
err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
|
||||
require.Nil(t, err)
|
||||
|
||||
err = th.App.DoPostAction(post2.Id, attachments2[0].Actions[0].Id, th.BasicUser.Id, "selected")
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ const (
|
||||
PROPS_ADD_CHANNEL_MEMBER = "add_channel_member"
|
||||
POST_PROPS_ADDED_USER_ID = "addedUserId"
|
||||
POST_PROPS_DELETE_BY = "deleteBy"
|
||||
POST_ACTION_TYPE_BUTTON = "button"
|
||||
POST_ACTION_TYPE_SELECT = "select"
|
||||
)
|
||||
|
||||
type Post struct {
|
||||
@@ -108,21 +110,35 @@ type PostForIndexing struct {
|
||||
ParentCreateAt *int64 `json:"parent_create_at"`
|
||||
}
|
||||
|
||||
type DoPostActionRequest struct {
|
||||
SelectedOption string `json:"selected_option"`
|
||||
}
|
||||
|
||||
type PostAction struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
DataSource string `json:"data_source"`
|
||||
Options []*PostActionOptions `json:"options"`
|
||||
Integration *PostActionIntegration `json:"integration,omitempty"`
|
||||
}
|
||||
|
||||
type PostActionOptions struct {
|
||||
Text string `json:"text"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type PostActionIntegration struct {
|
||||
URL string `json:"url,omitempty"`
|
||||
Context StringInterface `json:"context,omitempty"`
|
||||
}
|
||||
|
||||
type PostActionIntegrationRequest struct {
|
||||
UserId string `json:"user_id"`
|
||||
PostId string `json:"post_id"`
|
||||
Context StringInterface `json:"context,omitempty"`
|
||||
UserId string `json:"user_id"`
|
||||
PostId string `json:"post_id"`
|
||||
Type string `json:"type"`
|
||||
DataSource string `json:"data_source"`
|
||||
Context StringInterface `json:"context,omitempty"`
|
||||
}
|
||||
|
||||
type PostActionIntegrationResponse struct {
|
||||
@@ -455,6 +471,12 @@ func (o *PostEphemeral) ToUnsanitizedJson() string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func DoPostActionRequestFromJson(data io.Reader) *DoPostActionRequest {
|
||||
var o *DoPostActionRequest
|
||||
json.NewDecoder(data).Decode(&o)
|
||||
return o
|
||||
}
|
||||
|
||||
// RewriteImageURLs takes a message and returns a copy that has all of the image URLs replaced
|
||||
// according to the function f. For each image URL, f will be invoked, and the resulting markdown
|
||||
// will contain the URL returned by that invocation instead.
|
||||
|
||||
Ссылка в новой задаче
Block a user