PLT-6403: Interactive messages (#7274)
* wip * finish first pass * requested changes * add DoPostAction to Client4
Этот коммит содержится в:
@@ -53,7 +53,7 @@ func CreateCommandPost(post *model.Post, teamId string, response *model.CommandR
|
||||
}
|
||||
|
||||
post.ParentId = ""
|
||||
SendEphemeralPost(teamId, post.UserId, post)
|
||||
SendEphemeralPost(post.UserId, post)
|
||||
}
|
||||
|
||||
return post, nil
|
||||
|
||||
@@ -182,7 +182,6 @@ func SendNotifications(post *model.Post, team *model.Team, channel *model.Channe
|
||||
if hereNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
|
||||
hereNotification = false
|
||||
SendEphemeralPost(
|
||||
team.Id,
|
||||
post.UserId,
|
||||
&model.Post{
|
||||
ChannelId: post.ChannelId,
|
||||
@@ -195,7 +194,6 @@ func SendNotifications(post *model.Post, team *model.Team, channel *model.Channe
|
||||
// If the channel has more than 1K users then @channel is disabled
|
||||
if channelNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
|
||||
SendEphemeralPost(
|
||||
team.Id,
|
||||
post.UserId,
|
||||
&model.Post{
|
||||
ChannelId: post.ChannelId,
|
||||
@@ -208,7 +206,6 @@ func SendNotifications(post *model.Post, team *model.Team, channel *model.Channe
|
||||
// If the channel has more than 1K users then @all is disabled
|
||||
if allNotification && int64(len(profileMap)) > *utils.Cfg.TeamSettings.MaxNotificationsPerChannel {
|
||||
SendEphemeralPost(
|
||||
team.Id,
|
||||
post.UserId,
|
||||
&model.Post{
|
||||
ChannelId: post.ChannelId,
|
||||
@@ -734,7 +731,6 @@ func sendOutOfChannelMentions(sender *model.User, post *model.Post, teamId strin
|
||||
}
|
||||
|
||||
SendEphemeralPost(
|
||||
teamId,
|
||||
post.UserId,
|
||||
&model.Post{
|
||||
ChannelId: post.ChannelId,
|
||||
|
||||
67
app/post.go
67
app/post.go
@@ -4,8 +4,11 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/dyatlov/go-opengraph/opengraph"
|
||||
@@ -210,7 +213,7 @@ func parseSlackLinksToMarkdown(text string) string {
|
||||
return linkWithTextRegex.ReplaceAllString(text, "[${2}](${1})")
|
||||
}
|
||||
|
||||
func SendEphemeralPost(teamId, userId string, post *model.Post) *model.Post {
|
||||
func SendEphemeralPost(userId string, post *model.Post) *model.Post {
|
||||
post.Type = model.POST_EPHEMERAL
|
||||
|
||||
// fill in fields which haven't been specified which have sensible defaults
|
||||
@@ -638,3 +641,65 @@ func GetOpenGraphMetadata(url string) *opengraph.OpenGraph {
|
||||
|
||||
return og
|
||||
}
|
||||
|
||||
func DoPostAction(postId string, actionId string, userId string) *model.AppError {
|
||||
pchan := Srv.Store.Post().GetSingle(postId)
|
||||
|
||||
var post *model.Post
|
||||
if result := <-pchan; result.Err != nil {
|
||||
return result.Err
|
||||
} else {
|
||||
post = result.Data.(*model.Post)
|
||||
}
|
||||
|
||||
action := post.GetAction(actionId)
|
||||
if action == nil || action.Integration == nil {
|
||||
return model.NewAppError("DoPostAction", "api.post.do_action.action_id.app_error", nil, fmt.Sprintf("action=%v", action), http.StatusNotFound)
|
||||
}
|
||||
|
||||
request := &model.PostActionIntegrationRequest{
|
||||
UserId: userId,
|
||||
Context: action.Integration.Context,
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("POST", action.Integration.URL, strings.NewReader(request.ToJson()))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
resp, err := utils.HttpClient(false).Do(req)
|
||||
if err != nil {
|
||||
return model.NewAppError("DoPostAction", "api.post.do_action.action_integration.app_error", nil, "err="+err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return model.NewAppError("DoPostAction", "api.post.do_action.action_integration.app_error", nil, fmt.Sprintf("status=%v", resp.StatusCode), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
var response model.PostActionIntegrationResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
||||
return model.NewAppError("DoPostAction", "api.post.do_action.action_integration.app_error", nil, "err="+err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if response.Update != nil {
|
||||
response.Update.Id = postId
|
||||
response.Update.AddProp("from_webhook", "true")
|
||||
if _, err := UpdatePost(response.Update, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if response.EphemeralText != "" {
|
||||
ephemeralPost := &model.Post{}
|
||||
ephemeralPost.Message = parseSlackLinksToMarkdown(response.EphemeralText)
|
||||
ephemeralPost.ChannelId = post.ChannelId
|
||||
ephemeralPost.RootId = post.RootId
|
||||
if ephemeralPost.RootId == "" {
|
||||
ephemeralPost.RootId = post.Id
|
||||
}
|
||||
ephemeralPost.UserId = userId
|
||||
ephemeralPost.AddProp("from_webhook", "true")
|
||||
SendEphemeralPost(userId, ephemeralPost)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,11 +4,18 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
)
|
||||
|
||||
func TestUpdatePostEditAt(t *testing.T) {
|
||||
@@ -68,3 +75,66 @@ func TestPostReplyToPostWhereRootPosterLeftChannel(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostAction(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
|
||||
allowedInternalConnections := *utils.Cfg.ServiceSettings.AllowedUntrustedInternalConnections
|
||||
defer func() {
|
||||
utils.Cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
|
||||
}()
|
||||
*utils.Cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var request model.PostActionIntegrationRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&request)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, request.UserId, th.BasicUser.Id)
|
||||
assert.Equal(t, "foo", request.Context["s"])
|
||||
assert.EqualValues(t, 3, request.Context["n"])
|
||||
fmt.Fprintf(w, `{"update": {"message": "updated"}, "ephemeral_text": "foo"}`)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
interactivePost := 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{
|
||||
&model.SlackAttachment{
|
||||
Text: "hello",
|
||||
Actions: []*model.PostAction{
|
||||
&model.PostAction{
|
||||
Integration: &model.PostActionIntegration{
|
||||
Context: model.StringInterface{
|
||||
"s": "foo",
|
||||
"n": 3,
|
||||
},
|
||||
URL: ts.URL,
|
||||
},
|
||||
Name: "action",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
post, err := CreatePostAsUser(&interactivePost)
|
||||
require.Nil(t, err)
|
||||
|
||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
||||
require.True(t, ok)
|
||||
|
||||
require.NotEmpty(t, attachments[0].Actions)
|
||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||
|
||||
err = DoPostAction(post.Id, "notavalidid", th.BasicUser.Id)
|
||||
require.NotNil(t, err)
|
||||
assert.Equal(t, http.StatusNotFound, err.StatusCode)
|
||||
|
||||
err = DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user